Bug 1228280 - Part 2. Change the parameters of nsSVGIntegrationUtils::PaintFramesWithEffects;

MozReview-Commit-ID: CaOINlG7HD6
This commit is contained in:
CJKu 2016-05-19 15:43:32 +08:00
Родитель be0a6b927b
Коммит b4f5e64881
3 изменённых файлов: 97 добавлений и 84 удалений

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

@ -6615,10 +6615,12 @@ nsDisplaySVGEffects::PaintAsLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager) LayerManager* aManager)
{ {
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize()); nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
nsSVGIntegrationUtils::PaintFramesWithEffects(*aCtx->ThebesContext(), mFrame, nsSVGIntegrationUtils::PaintFramesParams params(*aCtx->ThebesContext(),
mVisibleRect, mFrame, mVisibleRect,
borderArea, borderArea, aBuilder,
aBuilder, aManager); aManager);
nsSVGIntegrationUtils::PaintFramesWithEffects(params);
} }
LayerState LayerState

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

@ -410,17 +410,12 @@ private:
}; };
void void
nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext, nsSVGIntegrationUtils::PaintFramesWithEffects(const PaintFramesParams& aParams)
nsIFrame* aFrame,
const nsRect& aDirtyRect,
const nsRect& aBorderArea,
nsDisplayListBuilder* aBuilder,
LayerManager *aLayerManager)
{ {
#ifdef DEBUG #ifdef DEBUG
NS_ASSERTION(!(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) || NS_ASSERTION(!(aParams.frame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
(NS_SVGDisplayListPaintingEnabled() && (NS_SVGDisplayListPaintingEnabled() &&
!(aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)), !(aParams.frame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)),
"Should not use nsSVGIntegrationUtils on this SVG frame"); "Should not use nsSVGIntegrationUtils on this SVG frame");
#endif #endif
@ -437,12 +432,12 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
* *
* + Merge opacity and masking if both used together. * + Merge opacity and masking if both used together.
*/ */
nsIFrame* frame = aParams.frame;
const nsIContent* content = aFrame->GetContent(); const nsIContent* content = frame->GetContent();
bool hasSVGLayout = (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT); bool hasSVGLayout = (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
if (hasSVGLayout) { if (hasSVGLayout) {
nsISVGChildFrame *svgChildFrame = do_QueryFrame(aFrame); nsISVGChildFrame *svgChildFrame = do_QueryFrame(frame);
if (!svgChildFrame || !aFrame->GetContent()->IsSVGElement()) { if (!svgChildFrame || !frame->GetContent()->IsSVGElement()) {
NS_ASSERTION(false, "why?"); NS_ASSERTION(false, "why?");
return; return;
} }
@ -451,19 +446,19 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
} }
} }
float opacity = aFrame->StyleEffects()->mOpacity; float opacity = frame->StyleEffects()->mOpacity;
if (opacity == 0.0f) { if (opacity == 0.0f) {
return; return;
} }
if (opacity != 1.0f && if (opacity != 1.0f &&
hasSVGLayout && nsSVGUtils::CanOptimizeOpacity(aFrame)) { hasSVGLayout && nsSVGUtils::CanOptimizeOpacity(frame)) {
opacity = 1.0f; opacity = 1.0f;
} }
/* Properties are added lazily and may have been removed by a restyle, /* Properties are added lazily and may have been removed by a restyle,
so make sure all applicable ones are set again. */ so make sure all applicable ones are set again. */
nsIFrame* firstFrame = nsIFrame* firstFrame =
nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame); nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
nsSVGEffects::EffectProperties effectProperties = nsSVGEffects::EffectProperties effectProperties =
nsSVGEffects::GetEffectProperties(firstFrame); nsSVGEffects::GetEffectProperties(firstFrame);
@ -471,22 +466,22 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK); nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
bool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : true; bool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : true;
gfxContext& context = aParams.ctx;
DrawTarget* drawTarget = aContext.GetDrawTarget(); DrawTarget* drawTarget = context.GetDrawTarget();
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&aContext); gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&context);
nsPoint firstFrameOffset = GetOffsetToBoundingBox(firstFrame); nsPoint firstFrameOffset = GetOffsetToBoundingBox(firstFrame);
nsPoint offsetToBoundingBox = aBuilder->ToReferenceFrame(firstFrame) - firstFrameOffset; nsPoint offsetToBoundingBox = aParams.builder->ToReferenceFrame(firstFrame) - firstFrameOffset;
if (!firstFrame->IsFrameOfType(nsIFrame::eSVG)) { if (!firstFrame->IsFrameOfType(nsIFrame::eSVG)) {
/* Snap the offset if the reference frame is not a SVG frame, /* Snap the offset if the reference frame is not a SVG frame,
* since other frames will be snapped to pixel when rendering. */ * since other frames will be snapped to pixel when rendering. */
offsetToBoundingBox = nsPoint( offsetToBoundingBox = nsPoint(
aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.x), frame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.x),
aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.y)); frame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.y));
} }
// After applying only "offsetToBoundingBox", aCtx would have its origin at // After applying only "offsetToBoundingBox", aCtx would have its origin at
// the top left corner of aFrame's bounding box (over all continuations). // the top left corner of frame's bounding box (over all continuations).
// However, SVG painting needs the origin to be located at the origin of the // However, SVG painting needs the origin to be located at the origin of the
// SVG frame's "user space", i.e. the space in which, for example, the // SVG frame's "user space", i.e. the space in which, for example, the
// frame's BBox lives. // frame's BBox lives.
@ -496,7 +491,7 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
// frame's position so that SVG painting can later add it again and the // frame's position so that SVG painting can later add it again and the
// frame is painted in the right place. // frame is painted in the right place.
gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(aFrame); gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(frame);
nsPoint toUserSpace(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)), nsPoint toUserSpace(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)),
nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y))); nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y)));
nsPoint offsetToUserSpace = offsetToBoundingBox - toUserSpace; nsPoint offsetToUserSpace = offsetToBoundingBox - toUserSpace;
@ -506,10 +501,10 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
gfxPoint devPixelOffsetToUserSpace = gfxPoint devPixelOffsetToUserSpace =
nsLayoutUtils::PointToGfxPoint(offsetToUserSpace, nsLayoutUtils::PointToGfxPoint(offsetToUserSpace,
aFrame->PresContext()->AppUnitsPerDevPixel()); frame->PresContext()->AppUnitsPerDevPixel());
aContext.SetMatrix(aContext.CurrentMatrix().Translate(devPixelOffsetToUserSpace)); context.SetMatrix(context.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(aFrame); gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(frame);
const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset(); const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
// Keep moving forward even if svgMaskFrame is nullptr or isOK is false. // Keep moving forward even if svgMaskFrame is nullptr or isOK is false.
@ -517,7 +512,7 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
nsSVGMaskFrame *svgMaskFrame = effectProperties.GetMaskFrame(&isOK); nsSVGMaskFrame *svgMaskFrame = effectProperties.GetMaskFrame(&isOK);
// These are used if we require a temporary surface for a custom blend mode. // These are used if we require a temporary surface for a custom blend mode.
RefPtr<gfxContext> target = &aContext; RefPtr<gfxContext> target = &aParams.ctx;
IntPoint targetOffset; IntPoint targetOffset;
// hasMaskToDraw is true means we have at least one drawable mask resource. // hasMaskToDraw is true means we have at least one drawable mask resource.
@ -536,35 +531,34 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
/* Check if we need to do additional operations on this child's /* Check if we need to do additional operations on this child's
* rendering, which necessitates rendering into another surface. */ * rendering, which necessitates rendering into another surface. */
if (opacity != 1.0f || (clipPathFrame && !isTrivialClip) if (opacity != 1.0f || (clipPathFrame && !isTrivialClip)
|| aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL || frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL
|| hasMaskToDraw) { || hasMaskToDraw) {
complexEffects = true; complexEffects = true;
aContext.Save(); context.Save();
nsRect overflowClipRect = nsRect clipRect =
aFrame->GetVisualOverflowRectRelativeToSelf() + toUserSpace; frame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
aContext.Clip(NSRectToSnappedRect(overflowClipRect, context.Clip(NSRectToSnappedRect(clipRect,
aFrame->PresContext()->AppUnitsPerDevPixel(), frame->PresContext()->AppUnitsPerDevPixel(),
*drawTarget)); *drawTarget));
Matrix maskTransform; Matrix maskTransform;
RefPtr<SourceSurface> maskSurface; RefPtr<SourceSurface> maskSurface;
if (svgMaskFrame) { if (svgMaskFrame) {
// Generate maskSurface from a SVG mask. // Generate maskSurface from a SVG mask.
maskSurface = svgMaskFrame->GetMaskForMaskedFrame(&aContext, maskSurface = svgMaskFrame->GetMaskForMaskedFrame(&context,
aFrame, aParams.frame,
cssPxToDevPxMatrix, cssPxToDevPxMatrix,
opacity, opacity,
&maskTransform, &maskTransform,
svgReset->mMask.mLayers[0].mMaskMode); svgReset->mMask.mLayers[0].mMaskMode);
} else if (hasMaskToDraw) { } else if (hasMaskToDraw) {
// Create maskSuface. // Create maskSuface.
gfxRect clipRect = aContext.GetClipExtents(); gfxRect clipRect = context.GetClipExtents();
{ {
gfxContextMatrixAutoSaveRestore matRestore(&aContext); gfxContextMatrixAutoSaveRestore matRestore(&context);
aContext.SetMatrix(gfxMatrix()); context.SetMatrix(gfxMatrix());
clipRect = aContext.GetClipExtents(); clipRect = context.GetClipExtents();
} }
IntRect drawRect = RoundedOut(ToRect(clipRect)); IntRect drawRect = RoundedOut(ToRect(clipRect));
@ -572,14 +566,14 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
// when mask-mode is not add(source over). Switch to skia when CG backend // when mask-mode is not add(source over). Switch to skia when CG backend
// detected. // detected.
RefPtr<DrawTarget> maskTargetDT = RefPtr<DrawTarget> maskTargetDT =
(aContext.GetDrawTarget()->GetBackendType() == BackendType::COREGRAPHICS) ? (context.GetDrawTarget()->GetBackendType() == BackendType::COREGRAPHICS) ?
Factory::CreateDrawTarget(BackendType::SKIA, drawRect.Size(), Factory::CreateDrawTarget(BackendType::SKIA, drawRect.Size(),
SurfaceFormat::A8) : SurfaceFormat::A8) :
aContext.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(), context.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(),
SurfaceFormat::A8); SurfaceFormat::A8);
if (!maskTargetDT || !maskTargetDT->IsValid()) { if (!maskTargetDT || !maskTargetDT->IsValid()) {
aContext.Restore(); context.Restore();
return; return;
} }
@ -590,57 +584,59 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
// Compose all mask-images onto maskSurface. // Compose all mask-images onto maskSurface.
nsRenderingContext rc(target); nsRenderingContext rc(target);
nsCSSRendering::PaintBGParams params = nsCSSRendering::PaintBGParams params =
nsCSSRendering::PaintBGParams::ForAllLayers(*aFrame->PresContext(), rc, nsCSSRendering::PaintBGParams::ForAllLayers(*aParams.frame->PresContext(),
aDirtyRect, aBorderArea, rc,
aFrame, aParams.dirtyRect,
aBuilder->GetBackgroundPaintFlags() | aParams.borderArea,
aParams.frame,
aParams.builder->GetBackgroundPaintFlags() |
nsCSSRendering::PAINTBG_MASK_IMAGE); nsCSSRendering::PAINTBG_MASK_IMAGE);
// FIXME We should use the return value, see bug 1258510. // FIXME We should use the return value, see bug 1258510.
Unused << nsCSSRendering::PaintBackgroundWithSC(params, Unused << nsCSSRendering::PaintBackgroundWithSC(params,
firstFrame->StyleContext(), firstFrame->StyleContext(),
*aFrame->StyleBorder()); *frame->StyleBorder());
maskSurface = maskTargetDT->Snapshot(); maskSurface = maskTargetDT->Snapshot();
// Compute mask transform. // Compute mask transform.
Matrix mat = ToMatrix(aContext.CurrentMatrix()); Matrix mat = ToMatrix(context.CurrentMatrix());
mat.Invert(); mat.Invert();
maskTransform = Matrix::Translation(drawRect.x, drawRect.y) * mat; maskTransform = Matrix::Translation(drawRect.x, drawRect.y) * mat;
} }
if (hasMaskToDraw && !maskSurface) { if (hasMaskToDraw && !maskSurface) {
// Entire surface is clipped out. // Entire surface is clipped out.
aContext.Restore(); context.Restore();
return; return;
} }
if (aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) { if (frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
// Create a temporary context to draw to so we can blend it back with // Create a temporary context to draw to so we can blend it back with
// another operator. // another operator.
gfxRect clipRect; gfxRect clipRect;
{ {
gfxContextMatrixAutoSaveRestore matRestore(&aContext); gfxContextMatrixAutoSaveRestore matRestore(&context);
aContext.SetMatrix(gfxMatrix()); context.SetMatrix(gfxMatrix());
clipRect = aContext.GetClipExtents(); clipRect = context.GetClipExtents();
} }
IntRect drawRect = RoundedOut(ToRect(clipRect)); IntRect drawRect = RoundedOut(ToRect(clipRect));
RefPtr<DrawTarget> targetDT = aContext.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(), SurfaceFormat::B8G8R8A8); RefPtr<DrawTarget> targetDT = context.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(), SurfaceFormat::B8G8R8A8);
if (!targetDT || !targetDT->IsValid()) { if (!targetDT || !targetDT->IsValid()) {
aContext.Restore(); context.Restore();
return; return;
} }
target = gfxContext::ForDrawTarget(targetDT); target = gfxContext::ForDrawTarget(targetDT);
MOZ_ASSERT(target); // already checked the draw target above MOZ_ASSERT(target); // already checked the draw target above
target->SetMatrix(aContext.CurrentMatrix() * gfxMatrix::Translation(-drawRect.TopLeft())); target->SetMatrix(context.CurrentMatrix() * gfxMatrix::Translation(-drawRect.TopLeft()));
targetOffset = drawRect.TopLeft(); targetOffset = drawRect.TopLeft();
} }
if (clipPathFrame && !isTrivialClip) { if (clipPathFrame && !isTrivialClip) {
Matrix clippedMaskTransform; Matrix clippedMaskTransform;
RefPtr<SourceSurface> clipMaskSurface = clipPathFrame->GetClipMask(aContext, aFrame, cssPxToDevPxMatrix, RefPtr<SourceSurface> clipMaskSurface = clipPathFrame->GetClipMask(context, frame, cssPxToDevPxMatrix,
&clippedMaskTransform, maskSurface, maskTransform); &clippedMaskTransform, maskSurface, maskTransform);
if (clipMaskSurface) { if (clipMaskSurface) {
@ -658,34 +654,35 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
* we can just do normal painting and get it clipped appropriately. * we can just do normal painting and get it clipped appropriately.
*/ */
if (clipPathFrame && isTrivialClip) { if (clipPathFrame && isTrivialClip) {
aContext.Save(); context.Save();
clipPathFrame->ApplyClipPath(aContext, aFrame, cssPxToDevPxMatrix); clipPathFrame->ApplyClipPath(context, frame, cssPxToDevPxMatrix);
} else if (!clipPathFrame && svgReset->HasClipPath()) { } else if (!clipPathFrame && svgReset->HasClipPath()) {
aContext.Save(); context.Save();
nsCSSClipPathInstance::ApplyBasicShapeClip(aContext, aFrame); nsCSSClipPathInstance::ApplyBasicShapeClip(context, frame);
} }
/* Paint the child */ /* Paint the child */
if (effectProperties.HasValidFilter()) { if (effectProperties.HasValidFilter()) {
RegularFramePaintCallback callback(aBuilder, aLayerManager, RegularFramePaintCallback callback(aParams.builder, aParams.layerManager,
offsetToUserSpace); offsetToUserSpace);
nsRegion dirtyRegion = aDirtyRect - offsetToBoundingBox; nsRegion dirtyRegion = aParams.dirtyRect - offsetToBoundingBox;
gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(aFrame); gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(frame);
nsFilterInstance::PaintFilteredFrame(aFrame, target->GetDrawTarget(), nsFilterInstance::PaintFilteredFrame(frame, target->GetDrawTarget(),
tm, &callback, &dirtyRegion); tm, &callback, &dirtyRegion);
} else { } else {
target->SetMatrix(matrixAutoSaveRestore.Matrix()); target->SetMatrix(matrixAutoSaveRestore.Matrix());
BasicLayerManager* basic = static_cast<BasicLayerManager*>(aLayerManager); BasicLayerManager* basic = static_cast<BasicLayerManager*>(aParams.layerManager);
RefPtr<gfxContext> oldCtx = basic->GetTarget(); RefPtr<gfxContext> oldCtx = basic->GetTarget();
basic->SetTarget(target); basic->SetTarget(target);
aLayerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer, aBuilder); aParams.layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
aParams.builder);
basic->SetTarget(oldCtx); basic->SetTarget(oldCtx);
} }
if ((clipPathFrame && isTrivialClip) || if ((clipPathFrame && isTrivialClip) ||
(!clipPathFrame && svgReset->HasClipPath())) { (!clipPathFrame && svgReset->HasClipPath())) {
aContext.Restore(); context.Restore();
} }
/* No more effects, we're done. */ /* No more effects, we're done. */
@ -697,18 +694,18 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
target->PopGroupAndBlend(); target->PopGroupAndBlend();
} }
if (aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) { if (frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
RefPtr<DrawTarget> targetDT = target->GetDrawTarget(); RefPtr<DrawTarget> targetDT = target->GetDrawTarget();
target = nullptr; target = nullptr;
RefPtr<SourceSurface> targetSurf = targetDT->Snapshot(); RefPtr<SourceSurface> targetSurf = targetDT->Snapshot();
aContext.SetMatrix(gfxMatrix()); // This will be restored right after. context.SetMatrix(gfxMatrix()); // This will be restored right after.
RefPtr<gfxPattern> pattern = new gfxPattern(targetSurf, Matrix::Translation(targetOffset.x, targetOffset.y)); RefPtr<gfxPattern> pattern = new gfxPattern(targetSurf, Matrix::Translation(targetOffset.x, targetOffset.y));
aContext.SetPattern(pattern); context.SetPattern(pattern);
aContext.Paint(); context.Paint();
} }
aContext.Restore(); context.Restore();
} }
gfxMatrix gfxMatrix

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

@ -123,15 +123,29 @@ public:
static bool static bool
HitTestFrameForEffects(nsIFrame* aFrame, const nsPoint& aPt); HitTestFrameForEffects(nsIFrame* aFrame, const nsPoint& aPt);
struct PaintFramesParams {
gfxContext& ctx;
nsIFrame* frame;
const nsRect& dirtyRect;
const nsRect& borderArea;
nsDisplayListBuilder* builder;
mozilla::layers::LayerManager* layerManager;
explicit PaintFramesParams(gfxContext& aCtx, nsIFrame* aFrame,
const nsRect& aDirtyRect,
const nsRect& aBorderArea,
nsDisplayListBuilder* aBuilder,
mozilla::layers::LayerManager* aLayerManager)
: ctx(aCtx), frame(aFrame), dirtyRect(aDirtyRect),
borderArea(aBorderArea), builder(aBuilder),
layerManager(aLayerManager)
{ }
};
/** /**
* Paint non-SVG frame with SVG effects. * Paint non-SVG frame with SVG effects.
*/ */
static void static void
PaintFramesWithEffects(gfxContext& aCtx, PaintFramesWithEffects(const PaintFramesParams& aParams);
nsIFrame* aFrame, const nsRect& aDirtyRect,
const nsRect& aBorderArea,
nsDisplayListBuilder* aBuilder,
mozilla::layers::LayerManager* aManager);
/** /**
* SVG frames expect to paint in SVG user units, which are equal to CSS px * SVG frames expect to paint in SVG user units, which are equal to CSS px