--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -6665,20 +6665,22 @@ nsDisplaySVGEffects::HitTest(nsDisplayLi
}
void
nsDisplaySVGEffects::PaintAsLayer(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx,
LayerManager* aManager)
{
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
- nsSVGIntegrationUtils::PaintFramesWithEffects(*aCtx->ThebesContext(), mFrame,
- mVisibleRect,
- borderArea,
- aBuilder, aManager);
+ nsSVGIntegrationUtils::PaintFramesParams params(*aCtx->ThebesContext(),
+ mFrame, mVisibleRect,
+ borderArea, aBuilder,
+ aManager);
+
+ nsSVGIntegrationUtils::PaintFramesWithEffects(params);
}
LayerState
nsDisplaySVGEffects::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters)
{
return LAYER_SVG_EFFECTS;
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -405,124 +405,119 @@ public:
private:
nsDisplayListBuilder* mBuilder;
LayerManager* mLayerManager;
nsPoint mOffset;
};
void
-nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
- nsIFrame* aFrame,
- const nsRect& aDirtyRect,
- const nsRect& aBorderArea,
- nsDisplayListBuilder* aBuilder,
- LayerManager *aLayerManager)
+nsSVGIntegrationUtils::PaintFramesWithEffects(const PaintFramesParams& aParams)
{
#ifdef DEBUG
- NS_ASSERTION(!(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
+ NS_ASSERTION(!(aParams.frame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
(NS_SVGDisplayListPaintingEnabled() &&
- !(aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)),
+ !(aParams.frame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)),
"Should not use nsSVGIntegrationUtils on this SVG frame");
#endif
/* SVG defines the following rendering model:
*
* 1. Render geometry
* 2. Apply filter
* 3. Apply clipping, masking, group opacity
*
* We follow this, but perform a couple of optimizations:
*
* + Use cairo's clipPath when representable natively (single object
* clip region).
*
* + Merge opacity and masking if both used together.
*/
-
- const nsIContent* content = aFrame->GetContent();
- bool hasSVGLayout = (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
+ nsIFrame* frame = aParams.frame;
+ const nsIContent* content = frame->GetContent();
+ bool hasSVGLayout = (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
if (hasSVGLayout) {
- nsISVGChildFrame *svgChildFrame = do_QueryFrame(aFrame);
- if (!svgChildFrame || !aFrame->GetContent()->IsSVGElement()) {
+ nsISVGChildFrame *svgChildFrame = do_QueryFrame(frame);
+ if (!svgChildFrame || !frame->GetContent()->IsSVGElement()) {
NS_ASSERTION(false, "why?");
return;
}
if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
return; // The SVG spec says not to draw _anything_
}
}
- float opacity = aFrame->StyleEffects()->mOpacity;
+ float opacity = frame->StyleEffects()->mOpacity;
if (opacity == 0.0f) {
return;
}
if (opacity != 1.0f &&
- hasSVGLayout && nsSVGUtils::CanOptimizeOpacity(aFrame)) {
+ hasSVGLayout && nsSVGUtils::CanOptimizeOpacity(frame)) {
opacity = 1.0f;
}
/* Properties are added lazily and may have been removed by a restyle,
so make sure all applicable ones are set again. */
nsIFrame* firstFrame =
- nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
+ nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
nsSVGEffects::EffectProperties effectProperties =
nsSVGEffects::GetEffectProperties(firstFrame);
bool isOK = effectProperties.HasNoFilterOrHasValidFilter();
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
bool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : true;
-
- DrawTarget* drawTarget = aContext.GetDrawTarget();
- gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&aContext);
+ gfxContext& context = aParams.ctx;
+ DrawTarget* drawTarget = context.GetDrawTarget();
+ gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&context);
nsPoint firstFrameOffset = GetOffsetToBoundingBox(firstFrame);
- nsPoint offsetToBoundingBox = aBuilder->ToReferenceFrame(firstFrame) - firstFrameOffset;
+ nsPoint offsetToBoundingBox = aParams.builder->ToReferenceFrame(firstFrame) - firstFrameOffset;
if (!firstFrame->IsFrameOfType(nsIFrame::eSVG)) {
/* Snap the offset if the reference frame is not a SVG frame,
* since other frames will be snapped to pixel when rendering. */
offsetToBoundingBox = nsPoint(
- aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.x),
- aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.y));
+ frame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.x),
+ frame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.y));
}
// 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
// SVG frame's "user space", i.e. the space in which, for example, the
// frame's BBox lives.
// SVG geometry frames and foreignObject frames apply their own offsets, so
// their position is relative to their user space. So for these frame types,
// if we want aCtx to be in user space, we first need to subtract the
// frame's position so that SVG painting can later add it again and the
// frame is painted in the right place.
- gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(aFrame);
+ gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(frame);
nsPoint toUserSpace(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)),
nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y)));
nsPoint offsetToUserSpace = offsetToBoundingBox - toUserSpace;
NS_ASSERTION(hasSVGLayout || offsetToBoundingBox == offsetToUserSpace,
"For non-SVG frames there shouldn't be any additional offset");
gfxPoint devPixelOffsetToUserSpace =
nsLayoutUtils::PointToGfxPoint(offsetToUserSpace,
- aFrame->PresContext()->AppUnitsPerDevPixel());
- aContext.SetMatrix(aContext.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
+ frame->PresContext()->AppUnitsPerDevPixel());
+ context.SetMatrix(context.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
- gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(aFrame);
+ gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(frame);
const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
// Keep moving forward even if svgMaskFrame is nullptr or isOK is false.
// This source is not a svg mask, but it still can be a correct mask image.
nsSVGMaskFrame *svgMaskFrame = effectProperties.GetMaskFrame(&isOK);
// 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;
// hasMaskToDraw is true means we have at least one drawable mask resource.
// We need to apply mask only if hasMaskToDraw is true.
bool hasMaskToDraw = (svgMaskFrame != nullptr);
if (!hasMaskToDraw) {
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, svgReset->mMask) {
if (!svgReset->mMask.mLayers[i].mImage.IsEmpty()) {
@@ -531,121 +526,123 @@ nsSVGIntegrationUtils::PaintFramesWithEf
}
}
}
bool complexEffects = false;
/* Check if we need to do additional operations on this child's
* rendering, which necessitates rendering into another surface. */
if (opacity != 1.0f || (clipPathFrame && !isTrivialClip)
- || aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL
+ || frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL
|| hasMaskToDraw) {
complexEffects = true;
- aContext.Save();
+ context.Save();
nsRect clipRect =
- aFrame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
- aContext.Clip(NSRectToSnappedRect(clipRect,
- aFrame->PresContext()->AppUnitsPerDevPixel(),
+ frame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
+ context.Clip(NSRectToSnappedRect(clipRect,
+ frame->PresContext()->AppUnitsPerDevPixel(),
*drawTarget));
Matrix maskTransform;
RefPtr<SourceSurface> maskSurface;
if (svgMaskFrame) {
// Generate maskSurface from a SVG mask.
- maskSurface = svgMaskFrame->GetMaskForMaskedFrame(&aContext,
- aFrame,
+ maskSurface = svgMaskFrame->GetMaskForMaskedFrame(&context,
+ aParams.frame,
cssPxToDevPxMatrix,
opacity,
&maskTransform,
svgReset->mMask.mLayers[0].mMaskMode);
} else if (hasMaskToDraw) {
// Create maskSuface.
- gfxRect clipRect = aContext.GetClipExtents();
+ gfxRect clipRect = context.GetClipExtents();
{
- gfxContextMatrixAutoSaveRestore matRestore(&aContext);
+ gfxContextMatrixAutoSaveRestore matRestore(&context);
- aContext.SetMatrix(gfxMatrix());
- clipRect = aContext.GetClipExtents();
+ context.SetMatrix(gfxMatrix());
+ clipRect = context.GetClipExtents();
}
IntRect drawRect = RoundedOut(ToRect(clipRect));
// Mask composition result on CoreGraphic::A8 surface is not correct
// when mask-mode is not add(source over). Switch to skia when CG backend
// detected.
RefPtr<DrawTarget> targetDT =
- (aContext.GetDrawTarget()->GetBackendType() == BackendType::COREGRAPHICS) ?
+ (context.GetDrawTarget()->GetBackendType() == BackendType::COREGRAPHICS) ?
Factory::CreateDrawTarget(BackendType::SKIA, drawRect.Size(),
SurfaceFormat::A8) :
- aContext.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(),
+ context.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(),
SurfaceFormat::A8);
if (!targetDT || !targetDT->IsValid()) {
- aContext.Restore();
+ context.Restore();
return;
}
RefPtr<gfxContext> target = gfxContext::ForDrawTarget(targetDT);
MOZ_ASSERT(target); // alrady checked the draw target above
target->SetMatrix(matrixAutoSaveRestore.Matrix() * gfxMatrix::Translation(-drawRect.TopLeft()));
// Compose all mask-images onto maskSurface.
nsRenderingContext rc(target);
nsCSSRendering::PaintBGParams params =
- nsCSSRendering::PaintBGParams::ForAllLayers(*aFrame->PresContext(), rc,
- aDirtyRect, aBorderArea,
- aFrame,
- aBuilder->GetBackgroundPaintFlags() |
+ nsCSSRendering::PaintBGParams::ForAllLayers(*aParams.frame->PresContext(),
+ rc,
+ aParams.dirtyRect,
+ aParams.borderArea,
+ aParams.frame,
+ aParams.builder->GetBackgroundPaintFlags() |
nsCSSRendering::PAINTBG_MASK_IMAGE);
// FIXME We should use the return value, see bug 1258510.
Unused << nsCSSRendering::PaintBackgroundWithSC(params,
firstFrame->StyleContext(),
- *aFrame->StyleBorder());
+ *frame->StyleBorder());
maskSurface = targetDT->Snapshot();
// Compute mask transform.
- Matrix mat = ToMatrix(aContext.CurrentMatrix());
+ Matrix mat = ToMatrix(context.CurrentMatrix());
mat.Invert();
maskTransform = Matrix::Translation(drawRect.x, drawRect.y) * mat;
}
if (hasMaskToDraw && !maskSurface) {
// Entire surface is clipped out.
- aContext.Restore();
+ context.Restore();
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
// another operator.
gfxRect clipRect;
{
- gfxContextMatrixAutoSaveRestore matRestore(&aContext);
+ gfxContextMatrixAutoSaveRestore matRestore(&context);
- aContext.SetMatrix(gfxMatrix());
- clipRect = aContext.GetClipExtents();
+ context.SetMatrix(gfxMatrix());
+ clipRect = context.GetClipExtents();
}
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()) {
- aContext.Restore();
+ context.Restore();
return;
}
target = gfxContext::ForDrawTarget(targetDT);
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();
}
if (clipPathFrame && !isTrivialClip) {
Matrix clippedMaskTransform;
- RefPtr<SourceSurface> clipMaskSurface = clipPathFrame->GetClipMask(aContext, aFrame, cssPxToDevPxMatrix,
+ RefPtr<SourceSurface> clipMaskSurface = clipPathFrame->GetClipMask(context, frame, cssPxToDevPxMatrix,
&clippedMaskTransform, maskSurface, maskTransform);
if (clipMaskSurface) {
maskSurface = clipMaskSurface;
maskTransform = clippedMaskTransform;
}
}
@@ -653,67 +650,68 @@ nsSVGIntegrationUtils::PaintFramesWithEf
target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity, maskSurface, maskTransform);
}
}
/* If this frame has only a trivial clipPath, set up cairo's clipping now so
* we can just do normal painting and get it clipped appropriately.
*/
if (clipPathFrame && isTrivialClip) {
- aContext.Save();
- clipPathFrame->ApplyClipPath(aContext, aFrame, cssPxToDevPxMatrix);
+ context.Save();
+ clipPathFrame->ApplyClipPath(context, frame, cssPxToDevPxMatrix);
} else if (!clipPathFrame && svgReset->HasClipPath()) {
- aContext.Save();
- nsCSSClipPathInstance::ApplyBasicShapeClip(aContext, aFrame);
+ context.Save();
+ nsCSSClipPathInstance::ApplyBasicShapeClip(context, frame);
}
/* Paint the child */
if (effectProperties.HasValidFilter()) {
- RegularFramePaintCallback callback(aBuilder, aLayerManager,
+ RegularFramePaintCallback callback(aParams.builder, aParams.layerManager,
offsetToUserSpace);
- nsRegion dirtyRegion = aDirtyRect - offsetToBoundingBox;
- gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(aFrame);
- nsFilterInstance::PaintFilteredFrame(aFrame, target->GetDrawTarget(),
+ nsRegion dirtyRegion = aParams.dirtyRect - offsetToBoundingBox;
+ gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(frame);
+ nsFilterInstance::PaintFilteredFrame(frame, target->GetDrawTarget(),
tm, &callback, &dirtyRegion);
} else {
target->SetMatrix(matrixAutoSaveRestore.Matrix());
- BasicLayerManager* basic = static_cast<BasicLayerManager*>(aLayerManager);
+ BasicLayerManager* basic = static_cast<BasicLayerManager*>(aParams.layerManager);
RefPtr<gfxContext> oldCtx = basic->GetTarget();
basic->SetTarget(target);
- aLayerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer, aBuilder);
+ aParams.layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
+ aParams.builder);
basic->SetTarget(oldCtx);
}
if ((clipPathFrame && isTrivialClip) ||
(!clipPathFrame && svgReset->HasClipPath())) {
- aContext.Restore();
+ context.Restore();
}
/* No more effects, we're done. */
if (!complexEffects) {
return;
}
if (opacity != 1.0f || hasMaskToDraw || (clipPathFrame && !isTrivialClip)) {
target->PopGroupAndBlend();
}
- if (aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
+ if (frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
RefPtr<DrawTarget> targetDT = target->GetDrawTarget();
target = nullptr;
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));
- aContext.SetPattern(pattern);
- aContext.Paint();
+ context.SetPattern(pattern);
+ context.Paint();
}
- aContext.Restore();
+ context.Restore();
}
gfxMatrix
nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(nsIFrame* aNonSVGFrame)
{
int32_t appUnitsPerDevPixel = aNonSVGFrame->PresContext()->AppUnitsPerDevPixel();
float devPxPerCSSPx =
1 / nsPresContext::AppUnitsToFloatCSSPixels(appUnitsPerDevPixel);
--- a/layout/svg/nsSVGIntegrationUtils.h
+++ b/layout/svg/nsSVGIntegrationUtils.h
@@ -118,25 +118,39 @@ public:
/**
* Returns true if the given point is not clipped out by effects.
* @param aPt in appunits relative to aFrame
*/
static bool
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.
*/
static void
- PaintFramesWithEffects(gfxContext& aCtx,
- nsIFrame* aFrame, const nsRect& aDirtyRect,
- const nsRect& aBorderArea,
- nsDisplayListBuilder* aBuilder,
- mozilla::layers::LayerManager* aManager);
+ PaintFramesWithEffects(const PaintFramesParams& aParams);
/**
* SVG frames expect to paint in SVG user units, which are equal to CSS px
* units. This method provides a transform matrix to multiply onto a
* gfxContext's current transform to convert the context's current units from
* its usual dev pixels to SVG user units/CSS px to keep the SVG code happy.
*/
static gfxMatrix