mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-02 12:07:52 +00:00
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:
parent
ab1a5ceec2
commit
2ec303fb9e
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -85,6 +85,7 @@ public:
|
||||
|
||||
// nsSVGMarkerFrame methods:
|
||||
nsresult PaintMark(nsRenderingContext *aContext,
|
||||
const gfxMatrix& aToMarkedFrameUserSpace,
|
||||
nsSVGPathGeometryFrame *aMarkedFrame,
|
||||
nsSVGMark *aMark,
|
||||
float aStrokeWidth);
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user