Bug 1346265 - Part 1. Pass gfxContext to nsCSSRendering::PaintGradient.
If mask-mode is luminace, we will create a temporary context at [1]. It's
obvious we do not use this gfxContext at all in PaintGradient path. This patch is
trying to fix this problem by pass gfxContext, instead of RenderingContext,
directly to PaintGraident.
[1] https://hg.mozilla.org/mozilla-central/file/991f5724e58f/layout/painting/nsCSSRendering.cpp#l5811
MozReview-Commit-ID: LLmg4k6IEm3
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -2897,17 +2897,17 @@ ClampColorStops(nsTArray<ColorStop>& aSt
}
if (aStops.LastElement().mPosition < 1) {
aStops.AppendElement(ColorStop(1, false, aStops.LastElement().mColor));
}
}
void
nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
- nsRenderingContext& aRenderingContext,
+ gfxContext& aContext,
nsStyleGradient* aGradient,
const nsRect& aDirtyRect,
const nsRect& aDest,
const nsRect& aFillArea,
const nsSize& aRepeatSize,
const CSSIntRect& aSrc,
const nsSize& aIntrinsicSize,
float aOpacity)
@@ -2915,17 +2915,16 @@ nsCSSRendering::PaintGradient(nsPresCont
PROFILER_LABEL("nsCSSRendering", "PaintGradient",
js::ProfileEntry::Category::GRAPHICS);
Telemetry::AutoTimer<Telemetry::GRADIENT_DURATION, Telemetry::Microsecond> gradientTimer;
if (aDest.IsEmpty() || aFillArea.IsEmpty()) {
return;
}
- gfxContext *ctx = aRenderingContext.ThebesContext();
nscoord appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
gfxSize srcSize = gfxSize(gfxFloat(aIntrinsicSize.width)/appUnitsPerDevPixel,
gfxFloat(aIntrinsicSize.height)/appUnitsPerDevPixel);
bool cellContainsFill = aDest.Contains(aFillArea);
// Compute "gradient line" start and end relative to the intrinsic size of
// the gradient.
@@ -3258,17 +3257,17 @@ nsCSSRendering::PaintGradient(nsPresCont
nsTArray<gfx::GradientStop> rawStops(stops.Length());
rawStops.SetLength(stops.Length());
for(uint32_t i = 0; i < stops.Length(); i++) {
rawStops[i].color = stops[i].mColor;
rawStops[i].color.a *= aOpacity;
rawStops[i].offset = stopScale * (stops[i].mPosition - stopOrigin);
}
RefPtr<mozilla::gfx::GradientStops> gs =
- gfxGradientCache::GetOrCreateGradientStops(ctx->GetDrawTarget(),
+ gfxGradientCache::GetOrCreateGradientStops(aContext.GetDrawTarget(),
rawStops,
isRepeat ? gfx::ExtendMode::REPEAT : gfx::ExtendMode::CLAMP);
gradientPattern->SetColorStops(gs);
// Paint gradient tiles. This isn't terribly efficient, but doing it this
// way is simple and sure to get pixel-snapping right. We could speed things
// up by drawing tiles into temporary surfaces and copying those to the
// destination, but after pixel-snapping tiles may not all be the same size.
@@ -3276,17 +3275,17 @@ nsCSSRendering::PaintGradient(nsPresCont
if (!dirty.IntersectRect(aDirtyRect, aFillArea))
return;
gfxRect areaToFill =
nsLayoutUtils::RectToGfxRect(aFillArea, appUnitsPerDevPixel);
gfxRect dirtyAreaToFill = nsLayoutUtils::RectToGfxRect(dirty, appUnitsPerDevPixel);
dirtyAreaToFill.RoundOut();
- gfxMatrix ctm = ctx->CurrentMatrix();
+ gfxMatrix ctm = aContext.CurrentMatrix();
bool isCTMPreservingAxisAlignedRectangles = ctm.PreservesAxisAlignedRectangles();
// xStart/yStart are the top-left corner of the top-left tile.
nscoord xStart = FindTileStart(dirty.x, aDest.x, aRepeatSize.width);
nscoord yStart = FindTileStart(dirty.y, aDest.y, aRepeatSize.height);
nscoord xEnd = forceRepeatToCoverTiles ? xStart + aDest.width : dirty.XMost();
nscoord yEnd = forceRepeatToCoverTiles ? yStart + aDest.height : dirty.YMost();
@@ -3304,51 +3303,51 @@ nsCSSRendering::PaintGradient(nsPresCont
// Try snapping the fill rect. Snap its top-left and bottom-right
// independently to preserve the orientation.
gfxPoint snappedFillRectTopLeft = fillRect.TopLeft();
gfxPoint snappedFillRectTopRight = fillRect.TopRight();
gfxPoint snappedFillRectBottomRight = fillRect.BottomRight();
// Snap three points instead of just two to ensure we choose the
// correct orientation if there's a reflection.
if (isCTMPreservingAxisAlignedRectangles &&
- ctx->UserToDevicePixelSnapped(snappedFillRectTopLeft, true) &&
- ctx->UserToDevicePixelSnapped(snappedFillRectBottomRight, true) &&
- ctx->UserToDevicePixelSnapped(snappedFillRectTopRight, true)) {
+ aContext.UserToDevicePixelSnapped(snappedFillRectTopLeft, true) &&
+ aContext.UserToDevicePixelSnapped(snappedFillRectBottomRight, true) &&
+ aContext.UserToDevicePixelSnapped(snappedFillRectTopRight, true)) {
if (snappedFillRectTopLeft.x == snappedFillRectBottomRight.x ||
snappedFillRectTopLeft.y == snappedFillRectBottomRight.y) {
// Nothing to draw; avoid scaling by zero and other weirdness that
// could put the context in an error state.
continue;
}
// Set the context's transform to the transform that maps fillRect to
// snappedFillRect. The part of the gradient that was going to
// exactly fill fillRect will fill snappedFillRect instead.
gfxMatrix transform = gfxUtils::TransformRectToRect(fillRect,
snappedFillRectTopLeft, snappedFillRectTopRight,
snappedFillRectBottomRight);
- ctx->SetMatrix(transform);
+ aContext.SetMatrix(transform);
}
- ctx->NewPath();
- ctx->Rectangle(fillRect);
+ aContext.NewPath();
+ aContext.Rectangle(fillRect);
gfxRect dirtyFillRect = fillRect.Intersect(dirtyAreaToFill);
gfxRect fillRectRelativeToTile = dirtyFillRect - tileRect.TopLeft();
Color edgeColor;
if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR && !isRepeat &&
RectIsBeyondLinearGradientEdge(fillRectRelativeToTile, matrix, stops,
gradientStart, gradientEnd, &edgeColor)) {
edgeColor.a *= aOpacity;
- ctx->SetColor(edgeColor);
+ aContext.SetColor(edgeColor);
} else {
- ctx->SetMatrix(
- ctx->CurrentMatrix().Copy().Translate(tileRect.TopLeft()));
- ctx->SetPattern(gradientPattern);
+ aContext.SetMatrix(
+ aContext.CurrentMatrix().Copy().Translate(tileRect.TopLeft()));
+ aContext.SetPattern(gradientPattern);
}
- ctx->Fill();
- ctx->SetMatrix(ctm);
+ aContext.Fill();
+ aContext.SetMatrix(ctm);
}
}
}
static CompositionOp
DetermineCompositionOp(const nsCSSRendering::PaintBGParams& aParams,
const nsStyleImageLayers& aLayers,
uint32_t aLayerIndex)
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -232,17 +232,17 @@ struct nsCSSRendering {
* aFill is the rect on the destination to be covered by repeated tiling of
* the gradient.
* aSrc is the part of the gradient to be rendered into a tile (aDest), if
* aSrc and aDest are different sizes, the image will be scaled to map aSrc
* onto aDest.
* aIntrinsicSize is the size of the source gradient.
*/
static void PaintGradient(nsPresContext* aPresContext,
- nsRenderingContext& aRenderingContext,
+ gfxContext& aContext,
nsStyleGradient* aGradient,
const nsRect& aDirtyRect,
const nsRect& aDest,
const nsRect& aFill,
const nsSize& aRepeatSize,
const mozilla::CSSIntRect& aSrc,
const nsSize& aIntrinsiceSize,
float aOpacity = 1.0);
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -503,17 +503,17 @@ nsImageRenderer::Draw(nsPresContext*
aDest, aFill, aRepeatSize,
aAnchor, aDirtyRect,
ConvertImageRendererToDrawFlags(mFlags),
mExtendMode, aOpacity);
break;
}
case eStyleImageType_Gradient:
{
- nsCSSRendering::PaintGradient(aPresContext, aRenderingContext,
+ nsCSSRendering::PaintGradient(aPresContext, *ctx,
mGradientData, aDirtyRect,
aDest, aFill, aRepeatSize, aSrc, mSize,
aOpacity);
break;
}
case eStyleImageType_Element:
{
RefPtr<gfxDrawable> drawable = DrawableForElement(aDest,