Bug 1209765 (Part 1) - Support sync decoding of border-image in nsCSSRendering. r=tn

This commit is contained in:
Seth Fowler 2015-10-22 19:54:48 -07:00
Родитель b2aa4e334a
Коммит 6a4f2f8dde
2 изменённых файлов: 116 добавлений и 78 удалений

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

@ -401,13 +401,14 @@ struct ColorStop {
};
/* Local functions */
static void DrawBorderImage(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aBorderArea,
const nsStyleBorder& aStyleBorder,
const nsRect& aDirtyRect,
Sides aSkipSides);
static DrawResult DrawBorderImage(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aBorderArea,
const nsStyleBorder& aStyleBorder,
const nsRect& aDirtyRect,
Sides aSkipSides,
PaintBorderFlags aFlags);
static nscolor MakeBevelColor(mozilla::css::Side whichSide, uint8_t style,
nscolor aBackgroundColor,
@ -616,13 +617,14 @@ nsCSSRendering::ComputePixelRadii(const nscoord *aAppUnitsRadii,
radii[NS_CORNER_BOTTOM_LEFT_Y]);
}
void
DrawResult
nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aDirtyRect,
const nsRect& aBorderArea,
nsStyleContext* aStyleContext,
PaintBorderFlags aFlags,
Sides aSkipSides)
{
PROFILER_LABEL("nsCSSRendering", "PaintBorder",
@ -633,10 +635,9 @@ nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
// Don't check RelevantLinkVisited here, since we want to take the
// same amount of time whether or not it's true.
if (!styleIfVisited) {
PaintBorderWithStyleBorder(aPresContext, aRenderingContext, aForFrame,
aDirtyRect, aBorderArea, *styleBorder,
aStyleContext, aSkipSides);
return;
return PaintBorderWithStyleBorder(aPresContext, aRenderingContext, aForFrame,
aDirtyRect, aBorderArea, *styleBorder,
aStyleContext, aFlags, aSkipSides);
}
nsStyleBorder newStyleBorder(*styleBorder);
@ -650,17 +651,20 @@ nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
aStyleContext->GetVisitedDependentColor(
nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color)[side]));
}
PaintBorderWithStyleBorder(aPresContext, aRenderingContext, aForFrame,
aDirtyRect, aBorderArea, newStyleBorder,
aStyleContext, aSkipSides);
DrawResult result =
PaintBorderWithStyleBorder(aPresContext, aRenderingContext, aForFrame,
aDirtyRect, aBorderArea, newStyleBorder,
aStyleContext, aFlags, aSkipSides);
// We could do something fancy to avoid the TrackImage/UntrackImage
// work, but it doesn't seem worth it. (We need to call UntrackImage
// since we're not going through nsStyleBorder::Destroy.)
newStyleBorder.UntrackImage(aPresContext);
return result;
}
void
DrawResult
nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
@ -668,6 +672,7 @@ nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
const nsRect& aBorderArea,
const nsStyleBorder& aStyleBorder,
nsStyleContext* aStyleContext,
PaintBorderFlags aFlags,
Sides aSkipSides)
{
DrawTarget& aDrawTarget = *aRenderingContext.GetDrawTarget();
@ -680,14 +685,26 @@ nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
const nsStyleDisplay* displayData = aStyleContext->StyleDisplay();
if (displayData->mAppearance) {
nsITheme *theme = aPresContext->GetTheme();
if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame, displayData->mAppearance))
return; // Let the theme handle it.
if (theme &&
theme->ThemeSupportsWidget(aPresContext, aForFrame,
displayData->mAppearance)) {
return DrawResult::SUCCESS; // Let the theme handle it.
}
}
if (aStyleBorder.IsBorderImageLoaded()) {
DrawBorderImage(aPresContext, aRenderingContext, aForFrame,
aBorderArea, aStyleBorder, aDirtyRect, aSkipSides);
return;
return DrawBorderImage(aPresContext, aRenderingContext, aForFrame,
aBorderArea, aStyleBorder, aDirtyRect,
aSkipSides, aFlags);
}
DrawResult result = DrawResult::SUCCESS;
// If we had a border-image, but it wasn't loaded, then we should return
// DrawResult::NOT_READY; we'll want to try again if we do a paint with sync
// decoding enabled.
if (aStyleBorder.mBorderImageSource.GetType() != eStyleImageType_Null) {
result = DrawResult::NOT_READY;
}
// Get our style context's color struct.
@ -705,7 +722,7 @@ nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
if (0 == border.left && 0 == border.right &&
0 == border.top && 0 == border.bottom) {
// Empty border area
return;
return result;
}
// Compute the outermost boundary of the area that might be painted.
@ -789,6 +806,8 @@ nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
ctx->Restore();
PrintAsStringNewline();
return result;
}
static nsRect
@ -3347,22 +3366,28 @@ nsCSSRendering::GetBackgroundLayerRect(nsPresContext* aPresContext,
return state.mFillArea;
}
static void
static DrawResult
DrawBorderImage(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aBorderArea,
const nsStyleBorder& aStyleBorder,
const nsRect& aDirtyRect,
Sides aSkipSides)
Sides aSkipSides,
PaintBorderFlags aFlags)
{
NS_PRECONDITION(aStyleBorder.IsBorderImageLoaded(),
"drawing border image that isn't successfully loaded");
if (aDirtyRect.IsEmpty())
return;
if (aDirtyRect.IsEmpty()) {
return DrawResult::SUCCESS;
}
nsImageRenderer renderer(aForFrame, &aStyleBorder.mBorderImageSource, 0);
uint32_t irFlags = 0;
if (aFlags & PaintBorderFlags::SYNC_DECODE_IMAGES) {
irFlags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
}
nsImageRenderer renderer(aForFrame, &aStyleBorder.mBorderImageSource, irFlags);
// Ensure we get invalidated for loads and animations of the image.
// We need to do this here because this might be the only code that
@ -3373,7 +3398,7 @@ DrawBorderImage(nsPresContext* aPresContext,
aForFrame->AssociateImage(aStyleBorder.mBorderImageSource, aPresContext);
if (!renderer.PrepareImage()) {
return;
return renderer.PrepareResult();
}
// NOTE: no Save() yet, we do that later by calling autoSR.EnsureSaved()
@ -3549,6 +3574,8 @@ DrawBorderImage(nsPresContext* aPresContext,
slice.bottom,
};
DrawResult result = DrawResult::SUCCESS;
for (int i = LEFT; i <= RIGHT; i++) {
for (int j = TOP; j <= BOTTOM; j++) {
uint8_t fillStyleH, fillStyleV;
@ -3633,16 +3660,19 @@ DrawBorderImage(nsPresContext* aPresContext,
nsRect subArea(sliceX[i], sliceY[j], sliceWidth[i], sliceHeight[j]);
nsIntRect intSubArea = subArea.ToOutsidePixels(nsPresContext::AppUnitsPerCSSPixel());
renderer.DrawBorderImageComponent(aPresContext,
aRenderingContext, aDirtyRect,
destArea, CSSIntRect(intSubArea.x,
intSubArea.y,
intSubArea.width,
intSubArea.height),
fillStyleH, fillStyleV,
unitSize, j * (RIGHT + 1) + i);
result &=
renderer.DrawBorderImageComponent(aPresContext,
aRenderingContext, aDirtyRect,
destArea, CSSIntRect(intSubArea.x,
intSubArea.y,
intSubArea.width,
intSubArea.height),
fillStyleH, fillStyleV,
unitSize, j * (RIGHT + 1) + i);
}
}
return result;
}
// Begin table border-collapsing section
@ -5031,17 +5061,18 @@ nsImageRenderer::Draw(nsPresContext* aPresContext,
}
nsCOMPtr<imgIContainer> image(ImageOps::CreateFromDrawable(drawable));
nsLayoutUtils::DrawImage(*aRenderingContext.ThebesContext(),
aPresContext, image,
filter, aDest, aFill, aAnchor, aDirtyRect,
ConvertImageRendererToDrawFlags(mFlags));
DrawResult result =
nsLayoutUtils::DrawImage(*aRenderingContext.ThebesContext(),
aPresContext, image,
filter, aDest, aFill, aAnchor, aDirtyRect,
ConvertImageRendererToDrawFlags(mFlags));
if (op != CompositionOp::OP_OVER) {
ctx->PopGroupToSource();
ctx->Paint();
}
return DrawResult::SUCCESS;
return result;
}
case eStyleImageType_Null:
default:
@ -5177,7 +5208,7 @@ RequiresScaling(const nsRect& aFill,
aUnitSize.height != aFill.height);
}
void
DrawResult
nsImageRenderer::DrawBorderImageComponent(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
@ -5190,10 +5221,10 @@ nsImageRenderer::DrawBorderImageComponent(nsPresContext* aPresContext,
{
if (!IsReady()) {
NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
return;
return DrawResult::BAD_ARGS;
}
if (aFill.IsEmpty() || aSrc.IsEmpty()) {
return;
return DrawResult::SUCCESS;
}
if (mType == eStyleImageType_Image || mType == eStyleImageType_Element) {
@ -5219,7 +5250,7 @@ nsImageRenderer::DrawBorderImageComponent(nsPresContext* aPresContext,
aRenderingContext);
if (!drawable) {
NS_WARNING("Could not create drawable for element");
return;
return DrawResult::TEMPORARY_ERROR;
}
nsCOMPtr<imgIContainer> image(ImageOps::CreateFromDrawable(drawable));
@ -5229,32 +5260,30 @@ nsImageRenderer::DrawBorderImageComponent(nsPresContext* aPresContext,
Filter filter = nsLayoutUtils::GetGraphicsFilterForFrame(mForFrame);
if (!RequiresScaling(aFill, aHFill, aVFill, aUnitSize)) {
nsLayoutUtils::DrawSingleImage(*aRenderingContext.ThebesContext(),
aPresContext,
subImage,
filter,
aFill, aDirtyRect,
nullptr,
imgIContainer::FLAG_NONE);
return;
return nsLayoutUtils::DrawSingleImage(*aRenderingContext.ThebesContext(),
aPresContext,
subImage,
filter,
aFill, aDirtyRect,
nullptr,
ConvertImageRendererToDrawFlags(mFlags));
}
nsRect tile = ComputeTile(aFill, aHFill, aVFill, aUnitSize);
nsLayoutUtils::DrawImage(*aRenderingContext.ThebesContext(),
aPresContext,
subImage,
filter,
tile, aFill, tile.TopLeft(), aDirtyRect,
imgIContainer::FLAG_NONE);
return;
return nsLayoutUtils::DrawImage(*aRenderingContext.ThebesContext(),
aPresContext,
subImage,
filter,
tile, aFill, tile.TopLeft(), aDirtyRect,
ConvertImageRendererToDrawFlags(mFlags));
}
nsRect destTile = RequiresScaling(aFill, aHFill, aVFill, aUnitSize)
? ComputeTile(aFill, aHFill, aVFill, aUnitSize)
: aFill;
Draw(aPresContext, aRenderingContext, aDirtyRect, destTile,
aFill, destTile.TopLeft(), aSrc);
return Draw(aPresContext, aRenderingContext, aDirtyRect, destTile,
aFill, destTile.TopLeft(), aSrc);
}
bool

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

@ -13,6 +13,7 @@
#include "imgIContainer.h"
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/TypedEnumBits.h"
#include "nsLayoutUtils.h"
#include "nsStyleStruct.h"
#include "nsIFrame.h"
@ -99,6 +100,12 @@ struct CSSSizeOrRatio
bool mHasHeight;
};
enum class PaintBorderFlags : uint8_t
{
SYNC_DECODE_IMAGES = 1 << 0
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(PaintBorderFlags)
} // namespace mozilla
/**
@ -225,7 +232,7 @@ public:
* 3 4 5
* 6 7 8
*/
void
DrawResult
DrawBorderImageComponent(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
@ -380,27 +387,29 @@ struct nsCSSRendering {
* for borders. aSkipSides says which sides to skip
* when rendering, the default is to skip none.
*/
static void PaintBorder(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aDirtyRect,
const nsRect& aBorderArea,
nsStyleContext* aStyleContext,
Sides aSkipSides = Sides());
static DrawResult PaintBorder(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aDirtyRect,
const nsRect& aBorderArea,
nsStyleContext* aStyleContext,
mozilla::PaintBorderFlags aFlags,
Sides aSkipSides = Sides());
/**
* Like PaintBorder, but taking an nsStyleBorder argument instead of
* getting it from aStyleContext. aSkipSides says which sides to skip
* when rendering, the default is to skip none.
*/
static void PaintBorderWithStyleBorder(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aDirtyRect,
const nsRect& aBorderArea,
const nsStyleBorder& aBorderStyle,
nsStyleContext* aStyleContext,
Sides aSkipSides = Sides());
static DrawResult PaintBorderWithStyleBorder(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aDirtyRect,
const nsRect& aBorderArea,
const nsStyleBorder& aBorderStyle,
nsStyleContext* aStyleContext,
mozilla::PaintBorderFlags aFlags,
Sides aSkipSides = Sides());
/**