Bug 507817: BorderImage should not call ExtractCurrentFrame each time it draws [r=dbaron r=joedrew]

This commit is contained in:
Mark Finkle 2009-11-13 23:23:00 -05:00
Родитель d305b5ffae
Коммит 013b393bf3
3 изменённых файлов: 67 добавлений и 26 удалений

Просмотреть файл

@ -364,7 +364,7 @@ static void DrawBorderImage(nsPresContext* aPresContext,
nsIRenderingContext& aRenderingContext, nsIRenderingContext& aRenderingContext,
nsIFrame* aForFrame, nsIFrame* aForFrame,
const nsRect& aBorderArea, const nsRect& aBorderArea,
const nsStyleBorder& aBorderStyle, const nsStyleBorder& aStyleBorder,
const nsRect& aDirtyRect); const nsRect& aDirtyRect);
static void DrawBorderImageComponent(nsIRenderingContext& aRenderingContext, static void DrawBorderImageComponent(nsIRenderingContext& aRenderingContext,
@ -375,7 +375,9 @@ static void DrawBorderImageComponent(nsIRenderingContext& aRenderingContext,
const nsIntRect& aSrc, const nsIntRect& aSrc,
PRUint8 aHFill, PRUint8 aHFill,
PRUint8 aVFill, PRUint8 aVFill,
const nsSize& aUnitSize); const nsSize& aUnitSize,
const nsStyleBorder& aStyleBorder,
PRUint8 aIndex);
static nscolor MakeBevelColor(PRIntn whichSide, PRUint8 style, static nscolor MakeBevelColor(PRIntn whichSide, PRUint8 style,
nscolor aBackgroundColor, nscolor aBackgroundColor,
@ -544,7 +546,7 @@ nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
nsIFrame* aForFrame, nsIFrame* aForFrame,
const nsRect& aDirtyRect, const nsRect& aDirtyRect,
const nsRect& aBorderArea, const nsRect& aBorderArea,
const nsStyleBorder& aBorderStyle, const nsStyleBorder& aStyleBorder,
nsStyleContext* aStyleContext, nsStyleContext* aStyleContext,
PRIntn aSkipSides) PRIntn aSkipSides)
{ {
@ -564,9 +566,9 @@ nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
return; // Let the theme handle it. return; // Let the theme handle it.
} }
if (aBorderStyle.IsBorderImageLoaded()) { if (aStyleBorder.IsBorderImageLoaded()) {
DrawBorderImage(aPresContext, aRenderingContext, aForFrame, DrawBorderImage(aPresContext, aRenderingContext, aForFrame,
aBorderArea, aBorderStyle, aDirtyRect); aBorderArea, aStyleBorder, aDirtyRect);
return; return;
} }
@ -579,14 +581,14 @@ nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
(aStyleContext, compatMode == eCompatibility_NavQuirks ? PR_TRUE : PR_FALSE); (aStyleContext, compatMode == eCompatibility_NavQuirks ? PR_TRUE : PR_FALSE);
const nsStyleBackground* bgColor = bgContext->GetStyleBackground(); const nsStyleBackground* bgColor = bgContext->GetStyleBackground();
border = aBorderStyle.GetComputedBorder(); border = aStyleBorder.GetComputedBorder();
if ((0 == border.left) && (0 == border.right) && if ((0 == border.left) && (0 == border.right) &&
(0 == border.top) && (0 == border.bottom)) { (0 == border.top) && (0 == border.bottom)) {
// Empty border area // Empty border area
return; return;
} }
GetBorderRadiusTwips(aBorderStyle.mBorderRadius, aForFrame->GetSize().width, GetBorderRadiusTwips(aStyleBorder.mBorderRadius, aForFrame->GetSize().width,
twipsRadii); twipsRadii);
// Turn off rendering for all of the zero sized sides // Turn off rendering for all of the zero sized sides
@ -626,9 +628,9 @@ nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
// pull out styles, colors, composite colors // pull out styles, colors, composite colors
NS_FOR_CSS_SIDES (i) { NS_FOR_CSS_SIDES (i) {
PRBool foreground; PRBool foreground;
borderStyles[i] = aBorderStyle.GetBorderStyle(i); borderStyles[i] = aStyleBorder.GetBorderStyle(i);
aBorderStyle.GetBorderColor(i, borderColors[i], foreground); aStyleBorder.GetBorderColor(i, borderColors[i], foreground);
aBorderStyle.GetCompositeColors(i, &compositeColors[i]); aStyleBorder.GetCompositeColors(i, &compositeColors[i]);
if (foreground) if (foreground)
borderColors[i] = ourColor->mColor; borderColors[i] = ourColor->mColor;
@ -685,7 +687,7 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
nsIFrame* aForFrame, nsIFrame* aForFrame,
const nsRect& aDirtyRect, const nsRect& aDirtyRect,
const nsRect& aBorderArea, const nsRect& aBorderArea,
const nsStyleBorder& aBorderStyle, const nsStyleBorder& aStyleBorder,
const nsStyleOutline& aOutlineStyle, const nsStyleOutline& aOutlineStyle,
nsStyleContext* aStyleContext) nsStyleContext* aStyleContext)
{ {
@ -2484,7 +2486,7 @@ DrawBorderImage(nsPresContext* aPresContext,
nsIRenderingContext& aRenderingContext, nsIRenderingContext& aRenderingContext,
nsIFrame* aForFrame, nsIFrame* aForFrame,
const nsRect& aBorderArea, const nsRect& aBorderArea,
const nsStyleBorder& aBorderStyle, const nsStyleBorder& aStyleBorder,
const nsRect& aDirtyRect) const nsRect& aDirtyRect)
{ {
if (aDirtyRect.IsEmpty()) if (aDirtyRect.IsEmpty())
@ -2496,9 +2498,9 @@ DrawBorderImage(nsPresContext* aPresContext,
// XXX We shouldn't really... since if anybody is passing in a // XXX We shouldn't really... since if anybody is passing in a
// different style, they'll potentially have the wrong size for the // different style, they'll potentially have the wrong size for the
// border too. // border too.
aPresContext->SetupBorderImageLoaders(aForFrame, &aBorderStyle); aPresContext->SetupBorderImageLoaders(aForFrame, &aStyleBorder);
imgIRequest *req = aBorderStyle.GetBorderImage(); imgIRequest *req = aStyleBorder.GetBorderImage();
#ifdef DEBUG #ifdef DEBUG
{ {
@ -2525,7 +2527,7 @@ DrawBorderImage(nsPresContext* aPresContext,
// Convert percentages and clamp values to the image size. // Convert percentages and clamp values to the image size.
nsIntMargin split; nsIntMargin split;
NS_FOR_CSS_SIDES(s) { NS_FOR_CSS_SIDES(s) {
nsStyleCoord coord = aBorderStyle.mBorderImageSplit.Get(s); nsStyleCoord coord = aStyleBorder.mBorderImageSplit.Get(s);
PRInt32 imgDimension = ((s == NS_SIDE_TOP || s == NS_SIDE_BOTTOM) PRInt32 imgDimension = ((s == NS_SIDE_TOP || s == NS_SIDE_BOTTOM)
? imageSize.height ? imageSize.height
: imageSize.width); : imageSize.width);
@ -2550,7 +2552,7 @@ DrawBorderImage(nsPresContext* aPresContext,
split.side(s) = NS_lround(value); split.side(s) = NS_lround(value);
} }
nsMargin border(aBorderStyle.GetActualBorder()); nsMargin border(aStyleBorder.GetActualBorder());
// These helper tables recharacterize the 'split' and 'border' margins // These helper tables recharacterize the 'split' and 'border' margins
// in a more convenient form: they are the x/y/width/height coords // in a more convenient form: they are the x/y/width/height coords
@ -2642,8 +2644,8 @@ DrawBorderImage(nsPresContext* aPresContext,
unitSize.width = splitWidth[i]*hFactor; unitSize.width = splitWidth[i]*hFactor;
unitSize.height = splitHeight[j]*vFactor; unitSize.height = splitHeight[j]*vFactor;
fillStyleH = aBorderStyle.mBorderImageHFill; fillStyleH = aStyleBorder.mBorderImageHFill;
fillStyleV = aBorderStyle.mBorderImageVFill; fillStyleV = aStyleBorder.mBorderImageVFill;
} else if (i == MIDDLE) { // top, bottom } else if (i == MIDDLE) { // top, bottom
// Sides are always stretched to the thickness of their border, // Sides are always stretched to the thickness of their border,
@ -2656,7 +2658,7 @@ DrawBorderImage(nsPresContext* aPresContext,
unitSize.width = splitWidth[i]*factor; unitSize.width = splitWidth[i]*factor;
unitSize.height = borderHeight[j]; unitSize.height = borderHeight[j];
fillStyleH = aBorderStyle.mBorderImageHFill; fillStyleH = aStyleBorder.mBorderImageHFill;
fillStyleV = NS_STYLE_BORDER_IMAGE_STRETCH; fillStyleV = NS_STYLE_BORDER_IMAGE_STRETCH;
} else if (j == MIDDLE) { // left, right } else if (j == MIDDLE) { // left, right
@ -2669,7 +2671,7 @@ DrawBorderImage(nsPresContext* aPresContext,
unitSize.width = borderWidth[i]; unitSize.width = borderWidth[i];
unitSize.height = splitHeight[j]*factor; unitSize.height = splitHeight[j]*factor;
fillStyleH = NS_STYLE_BORDER_IMAGE_STRETCH; fillStyleH = NS_STYLE_BORDER_IMAGE_STRETCH;
fillStyleV = aBorderStyle.mBorderImageVFill; fillStyleV = aStyleBorder.mBorderImageVFill;
} else { } else {
// Corners are always stretched to fit the corner. // Corners are always stretched to fit the corner.
@ -2682,7 +2684,8 @@ DrawBorderImage(nsPresContext* aPresContext,
DrawBorderImageComponent(aRenderingContext, aForFrame, DrawBorderImageComponent(aRenderingContext, aForFrame,
imgContainer, aDirtyRect, imgContainer, aDirtyRect,
destArea, subArea, destArea, subArea,
fillStyleH, fillStyleV, unitSize); fillStyleH, fillStyleV,
unitSize, aStyleBorder, i * (RIGHT + 1) + j);
} }
} }
} }
@ -2696,16 +2699,28 @@ DrawBorderImageComponent(nsIRenderingContext& aRenderingContext,
const nsIntRect& aSrc, const nsIntRect& aSrc,
PRUint8 aHFill, PRUint8 aHFill,
PRUint8 aVFill, PRUint8 aVFill,
const nsSize& aUnitSize) const nsSize& aUnitSize,
const nsStyleBorder& aStyleBorder,
PRUint8 aIndex)
{ {
if (aFill.IsEmpty() || aSrc.IsEmpty()) if (aFill.IsEmpty() || aSrc.IsEmpty())
return; return;
// Don't bother trying to cache sub images if the border image is animated
// We can only sucessfully call GetAnimated() if we are fully decoded, so default to PR_TRUE
PRBool animated = PR_TRUE;
aImage->GetAnimated(&animated);
nsCOMPtr<imgIContainer> subImage; nsCOMPtr<imgIContainer> subImage;
if (NS_FAILED(aImage->ExtractFrame(imgIContainer::FRAME_CURRENT, aSrc, if (animated || (subImage = aStyleBorder.GetSubImage(aIndex)) == 0) {
imgIContainer::FLAG_SYNC_DECODE, if (NS_FAILED(aImage->ExtractFrame(imgIContainer::FRAME_CURRENT, aSrc,
getter_AddRefs(subImage)))) imgIContainer::FLAG_SYNC_DECODE,
return; getter_AddRefs(subImage))))
return;
if (!animated)
aStyleBorder.SetSubImage(aIndex, subImage);
}
gfxPattern::GraphicsFilter graphicsFilter = gfxPattern::GraphicsFilter graphicsFilter =
nsLayoutUtils::GetGraphicsFilterForFrame(aForFrame); nsLayoutUtils::GetGraphicsFilterForFrame(aForFrame);

Просмотреть файл

@ -69,6 +69,7 @@
class nsIFrame; class nsIFrame;
class imgIRequest; class imgIRequest;
class imgIContainer;
// Includes nsStyleStructID. // Includes nsStyleStructID.
#include "nsStyleStructFwd.h" #include "nsStyleStructFwd.h"
@ -838,6 +839,11 @@ struct nsStyleBorder {
inline void SetBorderImage(imgIRequest* aImage); inline void SetBorderImage(imgIRequest* aImage);
inline imgIRequest* GetBorderImage() const; inline imgIRequest* GetBorderImage() const;
// These methods are used for the caller to caches the sub images created during
// a border-image paint operation
inline void SetSubImage(PRUint8 aIndex, imgIContainer* aSubImage) const;
inline imgIContainer* GetSubImage(PRUint8 aIndex) const;
void GetCompositeColors(PRInt32 aIndex, nsBorderColors** aColors) const void GetCompositeColors(PRInt32 aIndex, nsBorderColors** aColors) const
{ {
if (!mBorderColors) if (!mBorderColors)
@ -897,6 +903,9 @@ protected:
nsCOMPtr<imgIRequest> mBorderImage; // [reset] nsCOMPtr<imgIRequest> mBorderImage; // [reset]
// Cache used by callers for border-image painting
nsCOMArray<imgIContainer> mSubImages;
nscoord mTwipsPerPixel; nscoord mTwipsPerPixel;
}; };

Просмотреть файл

@ -46,11 +46,13 @@
#include "nsStyleStruct.h" #include "nsStyleStruct.h"
#include "imgIRequest.h" #include "imgIRequest.h"
#include "imgIContainer.h"
inline void inline void
nsStyleBorder::SetBorderImage(imgIRequest* aImage) nsStyleBorder::SetBorderImage(imgIRequest* aImage)
{ {
mBorderImage = aImage; mBorderImage = aImage;
mSubImages.Clear();
/* /*
* Request a decode to jump start decoding, and lock it to make sure it * Request a decode to jump start decoding, and lock it to make sure it
@ -76,4 +78,19 @@ inline PRBool nsStyleBorder::IsBorderImageLoaded() const
(status & imgIRequest::STATUS_LOAD_COMPLETE); (status & imgIRequest::STATUS_LOAD_COMPLETE);
} }
inline void
nsStyleBorder::SetSubImage(PRUint8 aIndex, imgIContainer* aSubImage) const
{
const_cast<nsStyleBorder*>(this)->mSubImages.ReplaceObjectAt(aSubImage, aIndex);
}
inline imgIContainer*
nsStyleBorder::GetSubImage(PRUint8 aIndex) const
{
imgIContainer* subImage = 0;
if (0 <= aIndex && mSubImages.Count() > aIndex)
subImage = mSubImages[aIndex];
return subImage;
}
#endif /* !defined(nsStyleStructInlines_h_) */ #endif /* !defined(nsStyleStructInlines_h_) */