Bug 1269971 - Part 2. From ClipBackgroundByText to GenerateAndPushTextMask;
MozReview-Commit-ID: 1PK2Huytq3i
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -488,40 +488,69 @@ AddAnimationsForProperty(nsIFrame* aFram
}
AddAnimationForProperty(aFrame, *property, anim, aLayer, aData, aPending);
effect->SetIsRunningOnCompositor(aProperty, true);
}
}
static void
-ClipBackgroundByText(nsIFrame* aFrame, nsRenderingContext* aContext,
- const nsRect& aFillRect)
+GenerateAndPushTextMask(nsIFrame* aFrame, nsRenderingContext* aContext,
+ const nsRect& aFillRect)
{
// The main function of enabling background-clip:text property value.
// When a nsDisplayBackgroundImage detects "text" bg-clip style, it will call
// this function to
- // 1. Ask every text frame objects in aFrame puts glyph paths into aContext.
- // 2. Clip aContext.
- //
- // Then, nsDisplayBackgroundImage paints bg-images into this clipped region,
- // so we get images embedded in text shape!
-
- gfxContext* ctx = aContext->ThebesContext();
- gfxContextMatrixAutoSaveRestore save(ctx);
- gfxRect bounds = nsLayoutUtils::RectToGfxRect(aFillRect, aFrame->PresContext()->AppUnitsPerDevPixel());
- ctx->SetMatrix(ctx->CurrentMatrix().Translate(bounds.TopLeft()));
- ctx->NewPath();
-
- nsLayoutUtils::PaintFrame(aContext, aFrame,
+ // 1. Generate a mask by all descendant text frames
+ // 2. Push the generated mask into aContext.
+
+ gfxContext* sourceCtx = aContext->ThebesContext();
+ gfxRect bounds =
+ nsLayoutUtils::RectToGfxRect(aFillRect,
+ aFrame->PresContext()->AppUnitsPerDevPixel());
+
+ // Evaluate required surface size.
+ IntRect drawRect;
+ {
+ gfxContextMatrixAutoSaveRestore matRestore(sourceCtx);
+
+ sourceCtx->SetMatrix(gfxMatrix());
+ gfxRect clipRect = sourceCtx->GetClipExtents();
+ drawRect = RoundedOut(ToRect(clipRect));
+ }
+
+ // Create a mask surface.
+ RefPtr<DrawTarget> sourceTarget = sourceCtx->GetDrawTarget();
+ RefPtr<DrawTarget> maskDT =
+ sourceTarget->CreateSimilarDrawTarget(drawRect.Size(),
+ SurfaceFormat::A8);
+ if (!maskDT) {
+ NS_ABORT_OOM(drawRect.width * drawRect.height);
+ }
+ RefPtr<gfxContext> maskCtx = gfxContext::ForDrawTargetWithTransform(maskDT);
+ gfxMatrix currentMatrix = sourceCtx->CurrentMatrix();
+ maskCtx->SetMatrix(gfxMatrix::Translation(bounds.TopLeft()) *
+ currentMatrix *
+ gfxMatrix::Translation(-drawRect.TopLeft()));
+
+ // Shade text shape into mask A8 surface.
+ nsRenderingContext rc(maskCtx);
+ nsLayoutUtils::PaintFrame(&rc, aFrame,
nsRect(nsPoint(0, 0), aFrame->GetSize()),
NS_RGB(255, 255, 255),
nsDisplayListBuilderMode::GENERATE_GLYPH);
- ctx->Clip();
+ // Push the generated mask into aContext, so that the caller can pop and
+ // blend with it.
+ Matrix maskTransform = ToMatrix(currentMatrix) *
+ Matrix::Translation(-drawRect.x, -drawRect.y);
+ maskTransform.Invert();
+
+ RefPtr<SourceSurface> maskSurface = maskDT->Snapshot();
+ sourceCtx->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, 1.0, maskSurface, maskTransform);
}
/* static */ void
nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem,
nsIFrame* aFrame,
nsCSSProperty aProperty)
@@ -2907,29 +2936,28 @@ nsDisplayBackgroundImage::PaintInternal(
nsRect* aClipRect) {
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
CheckForBorderItem(this, flags);
gfxContext* ctx = aCtx->ThebesContext();
uint8_t clip = mBackgroundStyle->mImage.mLayers[mLayer].mClip;
if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
- ctx->Save();
- ClipBackgroundByText(mFrame, aCtx, mBackgroundRect);
+ GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect);
}
image::DrawResult result =
nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
aBounds,
mBackgroundRect,
flags, aClipRect, mLayer,
CompositionOp::OP_OVER);
if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
- ctx->Restore();
+ ctx->PopGroupAndBlend();
}
nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
}
void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
@@ -3339,20 +3367,20 @@ nsDisplayBackgroundColor::Paint(nsDispla
aDrawTarget.FillRect(rect, color);
#else
gfxContext* ctx = aCtx->ThebesContext();
uint8_t clip = mBackgroundStyle->mImage.mLayers[0].mClip;
if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
gfxContextAutoSaveRestore save(ctx);
- ClipBackgroundByText(mFrame, aCtx, mBackgroundRect);
+ GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect);
ctx->SetColor(mColor);
ctx->Fill();
-
+ ctx->PopGroupAndBlend();
return;
}
gfxRect bounds =
nsLayoutUtils::RectToGfxRect(mBackgroundRect, mFrame->PresContext()->AppUnitsPerDevPixel());
ctx->SetColor(mColor);
ctx->NewPath();
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -4793,20 +4793,17 @@ nsDisplayText::Paint(nsDisplayListBuilde
ctx->SetMatrix(mat);
}
}
nsTextFrame::PaintTextParams params(aCtx->ThebesContext());
params.framePt = gfxPoint(framePt.x, framePt.y);
params.dirtyRect = extraVisible;
nsTextFrame::DrawPathCallbacks callbacks;
- if (aBuilder->IsForGenerateGlyphMask()) {
- params.callbacks = &callbacks;
- }
-
+ params.generateTextMask = aBuilder->IsForGenerateGlyphMask();
f->PaintText(params, *this, mOpacity);
}
void
nsTextFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
@@ -6590,17 +6587,19 @@ nsTextFrame::PaintText(const PaintTextPa
params.provider = &provider;
params.contentRange = contentRange;
params.textPaintStyle = &textPaintStyle;
if (PaintTextWithSelection(params, clipEdges)) {
return;
}
}
- nscolor foregroundColor = textPaintStyle.GetTextColor();
+ nscolor foregroundColor = aParams.generateTextMask
+ ? NS_RGBA(0, 0, 0, 255)
+ : textPaintStyle.GetTextColor();
if (aOpacity != 1.0f) {
gfx::Color gfxColor = gfx::Color::FromABGR(foregroundColor);
gfxColor.a *= aOpacity;
foregroundColor = gfxColor.ToABGR();
}
nscolor textStrokeColor = textPaintStyle.GetWebkitTextStrokeColor();
if (aOpacity != 1.0f) {
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -387,16 +387,17 @@ public:
struct PaintTextParams
{
gfxContext* context;
gfxPoint framePt;
LayoutDeviceRect dirtyRect;
gfxTextContextPaint* contextPaint = nullptr;
DrawPathCallbacks* callbacks = nullptr;
+ bool generateTextMask = false;
explicit PaintTextParams(gfxContext* aContext) : context(aContext) {}
};
struct PaintTextSelectionParams : PaintTextParams
{
gfxPoint textBaselinePt;
PropertyProvider* provider = nullptr;
Range contentRange;