Bug 932771, part 3 - Make PaintSVG painting work by passing transforms down, rather than walking up the tree using GetCanvasTM. r=longsonr

This commit is contained in:
Jonathan Watt 2014-08-29 20:42:07 +01:00
parent ab1a5ceec2
commit 2ec303fb9e
26 changed files with 293 additions and 186 deletions

View File

@ -3134,14 +3134,21 @@ nsDisplaySVGText::Paint(nsDisplayListBuilder* aBuilder,
gfxContextAutoDisableSubpixelAntialiasing
disable(aCtx->ThebesContext(), mDisableSubpixelAA);
uint32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
// ToReferenceFrame includes our mRect offset, but painting takes
// account of that too. To avoid double counting, we subtract that
// here.
nsPoint offset = ToReferenceFrame() - mFrame->GetPosition();
gfxPoint devPixelOffset =
nsLayoutUtils::PointToGfxPoint(offset, appUnitsPerDevPixel);
gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(mFrame) *
gfxMatrix::Translation(devPixelOffset);
aCtx->PushState();
aCtx->Translate(offset);
static_cast<SVGTextFrame*>(mFrame)->PaintSVG(aCtx, nullptr);
static_cast<SVGTextFrame*>(mFrame)->PaintSVG(aCtx, tm);
aCtx->PopState();
}
@ -3565,8 +3572,8 @@ ShouldPaintCaret(const TextRenderedRun& aThisRun, nsCaret* aCaret)
nsresult
SVGTextFrame::PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot)
const gfxMatrix& aTransform,
const nsIntRect *aDirtyRect)
{
nsIFrame* kid = GetFirstPrincipalChild();
if (!kid)
@ -3596,13 +3603,12 @@ SVGTextFrame::PaintSVG(nsRenderingContext* aContext,
return NS_OK;
}
gfxMatrix canvasTM = GetCanvasTM(FOR_PAINTING, aTransformRoot);
if (canvasTM.IsSingular()) {
if (aTransform.IsSingular()) {
NS_WARNING("Can't render text element!");
return NS_ERROR_FAILURE;
}
gfxMatrix matrixForPaintServers = canvasTM * initialMatrix;
gfxMatrix matrixForPaintServers = aTransform * initialMatrix;
// Check if we need to draw anything.
if (aDirtyRect) {
@ -3625,12 +3631,12 @@ SVGTextFrame::PaintSVG(nsRenderingContext* aContext,
}
}
// SVG paints in CSS px, but normally frames paint in dev pixels. Here we
// multiply a CSS-px-to-dev-pixel factor onto canvasTM so our children paint
// correctly.
// SVG frames' PaintSVG methods paint in CSS px, but normally frames paint in
// dev pixels. Here we multiply a CSS-px-to-dev-pixel factor onto aTransform
// so our non-SVG nsTextFrame children paint correctly.
float cssPxPerDevPx = presContext->
AppUnitsToFloatCSSPixels(presContext->AppUnitsPerDevPixel());
gfxMatrix canvasTMForChildren = canvasTM;
gfxMatrix canvasTMForChildren = aTransform;
canvasTMForChildren.Scale(cssPxPerDevPx, cssPxPerDevPx);
initialMatrix.Scale(1 / cssPxPerDevPx, 1 / cssPxPerDevPx);

View File

@ -318,8 +318,8 @@ public:
// nsISVGChildFrame interface:
virtual void NotifySVGChanged(uint32_t aFlags) MOZ_OVERRIDE;
virtual nsresult PaintSVG(nsRenderingContext* aContext,
const nsIntRect* aDirtyRect,
nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE;
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect = nullptr) MOZ_OVERRIDE;
virtual nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) MOZ_OVERRIDE;
virtual void ReflowSVG() MOZ_OVERRIDE;
virtual nsRect GetCoveredRegion() MOZ_OVERRIDE;

View File

@ -24,15 +24,14 @@ using namespace mozilla::dom;
using namespace mozilla::gfx;
nsresult
nsFilterInstance::PaintFilteredFrame(nsRenderingContext *aContext,
nsIFrame *aFilteredFrame,
nsFilterInstance::PaintFilteredFrame(nsIFrame *aFilteredFrame,
nsRenderingContext *aContext,
const gfxMatrix& aTransform,
nsSVGFilterPaintCallback *aPaintCallback,
const nsRegion *aDirtyArea,
nsIFrame* aTransformRoot)
const nsRegion *aDirtyArea)
{
nsFilterInstance instance(aFilteredFrame, aPaintCallback, aDirtyArea,
nullptr, nullptr, nullptr,
aTransformRoot);
nsFilterInstance instance(aFilteredFrame, aPaintCallback, aTransform,
aDirtyArea, nullptr, nullptr, nullptr);
if (!instance.IsInitialized()) {
return NS_OK;
}
@ -47,7 +46,8 @@ nsFilterInstance::GetPostFilterDirtyArea(nsIFrame *aFilteredFrame,
return nsRegion();
}
nsFilterInstance instance(aFilteredFrame, nullptr, nullptr,
gfxMatrix unused; // aPaintTransform arg not used since we're not painting
nsFilterInstance instance(aFilteredFrame, nullptr, unused, nullptr,
&aPreFilterDirtyRegion);
if (!instance.IsInitialized()) {
return nsRegion();
@ -63,7 +63,9 @@ nsRegion
nsFilterInstance::GetPreFilterNeededArea(nsIFrame *aFilteredFrame,
const nsRegion& aPostFilterDirtyRegion)
{
nsFilterInstance instance(aFilteredFrame, nullptr, &aPostFilterDirtyRegion);
gfxMatrix unused; // aPaintTransform arg not used since we're not painting
nsFilterInstance instance(aFilteredFrame, nullptr, unused,
&aPostFilterDirtyRegion);
if (!instance.IsInitialized()) {
return nsRect();
}
@ -89,7 +91,8 @@ nsFilterInstance::GetPostFilterBounds(nsIFrame *aFilteredFrame,
preFilterRegionPtr = &preFilterRegion;
}
nsFilterInstance instance(aFilteredFrame, nullptr, nullptr,
gfxMatrix unused; // aPaintTransform arg not used since we're not painting
nsFilterInstance instance(aFilteredFrame, nullptr, unused, nullptr,
preFilterRegionPtr, aPreFilterBounds,
aOverrideBBox);
if (!instance.IsInitialized()) {
@ -101,15 +104,16 @@ nsFilterInstance::GetPostFilterBounds(nsIFrame *aFilteredFrame,
nsFilterInstance::nsFilterInstance(nsIFrame *aTargetFrame,
nsSVGFilterPaintCallback *aPaintCallback,
const gfxMatrix& aPaintTransform,
const nsRegion *aPostFilterDirtyRegion,
const nsRegion *aPreFilterDirtyRegion,
const nsRect *aPreFilterVisualOverflowRectOverride,
const gfxRect *aOverrideBBox,
nsIFrame* aTransformRoot) :
mTargetFrame(aTargetFrame),
mPaintCallback(aPaintCallback),
mTransformRoot(aTransformRoot),
mInitialized(false) {
const gfxRect *aOverrideBBox)
: mTargetFrame(aTargetFrame)
, mPaintCallback(aPaintCallback)
, mPaintTransform(aPaintTransform)
, mInitialized(false)
{
mTargetBBox = aOverrideBBox ?
*aOverrideBBox : nsSVGUtils::GetBBox(mTargetFrame);
@ -135,8 +139,7 @@ nsFilterInstance::nsFilterInstance(nsIFrame *aTargetFrame,
// Only used (so only set) when we paint:
if (mPaintCallback) {
mFilterSpaceToDeviceSpaceTransform = filterToUserSpace *
nsSVGUtils::GetCanvasTM(mTargetFrame, nsISVGChildFrame::FOR_PAINTING);
mFilterSpaceToDeviceSpaceTransform = filterToUserSpace * mPaintTransform;
}
mAppUnitsPerCSSPx = mTargetFrame->PresContext()->AppUnitsPerCSSPixel();
@ -308,11 +311,8 @@ nsFilterInstance::BuildSourcePaint(SourceInfo *aSource,
gfx->Save();
gfxMatrix matrix =
nsSVGUtils::GetCanvasTM(mTargetFrame, nsISVGChildFrame::FOR_PAINTING,
mTransformRoot);
if (!matrix.IsSingular()) {
gfx->Multiply(matrix);
if (!mPaintTransform.IsSingular()) {
gfx->Multiply(mPaintTransform);
gfx->Rectangle(FilterSpaceToUserSpace(neededRect));
if ((aSource == &mFillPaint &&
nsSVGUtils::SetupCairoFillPaint(mTargetFrame, gfx)) ||
@ -390,7 +390,7 @@ nsFilterInstance::BuildSourceImage(DrawTarget* aTargetDT)
return NS_ERROR_FAILURE;
}
tmpCtx->ThebesContext()->Multiply(deviceToFilterSpace);
mPaintCallback->Paint(tmpCtx, mTargetFrame, &dirty, mTransformRoot);
mPaintCallback->Paint(tmpCtx, mTargetFrame, mPaintTransform, &dirty);
mSourceGraphic.mSourceSurface = offscreenDT->Snapshot();
mSourceGraphic.mSurfaceRect = ToIntRect(neededRect);

View File

@ -55,11 +55,11 @@ public:
* frame space (i.e. relative to its origin, the top-left corner of its
* border box).
*/
static nsresult PaintFilteredFrame(nsRenderingContext *aContext,
nsIFrame *aFilteredFrame,
static nsresult PaintFilteredFrame(nsIFrame *aFilteredFrame,
nsRenderingContext *aContext,
const gfxMatrix& aTransform,
nsSVGFilterPaintCallback *aPaintCallback,
const nsRegion* aDirtyArea,
nsIFrame* aTransformRoot = nullptr);
const nsRegion* aDirtyArea);
/**
* Returns the post-filter area that could be dirtied when the given
@ -95,6 +95,8 @@ public:
* @param aTargetFrame The frame of the filtered element under consideration.
* @param aPaintCallback [optional] The callback that Render() should use to
* paint. Only required if you will call Render().
* @param aPaintTransform The transform to apply to convert to
* aTargetFrame's SVG user space. Only used when painting.
* @param aPostFilterDirtyRegion [optional] The post-filter area
* that has to be repainted, in app units. Only required if you will
* call ComputeSourceNeededRect() or Render().
@ -105,15 +107,14 @@ public:
* visual overflow rect for the target element.
* @param aOverrideBBox [optional] Use a different SVG bbox for the target
* element.
* @param aTransformRoot [optional] The transform root frame for painting.
*/
nsFilterInstance(nsIFrame *aTargetFrame,
nsSVGFilterPaintCallback *aPaintCallback,
const gfxMatrix& aPaintTransform,
const nsRegion *aPostFilterDirtyRegion = nullptr,
const nsRegion *aPreFilterDirtyRegion = nullptr,
const nsRect *aOverridePreFilterVisualOverflowRect = nullptr,
const gfxRect *aOverrideBBox = nullptr,
nsIFrame* aTransformRoot = nullptr);
const gfxRect *aOverrideBBox = nullptr);
/**
* Returns true if the filter instance was created successfully.
@ -313,7 +314,12 @@ private:
SourceInfo mSourceGraphic;
SourceInfo mFillPaint;
SourceInfo mStrokePaint;
nsIFrame* mTransformRoot;
/**
* The transform to the SVG user space of mTargetFrame.
*/
gfxMatrix mPaintTransform;
nsTArray<mozilla::RefPtr<SourceSurface>> mInputImages;
nsTArray<FilterPrimitiveDescription> mPrimitiveDescriptions;
int32_t mAppUnitsPerCSSPx;

View File

@ -9,11 +9,12 @@
#include "gfxRect.h"
#include "nsQueryFrame.h"
class gfxMatrix;
class nsIFrame;
class nsRenderingContext;
class SVGBBox;
struct nsPoint;
class SVGBBox;
struct nsRect;
struct nsIntRect;
@ -47,20 +48,36 @@ public:
NS_DECL_QUERYFRAME_TARGET(nsISVGChildFrame)
// Paint this frame.
// aDirtyRect is the area being redrawn, in frame offset pixel coordinates.
// aTransformRoot (if non-null) is the frame at which we stop looking up
// transforms, when painting content that is part of an SVG glyph. (See
// bug 875329.)
// For normal SVG graphics using display-list rendering, any transforms on
// the element or its parents will have already been set up in the context
// before PaintSVG is called. When painting SVG glyphs, this is not the case,
// so the element's full transform needs to be applied; but we don't want to
// apply transforms from outside the actual glyph element, so we need to know
// how far up the ancestor chain to go.
/**
* Paint this frame.
*
* SVG is painted using a combination of display lists (trees of
* nsDisplayItem built by BuildDisplayList() implementations) and recursive
* PaintSVG calls. SVG frames with the NS_FRAME_IS_NONDISPLAY bit set are
* always painted using recursive PaintSVG calls since display list painting
* would provide no advantages (they wouldn't be retained for invalidation).
* Displayed SVG is normally painted via a display list tree created under
* nsSVGOuterSVGFrame::BuildDisplayList, unless the
* svg.display-lists.painting.enabled pref has been set to false by the user
* in which case it is done via an nsSVGOuterSVGFrame::PaintSVG() call that
* recurses over the entire SVG frame tree. In future we may use PaintSVG()
* calls on SVG container frames to avoid display list construction when it
* is expensive and unnecessary (see bug 934411).
*
* @param aTransform The transform that has to be multiplied onto the
* DrawTarget in order for drawing to be in this frame's SVG user space.
* Implementations of this method should avoid multiplying aTransform onto
* the DrawTarget when possible and instead just pass a transform down to
* their children. This is preferable because changing the transform is
* very expensive for certain DrawTarget backends so it is best to minimize
* the number of transform changes.
*
* @param aDirtyRect The area being redrawn, in frame offset pixel
* coordinates.
*/
virtual nsresult PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot = nullptr) = 0;
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect = nullptr) = 0;
/**
* Returns the frame that should handle pointer events at aPoint. aPoint is

View File

@ -56,9 +56,20 @@ nsSVGClipPathFrame::ApplyClipOrPaintClipMask(nsRenderingContext* aContext,
// We have no children - the spec says clip away everything:
gfx->Rectangle(gfxRect());
} else {
singleClipPathChild->NotifySVGChanged(
nsISVGChildFrame::TRANSFORM_CHANGED);
singleClipPathChild->PaintSVG(aContext, nullptr);
nsIFrame* child = do_QueryFrame(singleClipPathChild);
nsIContent* childContent = child->GetContent();
if (childContent->IsSVG()) {
singleClipPathChild->NotifySVGChanged(
nsISVGChildFrame::TRANSFORM_CHANGED);
gfxMatrix toChildsUserSpace =
static_cast<const nsSVGElement*>(childContent)->
PrependLocalTransformsTo(mMatrixForChildren,
nsSVGElement::eUserSpaceToParent);
singleClipPathChild->PaintSVG(aContext, toChildsUserSpace);
} else {
// else, again, clip everything away
gfx->Rectangle(gfxRect());
}
}
gfx->Clip();
gfx->NewPath();
@ -110,7 +121,16 @@ nsSVGClipPathFrame::ApplyClipOrPaintClipMask(nsRenderingContext* aContext,
}
}
SVGFrame->PaintSVG(aContext, nullptr);
gfxMatrix toChildsUserSpace = mMatrixForChildren;
nsIFrame* child = do_QueryFrame(SVGFrame);
nsIContent* childContent = child->GetContent();
if (childContent->IsSVG()) {
toChildsUserSpace =
static_cast<const nsSVGElement*>(childContent)->
PrependLocalTransformsTo(mMatrixForChildren,
nsSVGElement::eUserSpaceToParent);
}
SVGFrame->PaintSVG(aContext, toChildsUserSpace);
if (clipPathFrame) {
if (!isTrivial) {

View File

@ -249,8 +249,8 @@ nsSVGDisplayContainerFrame::IsSVGTransformed(gfx::Matrix *aOwnTransform,
nsresult
nsSVGDisplayContainerFrame::PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot)
const gfxMatrix& aTransform,
const nsIntRect *aDirtyRect)
{
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(mState & NS_FRAME_IS_NONDISPLAY) ||
@ -259,12 +259,38 @@ nsSVGDisplayContainerFrame::PaintSVG(nsRenderingContext* aContext,
"SVG should take this code path");
const nsStyleDisplay *display = StyleDisplay();
if (display->mOpacity == 0.0)
if (display->mOpacity == 0.0) {
return NS_OK;
}
gfxMatrix matrix = aTransform;
if (GetContent()->IsSVG()) { // must check before cast
matrix = static_cast<const nsSVGElement*>(GetContent())->
PrependLocalTransformsTo(matrix,
nsSVGElement::eChildToUserSpace);
if (matrix.IsSingular()) {
return NS_OK;
}
}
for (nsIFrame* kid = mFrames.FirstChild(); kid;
kid = kid->GetNextSibling()) {
nsSVGUtils::PaintFrameWithEffects(aContext, aDirtyRect, kid, aTransformRoot);
gfxMatrix m = matrix;
// PaintFrameWithEffects() expects the transform that is passed to it to
// include the transform to the passed frame's user space, so add it:
const nsIContent* content = kid->GetContent();
if (content->IsSVG()) { // must check before cast
const nsSVGElement* element = static_cast<const nsSVGElement*>(content);
if (!element->HasValidDimensions()) {
continue; // nothing to paint for kid
}
m = element->
PrependLocalTransformsTo(m, nsSVGElement::eUserSpaceToParent);
if (m.IsSingular()) {
continue;
}
}
nsSVGUtils::PaintFrameWithEffects(kid, aContext, m, aDirtyRect);
}
return NS_OK;

View File

@ -146,8 +146,8 @@ public:
// nsISVGChildFrame interface:
virtual nsresult PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE;
const gfxMatrix& aTransform,
const nsIntRect *aDirtyRect = nullptr) MOZ_OVERRIDE;
virtual nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) MOZ_OVERRIDE;
virtual nsRect GetCoveredRegion() MOZ_OVERRIDE;
virtual void ReflowSVG() MOZ_OVERRIDE;

View File

@ -26,8 +26,8 @@ public:
* into account when painting an SVG glyph
*/
virtual void Paint(nsRenderingContext *aContext, nsIFrame *aTarget,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot) = 0;
const gfxMatrix& aTransform,
const nsIntRect *aDirtyRect) = 0;
};
#endif

View File

@ -193,8 +193,8 @@ nsSVGForeignObjectFrame::IsSVGTransformed(Matrix *aOwnTransform,
nsresult
nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot)
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect)
{
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(mState & NS_FRAME_IS_NONDISPLAY),
@ -208,9 +208,7 @@ nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
if (!kid)
return NS_OK;
gfxMatrix canvasTM = GetCanvasTM(FOR_PAINTING, aTransformRoot);
if (canvasTM.IsSingular()) {
if (aTransform.IsSingular()) {
NS_WARNING("Can't render foreignObject element!");
return NS_ERROR_FAILURE;
}
@ -223,7 +221,7 @@ nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
(mState & NS_FRAME_IS_NONDISPLAY),
"Display lists handle dirty rect intersection test");
// Transform the dirty rect into app units in our userspace.
gfxMatrix invmatrix = canvasTM;
gfxMatrix invmatrix = aTransform;
DebugOnly<bool> ok = invmatrix.Invert();
NS_ASSERTION(ok, "inverse of non-singular matrix should be non-singular");
@ -254,15 +252,15 @@ nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
gfxRect clipRect =
nsSVGUtils::GetClipRectForFrame(this, 0.0f, 0.0f, width, height);
nsSVGUtils::SetClipRect(gfx, canvasTM, clipRect);
nsSVGUtils::SetClipRect(gfx, aTransform, clipRect);
}
// SVG paints in CSS px, but normally frames paint in dev pixels. Here we
// multiply a CSS-px-to-dev-pixel factor onto canvasTM so our children paint
// correctly.
// multiply a CSS-px-to-dev-pixel factor onto aTransform so our children
// paint correctly.
float cssPxPerDevPx = PresContext()->
AppUnitsToFloatCSSPixels(PresContext()->AppUnitsPerDevPixel());
gfxMatrix canvasTMForChildren = canvasTM;
gfxMatrix canvasTMForChildren = aTransform;
canvasTMForChildren.Scale(cssPxPerDevPx, cssPxPerDevPx);
gfx->Multiply(canvasTMForChildren);

View File

@ -77,8 +77,8 @@ public:
// nsISVGChildFrame interface:
virtual nsresult PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE;
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect = nullptr) MOZ_OVERRIDE;
virtual nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) MOZ_OVERRIDE;
virtual nsRect GetCoveredRegion() MOZ_OVERRIDE;
virtual void ReflowSVG() MOZ_OVERRIDE;

View File

@ -63,8 +63,8 @@ public:
// nsISVGChildFrame interface:
virtual nsresult PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot) MOZ_OVERRIDE;
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect = nullptr) MOZ_OVERRIDE;
virtual nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) MOZ_OVERRIDE;
virtual void ReflowSVG() MOZ_OVERRIDE;
@ -100,13 +100,10 @@ public:
private:
gfx::Matrix GetRasterImageTransform(int32_t aNativeWidth,
int32_t aNativeHeight,
uint32_t aFor,
nsIFrame* aTransformRoot = nullptr);
gfx::Matrix GetVectorImageTransform(uint32_t aFor,
nsIFrame* aTransformRoot = nullptr);
int32_t aNativeHeight);
gfx::Matrix GetVectorImageTransform();
bool TransformContextForPainting(gfxContext* aGfxContext,
nsIFrame* aTransformRoot);
const gfxMatrix& aTransform);
nsCOMPtr<imgINotificationObserver> mListener;
@ -230,9 +227,7 @@ nsSVGImageFrame::AttributeChanged(int32_t aNameSpaceID,
gfx::Matrix
nsSVGImageFrame::GetRasterImageTransform(int32_t aNativeWidth,
int32_t aNativeHeight,
uint32_t aFor,
nsIFrame* aTransformRoot)
int32_t aNativeHeight)
{
float x, y, width, height;
SVGImageElement *element = static_cast<SVGImageElement*>(mContent);
@ -243,14 +238,11 @@ nsSVGImageFrame::GetRasterImageTransform(int32_t aNativeWidth,
0, 0, aNativeWidth, aNativeHeight,
element->mPreserveAspectRatio);
return viewBoxTM *
gfx::Matrix::Translation(x, y) *
gfx::ToMatrix(GetCanvasTM(aFor, aTransformRoot));
return viewBoxTM * gfx::Matrix::Translation(x, y);
}
gfx::Matrix
nsSVGImageFrame::GetVectorImageTransform(uint32_t aFor,
nsIFrame* aTransformRoot)
nsSVGImageFrame::GetVectorImageTransform()
{
float x, y, width, height;
SVGImageElement *element = static_cast<SVGImageElement*>(mContent);
@ -260,17 +252,16 @@ nsSVGImageFrame::GetVectorImageTransform(uint32_t aFor,
// "native size" that the SVG image has, and it will handle viewBox and
// preserveAspectRatio on its own once we give it a region to draw into.
return gfx::Matrix::Translation(x, y) *
gfx::ToMatrix(GetCanvasTM(aFor, aTransformRoot));
return gfx::Matrix::Translation(x, y);
}
bool
nsSVGImageFrame::TransformContextForPainting(gfxContext* aGfxContext,
nsIFrame* aTransformRoot)
const gfxMatrix& aTransform)
{
gfx::Matrix imageTransform;
if (mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) {
imageTransform = GetVectorImageTransform(FOR_PAINTING, aTransformRoot);
imageTransform = GetVectorImageTransform() * ToMatrix(aTransform);
} else {
int32_t nativeWidth, nativeHeight;
if (NS_FAILED(mImageContainer->GetWidth(&nativeWidth)) ||
@ -279,8 +270,7 @@ nsSVGImageFrame::TransformContextForPainting(gfxContext* aGfxContext,
return false;
}
imageTransform =
GetRasterImageTransform(nativeWidth, nativeHeight, FOR_PAINTING,
aTransformRoot);
GetRasterImageTransform(nativeWidth, nativeHeight) * ToMatrix(aTransform);
// NOTE: We need to cancel out the effects of Full-Page-Zoom, or else
// it'll get applied an extra time by DrawSingleUnscaledImage.
@ -302,8 +292,8 @@ nsSVGImageFrame::TransformContextForPainting(gfxContext* aGfxContext,
// nsISVGChildFrame methods:
nsresult
nsSVGImageFrame::PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot)
const gfxMatrix& aTransform,
const nsIntRect *aDirtyRect)
{
nsresult rv = NS_OK;
@ -334,11 +324,10 @@ nsSVGImageFrame::PaintSVG(nsRenderingContext *aContext,
if (StyleDisplay()->IsScrollableOverflow()) {
gfxRect clipRect = nsSVGUtils::GetClipRectForFrame(this, x, y,
width, height);
nsSVGUtils::SetClipRect(ctx, GetCanvasTM(FOR_PAINTING, aTransformRoot),
clipRect);
nsSVGUtils::SetClipRect(ctx, aTransform, clipRect);
}
if (!TransformContextForPainting(ctx, aTransformRoot)) {
if (!TransformContextForPainting(ctx, aTransform)) {
return NS_ERROR_FAILURE;
}
@ -363,8 +352,8 @@ nsSVGImageFrame::PaintSVG(nsRenderingContext *aContext,
dirtyRect = aDirtyRect->ToAppUnits(appUnitsPerDevPx);
// Adjust dirtyRect to match our local coordinate system.
nsRect rootRect =
nsSVGUtils::TransformFrameRectToOuterSVG(mRect,
GetCanvasTM(FOR_PAINTING), PresContext());
nsSVGUtils::TransformFrameRectToOuterSVG(mRect, aTransform,
PresContext());
dirtyRect.MoveBy(-rootRect.TopLeft());
}

View File

@ -61,8 +61,8 @@ nsSVGInnerSVGFrame::GetType() const
nsresult
nsSVGInnerSVGFrame::PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot)
const gfxMatrix& aTransform,
const nsIntRect *aDirtyRect)
{
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(mState & NS_FRAME_IS_NONDISPLAY),
@ -80,17 +80,14 @@ nsSVGInnerSVGFrame::PaintSVG(nsRenderingContext *aContext,
return NS_OK;
}
nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(GetParent());
gfxMatrix clipTransform = parent->GetCanvasTM(FOR_PAINTING, aTransformRoot);
gfxContext *gfx = aContext->ThebesContext();
autoSR.SetContext(gfx);
gfxRect clipRect =
nsSVGUtils::GetClipRectForFrame(this, x, y, width, height);
nsSVGUtils::SetClipRect(gfx, clipTransform, clipRect);
nsSVGUtils::SetClipRect(gfx, aTransform, clipRect);
}
return nsSVGInnerSVGFrameBase::PaintSVG(aContext, aDirtyRect);
return nsSVGInnerSVGFrameBase::PaintSVG(aContext, aTransform, aDirtyRect);
}
nsRect

View File

@ -54,8 +54,8 @@ public:
// nsISVGChildFrame interface:
virtual nsresult PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE;
const gfxMatrix& aTransform,
const nsIntRect *aDirtyRect = nullptr) MOZ_OVERRIDE;
virtual nsRect GetCoveredRegion() MOZ_OVERRIDE;
virtual void ReflowSVG() MOZ_OVERRIDE;
virtual void NotifySVGChanged(uint32_t aFlags) MOZ_OVERRIDE;

View File

@ -381,8 +381,8 @@ public:
mOffset(aOffset) {}
virtual void Paint(nsRenderingContext *aContext, nsIFrame *aTarget,
const nsIntRect* aDirtyRect,
nsIFrame* aTransformRoot) MOZ_OVERRIDE
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect) MOZ_OVERRIDE
{
BasicLayerManager* basic = static_cast<BasicLayerManager*>(mLayerManager);
basic->SetTarget(aContext->ThebesContext());
@ -524,7 +524,8 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
offsetToUserSpace);
nsRegion dirtyRegion = aDirtyRect - offsetToBoundingBox;
nsFilterInstance::PaintFilteredFrame(aCtx, aFrame, &callback, &dirtyRegion);
gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(aFrame);
nsFilterInstance::PaintFilteredFrame(aFrame, aCtx, tm, &callback, &dirtyRegion);
} else {
gfx->SetMatrix(matrixAutoSaveRestore.Matrix());
aLayerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder);

View File

@ -104,6 +104,7 @@ GetAnonymousChildFrame(nsIFrame* aFrame)
nsresult
nsSVGMarkerFrame::PaintMark(nsRenderingContext *aContext,
const gfxMatrix& aToMarkedFrameUserSpace,
nsSVGPathGeometryFrame *aMarkedFrame,
nsSVGMark *aMark, float aStrokeWidth)
{
@ -133,6 +134,14 @@ nsSVGMarkerFrame::PaintMark(nsRenderingContext *aContext,
mAutoAngle = aMark->angle;
mIsStart = aMark->type == nsSVGMark::eStart;
Matrix viewBoxTM = marker->GetViewBoxTransform();
Matrix markerTM = marker->GetMarkerTransform(mStrokeWidth, mX, mY,
mAutoAngle, mIsStart);
gfxMatrix markTM = ThebesMatrix(viewBoxTM) * ThebesMatrix(markerTM) *
aToMarkedFrameUserSpace;
gfxContext *gfx = aContext->ThebesContext();
if (StyleDisplay()->IsScrollableOverflow()) {
@ -140,15 +149,15 @@ nsSVGMarkerFrame::PaintMark(nsRenderingContext *aContext,
gfxRect clipRect =
nsSVGUtils::GetClipRectForFrame(this, viewBox.x, viewBox.y,
viewBox.width, viewBox.height);
nsSVGUtils::SetClipRect(gfx, GetCanvasTM(nsISVGChildFrame::FOR_PAINTING),
clipRect);
nsSVGUtils::SetClipRect(gfx, markTM, clipRect);
}
nsIFrame* kid = GetAnonymousChildFrame(this);
nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
// The CTM of each frame referencing us may be different.
SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);
nsSVGUtils::PaintFrameWithEffects(aContext, nullptr, kid);
nsSVGUtils::PaintFrameWithEffects(kid, aContext, markTM);
if (StyleDisplay()->IsScrollableOverflow())
gfx->Restore();

View File

@ -85,6 +85,7 @@ public:
// nsSVGMarkerFrame methods:
nsresult PaintMark(nsRenderingContext *aContext,
const gfxMatrix& aToMarkedFrameUserSpace,
nsSVGPathGeometryFrame *aMarkedFrame,
nsSVGMark *aMark,
float aStrokeWidth);

View File

@ -238,7 +238,12 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(gfxContext* aContext,
if (SVGFrame) {
SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);
}
nsSVGUtils::PaintFrameWithEffects(tmpCtx, nullptr, kid);
gfxMatrix m = mMatrixForChildren;
if (kid->GetContent()->IsSVG()) {
m = static_cast<nsSVGElement*>(kid->GetContent())->
PrependLocalTransformsTo(m);
}
nsSVGUtils::PaintFrameWithEffects(kid, tmpCtx, mMatrixForChildren);
}
RefPtr<SourceSurface> maskSnapshot = maskDT->Snapshot();

View File

@ -573,13 +573,21 @@ nsDisplayOuterSVG::Paint(nsDisplayListBuilder* aBuilder,
nsRect clipRect = mVisibleRect.Intersect(viewportRect);
uint32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
nsIntRect contentAreaDirtyRect =
(clipRect - viewportRect.TopLeft()).
ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel());
ToOutsidePixels(appUnitsPerDevPixel);
gfxPoint devPixelOffset =
nsLayoutUtils::PointToGfxPoint(viewportRect.TopLeft(), appUnitsPerDevPixel);
aContext->PushState();
aContext->Translate(viewportRect.TopLeft());
nsSVGUtils::PaintFrameWithEffects(aContext, &contentAreaDirtyRect, mFrame);
// We include the offset of our frame and a scale from device pixels to user
// units (i.e. CSS px) in the matrix that we pass to our children):
gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(mFrame) *
gfxMatrix::Translation(devPixelOffset);
nsSVGUtils::PaintFrameWithEffects(mFrame, aContext, tm, &contentAreaDirtyRect);
aContext->PopState();
NS_ASSERTION(!aContext->ThebesContext()->HasError(), "Cairo in error state");
@ -802,8 +810,8 @@ nsSVGOuterSVGFrame::NotifyViewportOrTransformChanged(uint32_t aFlags)
nsresult
nsSVGOuterSVGFrame::PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot)
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect)
{
NS_ASSERTION(GetFirstPrincipalChild()->GetType() ==
nsGkAtoms::svgOuterSVGAnonChildFrame &&
@ -811,7 +819,7 @@ nsSVGOuterSVGFrame::PaintSVG(nsRenderingContext* aContext,
"We should have a single, anonymous, child");
nsSVGOuterSVGAnonChildFrame *anonKid =
static_cast<nsSVGOuterSVGAnonChildFrame*>(GetFirstPrincipalChild());
return anonKid->PaintSVG(aContext, aDirtyRect, aTransformRoot);
return anonKid->PaintSVG(aContext, aTransform, aDirtyRect);
}
SVGBBox

View File

@ -115,8 +115,8 @@ public:
// nsISVGChildFrame methods:
virtual nsresult PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE;
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect = nullptr) MOZ_OVERRIDE;
virtual SVGBBox GetBBoxContribution(const Matrix &aToBBoxUserspace,
uint32_t aFlags) MOZ_OVERRIDE;

View File

@ -97,14 +97,20 @@ void
nsDisplaySVGPathGeometry::Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx)
{
uint32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
// ToReferenceFrame includes our mRect offset, but painting takes
// account of that too. To avoid double counting, we subtract that
// here.
nsPoint offset = ToReferenceFrame() - mFrame->GetPosition();
gfxPoint devPixelOffset =
nsLayoutUtils::PointToGfxPoint(offset, appUnitsPerDevPixel);
aCtx->PushState();
aCtx->Translate(offset);
static_cast<nsSVGPathGeometryFrame*>(mFrame)->PaintSVG(aCtx, nullptr);
gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(mFrame) *
gfxMatrix::Translation(devPixelOffset);
static_cast<nsSVGPathGeometryFrame*>(mFrame)->PaintSVG(aCtx, tm);
aCtx->PopState();
}
@ -207,29 +213,29 @@ nsSVGPathGeometryFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
nsresult
nsSVGPathGeometryFrame::PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot)
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect)
{
if (!StyleVisibility()->IsVisible())
return NS_OK;
uint32_t paintOrder = StyleSVG()->mPaintOrder;
if (paintOrder == NS_STYLE_PAINT_ORDER_NORMAL) {
Render(aContext, eRenderFill | eRenderStroke, aTransformRoot);
PaintMarkers(aContext);
Render(aContext, eRenderFill | eRenderStroke, aTransform);
PaintMarkers(aContext, aTransform);
} else {
while (paintOrder) {
uint32_t component =
paintOrder & ((1 << NS_STYLE_PAINT_ORDER_BITWIDTH) - 1);
switch (component) {
case NS_STYLE_PAINT_ORDER_FILL:
Render(aContext, eRenderFill, aTransformRoot);
Render(aContext, eRenderFill, aTransform);
break;
case NS_STYLE_PAINT_ORDER_STROKE:
Render(aContext, eRenderStroke, aTransformRoot);
Render(aContext, eRenderStroke, aTransform);
break;
case NS_STYLE_PAINT_ORDER_MARKERS:
PaintMarkers(aContext);
PaintMarkers(aContext, aTransform);
break;
}
paintOrder >>= NS_STYLE_PAINT_ORDER_BITWIDTH;
@ -613,7 +619,7 @@ nsSVGPathGeometryFrame::MarkerProperties::GetMarkerEndFrame()
void
nsSVGPathGeometryFrame::Render(nsRenderingContext *aContext,
uint32_t aRenderComponents,
nsIFrame* aTransformRoot)
const gfxMatrix& aTransform)
{
gfxContext *gfx = aContext->ThebesContext();
@ -653,7 +659,7 @@ nsSVGPathGeometryFrame::Render(nsRenderingContext *aContext,
autoSaveRestore.SetContext(gfx);
//}
GeneratePath(gfx, ToMatrix(GetCanvasTM(FOR_PAINTING, aTransformRoot)));
GeneratePath(gfx, ToMatrix(aTransform));
// We used to call gfx->Restore() here, since for the
// SVGAutoRenderState::CLIP case it is important to leave the fill rule
@ -682,7 +688,7 @@ nsSVGPathGeometryFrame::Render(nsRenderingContext *aContext,
gfxContextAutoSaveRestore autoSaveRestore(gfx);
GeneratePath(gfx, ToMatrix(GetCanvasTM(FOR_PAINTING, aTransformRoot)));
GeneratePath(gfx, ToMatrix(aTransform));
gfxTextContextPaint *contextPaint =
(gfxTextContextPaint*)aContext->GetUserData(&gfxTextContextPaint::sUserDataKey);
@ -723,7 +729,8 @@ nsSVGPathGeometryFrame::GeneratePath(gfxContext* aContext,
}
void
nsSVGPathGeometryFrame::PaintMarkers(nsRenderingContext* aContext)
nsSVGPathGeometryFrame::PaintMarkers(nsRenderingContext* aContext,
const gfxMatrix& aTransform)
{
gfxTextContextPaint *contextPaint =
(gfxTextContextPaint*)aContext->GetUserData(&gfxTextContextPaint::sUserDataKey);
@ -752,7 +759,7 @@ nsSVGPathGeometryFrame::PaintMarkers(nsRenderingContext* aContext)
nsSVGMark& mark = marks[i];
nsSVGMarkerFrame* frame = markerFrames[mark.type];
if (frame) {
frame->PaintMark(aContext, this, &mark, strokeWidth);
frame->PaintMark(aContext, aTransform, this, &mark, strokeWidth);
}
}
}

View File

@ -94,8 +94,8 @@ public:
protected:
// nsISVGChildFrame interface:
virtual nsresult PaintSVG(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE;
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect = nullptr) MOZ_OVERRIDE;
virtual nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) MOZ_OVERRIDE;
virtual nsRect GetCoveredRegion() MOZ_OVERRIDE;
virtual void ReflowSVG() MOZ_OVERRIDE;
@ -115,8 +115,13 @@ protected:
private:
enum { eRenderFill = 1, eRenderStroke = 2 };
void Render(nsRenderingContext *aContext, uint32_t aRenderComponents,
nsIFrame* aTransformRoot);
void PaintMarkers(nsRenderingContext *aContext);
const gfxMatrix& aTransform);
/**
* @param aMatrix The transform that must be multiplied onto aContext to
* establish this frame's SVG user space.
*/
void PaintMarkers(nsRenderingContext *aContext, const gfxMatrix& aMatrix);
struct MarkerProperties {
nsSVGMarkerProperty* mMarkerStart;

View File

@ -413,7 +413,12 @@ nsSVGPatternFrame::PaintPattern(Matrix* patternMatrix,
if (SVGFrame) {
SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);
}
nsSVGUtils::PaintFrameWithEffects(context, nullptr, kid);
gfxMatrix tm = *(patternFrame->mCTM);
if (kid->GetContent()->IsSVG()) {
tm = static_cast<nsSVGElement*>(kid->GetContent())->
PrependLocalTransformsTo(tm, nsSVGElement::eUserSpaceToParent);
}
nsSVGUtils::PaintFrameWithEffects(kid, context, tm);
}
patternFrame->RemoveStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);
}

View File

@ -53,8 +53,8 @@ public:
// nsISVGChildFrame interface:
virtual nsresult PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot) MOZ_OVERRIDE;
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect = nullptr) MOZ_OVERRIDE;
nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) MOZ_OVERRIDE;
nsRect GetCoveredRegion() MOZ_OVERRIDE;
virtual void ReflowSVG() MOZ_OVERRIDE;
@ -108,8 +108,8 @@ nsSVGSwitchFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
nsresult
nsSVGSwitchFrame::PaintSVG(nsRenderingContext* aContext,
const nsIntRect *aDirtyRect,
nsIFrame* aTransformRoot)
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect)
{
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(mState & NS_FRAME_IS_NONDISPLAY),
@ -121,7 +121,12 @@ nsSVGSwitchFrame::PaintSVG(nsRenderingContext* aContext,
nsIFrame *kid = GetActiveChildFrame();
if (kid) {
nsSVGUtils::PaintFrameWithEffects(aContext, aDirtyRect, kid, aTransformRoot);
gfxMatrix tm = aTransform;
if (kid->GetContent()->IsSVG()) {
tm = static_cast<nsSVGElement*>(kid->GetContent())->
PrependLocalTransformsTo(tm, nsSVGElement::eUserSpaceToParent);
}
nsSVGUtils::PaintFrameWithEffects(kid, aContext, tm, aDirtyRect);
}
return NS_OK;
}

View File

@ -448,8 +448,8 @@ class SVGPaintCallback : public nsSVGFilterPaintCallback
{
public:
virtual void Paint(nsRenderingContext *aContext, nsIFrame *aTarget,
const nsIntRect* aDirtyRect,
nsIFrame* aTransformRoot) MOZ_OVERRIDE
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect) MOZ_OVERRIDE
{
nsISVGChildFrame *svgChildFrame = do_QueryFrame(aTarget);
NS_ASSERTION(svgChildFrame, "Expected SVG frame here");
@ -460,8 +460,7 @@ public:
// aDirtyRect is in user-space pixels, we need to convert to
// outer-SVG-frame-relative device pixels.
if (aDirtyRect) {
gfxMatrix userToDeviceSpace =
nsSVGUtils::GetCanvasTM(aTarget, nsISVGChildFrame::FOR_PAINTING, aTransformRoot);
gfxMatrix userToDeviceSpace = aTransform;
if (userToDeviceSpace.IsSingular()) {
return;
}
@ -473,15 +472,15 @@ public:
}
}
svgChildFrame->PaintSVG(aContext, dirtyRect, aTransformRoot);
svgChildFrame->PaintSVG(aContext, aTransform, dirtyRect);
}
};
void
nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame *aFrame,
nsIFrame *aTransformRoot)
nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame,
nsRenderingContext *aContext,
const gfxMatrix& aTransform,
const nsIntRect *aDirtyRect)
{
NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
(aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY) ||
@ -525,7 +524,7 @@ nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
overflowRect = overflowRect + aFrame->GetPosition();
}
int32_t appUnitsPerDevPx = aFrame->PresContext()->AppUnitsPerDevPixel();
gfxMatrix tm = GetCanvasTM(aFrame, nsISVGChildFrame::FOR_PAINTING, aTransformRoot);
gfxMatrix tm = aTransform;
if (aFrame->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer)) {
gfx::Matrix childrenOnlyTM;
if (static_cast<nsSVGContainerFrame*>(aFrame)->
@ -576,10 +575,6 @@ nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
// Some resource is invalid. We shouldn't paint anything.
return;
}
gfxMatrix matrix;
if (clipPathFrame || maskFrame)
matrix = GetCanvasTM(aFrame, nsISVGChildFrame::FOR_PAINTING, aTransformRoot);
/* Check if we need to do additional operations on this child's
* rendering, which necessitates rendering into another surface. */
@ -591,7 +586,7 @@ nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
// aFrame has a valid visual overflow rect, so clip to it before calling
// PushGroup() to minimize the size of the surfaces we'll composite:
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(gfx);
gfx->Multiply(GetCanvasTM(aFrame, nsISVGChildFrame::FOR_PAINTING, aTransformRoot));
gfx->Multiply(aTransform);
nsRect overflowRect = aFrame->GetVisualOverflowRectRelativeToSelf();
if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry) ||
aFrame->IsSVGText()) {
@ -609,7 +604,7 @@ nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
*/
if (clipPathFrame && isTrivialClip) {
gfx->Save();
clipPathFrame->ApplyClipOrPaintClipMask(aContext, aFrame, matrix);
clipPathFrame->ApplyClipOrPaintClipMask(aContext, aFrame, aTransform);
}
/* Paint the child */
@ -636,10 +631,10 @@ nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
dirtyRegion = &tmpDirtyRegion;
}
SVGPaintCallback paintCallback;
nsFilterInstance::PaintFilteredFrame(aContext, aFrame, &paintCallback,
dirtyRegion, aTransformRoot);
nsFilterInstance::PaintFilteredFrame(aFrame, aContext, aTransform,
&paintCallback, dirtyRegion);
} else {
svgChildFrame->PaintSVG(aContext, aDirtyRect, aTransformRoot);
svgChildFrame->PaintSVG(aContext, aTransform, aDirtyRect);
}
if (clipPathFrame && isTrivialClip) {
@ -654,14 +649,14 @@ nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
nsRefPtr<gfxPattern> maskSurface =
maskFrame ? maskFrame->GetMaskForMaskedFrame(aContext->ThebesContext(),
aFrame, matrix, opacity)
aFrame, aTransform, opacity)
: nullptr;
nsRefPtr<gfxPattern> clipMaskSurface;
if (clipPathFrame && !isTrivialClip) {
gfx->PushGroup(gfxContentType::COLOR_ALPHA);
nsresult rv = clipPathFrame->ApplyClipOrPaintClipMask(aContext, aFrame, matrix);
nsresult rv = clipPathFrame->ApplyClipOrPaintClipMask(aContext, aFrame, aTransform);
clipMaskSurface = gfx->PopGroup();
if (NS_SUCCEEDED(rv) && clipMaskSurface) {
@ -1606,7 +1601,14 @@ nsSVGUtils::PaintSVGGlyph(Element* aElement, gfxContext* aContext,
context->AddUserData(&gfxTextContextPaint::sUserDataKey, aContextPaint,
nullptr);
svgFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);
nsresult rv = svgFrame->PaintSVG(context, nullptr, frame);
gfxMatrix m;
if (frame->GetContent()->IsSVG()) {
// PaintSVG() expects the passed transform to be the transform to its own
// SVG user space, so we need to account for any 'transform' attribute:
m = static_cast<nsSVGElement*>(frame->GetContent())->
PrependLocalTransformsTo(gfxMatrix(), nsSVGElement::eUserSpaceToParent);
}
nsresult rv = svgFrame->PaintSVG(context, m);
return NS_SUCCEEDED(rv);
}

View File

@ -296,10 +296,10 @@ public:
/* Paint SVG frame with SVG effects - aDirtyRect is the area being
* redrawn, in device pixel coordinates relative to the outer svg */
static void
PaintFrameWithEffects(nsRenderingContext *aContext,
const nsIntRect *aDirtyRect,
nsIFrame *aFrame,
nsIFrame* aTransformRoot = nullptr);
PaintFrameWithEffects(nsIFrame *aFrame,
nsRenderingContext *aContext,
const gfxMatrix& aTransform,
const nsIntRect *aDirtyRect = nullptr);
/* Hit testing - check if point hits the clipPath of indicated
* frame. Returns true if no clipPath set. */