Bug 1269971 - Part 2. From ClipBackgroundByText to GenerateAndPushTextMask; r=jfkthame,mtseng
MozReview-Commit-ID: 1PK2Huytq3i
This commit is contained in:
@@ -493,30 +493,59 @@ AddAnimationsForProperty(nsIFrame* aFrame, nsCSSProperty aProperty,
|
||||
}
|
||||
|
||||
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!
|
||||
// 1. Generate a mask by all descendant text frames
|
||||
// 2. Push the generated mask into aContext.
|
||||
|
||||
gfxContext* ctx = aContext->ThebesContext();
|
||||
gfxContextMatrixAutoSaveRestore save(ctx);
|
||||
gfxRect bounds = nsLayoutUtils::RectToGfxRect(aFillRect, aFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
ctx->SetMatrix(ctx->CurrentMatrix().Translate(bounds.TopLeft()));
|
||||
ctx->NewPath();
|
||||
gfxContext* sourceCtx = aContext->ThebesContext();
|
||||
gfxRect bounds =
|
||||
nsLayoutUtils::RectToGfxRect(aFillRect,
|
||||
aFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
|
||||
nsLayoutUtils::PaintFrame(aContext, aFrame,
|
||||
// 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
|
||||
@@ -2912,8 +2941,7 @@ nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
|
||||
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 =
|
||||
@@ -2924,7 +2952,7 @@ nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
|
||||
CompositionOp::OP_OVER);
|
||||
|
||||
if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
|
||||
ctx->Restore();
|
||||
ctx->PopGroupAndBlend();
|
||||
}
|
||||
|
||||
nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
|
||||
@@ -3344,10 +3372,10 @@ nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -4798,10 +4798,7 @@ nsDisplayText::Paint(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
params.dirtyRect = extraVisible;
|
||||
nsTextFrame::DrawPathCallbacks callbacks;
|
||||
if (aBuilder->IsForGenerateGlyphMask()) {
|
||||
params.callbacks = &callbacks;
|
||||
}
|
||||
|
||||
params.generateTextMask = aBuilder->IsForGenerateGlyphMask();
|
||||
f->PaintText(params, *this, mOpacity);
|
||||
}
|
||||
|
||||
@@ -6595,7 +6592,9 @@ nsTextFrame::PaintText(const PaintTextParams& aParams,
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -392,6 +392,7 @@ public:
|
||||
LayoutDeviceRect dirtyRect;
|
||||
gfxTextContextPaint* contextPaint = nullptr;
|
||||
DrawPathCallbacks* callbacks = nullptr;
|
||||
bool generateTextMask = false;
|
||||
explicit PaintTextParams(gfxContext* aContext) : context(aContext) {}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user