From f410406b6091cb050e14374d85e765bd26a8dc30 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Mon, 9 Jul 2012 02:04:56 +0100 Subject: [PATCH] Bug 769742 - Account for nsSVGOuterSVGFrames' border/padding offset by giving nsSVGOuterSVGFrame an anonymous child to wrap its real children. r=roc. --- content/base/src/nsGkAtomList.h | 1 + layout/base/nsCSSFrameConstructor.cpp | 121 ++++++++++++++--- layout/base/nsCSSFrameConstructor.h | 12 ++ layout/generic/nsFrameIdList.h | 1 + layout/style/nsCSSAnonBoxList.h | 1 + layout/svg/base/src/nsSVGOuterSVGFrame.cpp | 145 +++++++++++++++------ layout/svg/base/src/nsSVGOuterSVGFrame.h | 101 +++++++++++++- layout/svg/base/src/nsSVGUtils.cpp | 1 - 8 files changed, 325 insertions(+), 58 deletions(-) diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index 4824a948b59..3205222646a 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -1750,6 +1750,7 @@ GK_ATOM(svgLinearGradientFrame, "SVGLinearGradientFrame") GK_ATOM(svgMarkerFrame, "SVGMarkerFrame") GK_ATOM(svgMaskFrame, "SVGMaskFrame") GK_ATOM(svgOuterSVGFrame, "SVGOuterSVGFrame") +GK_ATOM(svgOuterSVGAnonChildFrame, "SVGOuterSVGAnonChildFrame") GK_ATOM(svgPathGeometryFrame, "SVGPathGeometryFrame") GK_ATOM(svgPatternFrame, "SVGPatternFrame") GK_ATOM(svgRadialGradientFrame, "SVGRadialGradientFrame") diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 5afd6d79cb5..cbfb8b356ec 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -139,6 +139,8 @@ NS_NewHTMLVideoFrame (nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* +NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); +nsIFrame* NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewSVGPathGeometryFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); @@ -2407,25 +2409,30 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle #endif if (aDocElement->IsSVG()) { if (aDocElement->Tag() == nsGkAtoms::svg) { - contentFrame = NS_NewSVGOuterSVGFrame(mPresShell, styleContext); - if (NS_UNLIKELY(!contentFrame)) { - return NS_ERROR_OUT_OF_MEMORY; - } - InitAndRestoreFrame(state, aDocElement, - state.GetGeometricParent(display, - mDocElementContainingBlock), - nsnull, contentFrame); + // We're going to call the right function ourselves, so no need to give a + // function to this FrameConstructionData. + + // XXXbz on the other hand, if we converted this whole function to + // FrameConstructionData/Item, then we'd need the right function + // here... but would probably be able to get away with less code in this + // function in general. + // Use a null PendingBinding, since our binding is not in fact pending. + static const FrameConstructionData rootSVGData = FCDATA_DECL(0, nsnull); + nsRefPtr extraRef(styleContext); + FrameConstructionItem item(&rootSVGData, aDocElement, + aDocElement->Tag(), kNameSpaceID_SVG, + nsnull, extraRef.forget(), true); - // AddChild takes care of transforming the frame tree for fixed-pos - // or abs-pos situations nsFrameItems frameItems; - rv = state.AddChild(contentFrame, frameItems, aDocElement, - styleContext, mDocElementContainingBlock); - if (NS_FAILED(rv) || frameItems.IsEmpty()) { + rv = ConstructOuterSVG(state, item, mDocElementContainingBlock, + styleContext->GetStyleDisplay(), + frameItems, &contentFrame); + if (NS_FAILED(rv)) return rv; - } + if (!contentFrame || frameItems.IsEmpty()) + return NS_ERROR_FAILURE; *aNewFrame = frameItems.FirstChild(); - processChildren = true; + NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames"); } else { return NS_ERROR_FAILURE; } @@ -2498,8 +2505,9 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle // Still need to process the child content nsFrameItems childItems; - NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame), - "Only XUL and SVG frames should reach here"); + NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame) && + !contentFrame->IsFrameOfType(nsIFrame::eSVG), + "Only XUL frames should reach here"); // Use a null PendingBinding, since our binding is not in fact pending. ProcessChildren(state, aDocElement, styleContext, contentFrame, true, childItems, false, nsnull); @@ -4702,6 +4710,82 @@ nsCSSFrameConstructor::FindMathMLData(Element* aElement, ArrayLength(sMathMLData)); } + +// Construct an nsSVGOuterSVGFrame, the anonymous child that wraps its real +// children, and its descendant frames. +nsresult +nsCSSFrameConstructor::ConstructOuterSVG(nsFrameConstructorState& aState, + FrameConstructionItem& aItem, + nsIFrame* aParentFrame, + const nsStyleDisplay* aDisplay, + nsFrameItems& aFrameItems, + nsIFrame** aNewFrame) +{ + nsIContent* const content = aItem.mContent; + nsStyleContext* const styleContext = aItem.mStyleContext; + + nsresult rv = NS_OK; + + // Create the nsSVGOuterSVGFrame: + nsIFrame* newFrame = NS_NewSVGOuterSVGFrame(mPresShell, styleContext); + + nsIFrame* geometricParent = + aState.GetGeometricParent(styleContext->GetStyleDisplay(), + aParentFrame); + + InitAndRestoreFrame(aState, content, geometricParent, nsnull, newFrame); + + // Create the pseudo SC for the anonymous wrapper child as a child of the SC: + nsRefPtr scForAnon; + scForAnon = mPresShell->StyleSet()-> + ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozSVGOuterSVGAnonChild, + styleContext); + + // Create the anonymous inner wrapper frame + nsIFrame* innerFrame = NS_NewSVGOuterSVGAnonChildFrame(mPresShell, scForAnon); + + if (!innerFrame) { + newFrame->Destroy(); + return NS_ERROR_OUT_OF_MEMORY; + } + + InitAndRestoreFrame(aState, content, newFrame, nsnull, innerFrame); + + // Put the newly created frames into the right child list + SetInitialSingleChild(newFrame, innerFrame); + + rv = aState.AddChild(newFrame, aFrameItems, content, styleContext, + aParentFrame); + if (NS_FAILED(rv)) { + return rv; + } + + if (!mRootElementFrame) { + // The frame we're constructing will be the root element frame. + // Set mRootElementFrame before processing children. + mRootElementFrame = newFrame; + } + + nsFrameItems childItems; + + // Process children + if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) { + rv = ConstructFramesFromItemList(aState, aItem.mChildItems, + innerFrame, childItems); + } else { + rv = ProcessChildren(aState, content, styleContext, innerFrame, + true, childItems, false, aItem.mPendingBinding); + } + // XXXbz what about cleaning up? + if (NS_FAILED(rv)) return rv; + + // Set the inner wrapper frame's initial primary list + innerFrame->SetInitialChildList(kPrincipalList, childItems); + + *aNewFrame = newFrame; + return rv; +} + // Only outer elements can be floated or positioned. All other SVG // should be in-flow. #define SIMPLE_SVG_FCDATA(_func) \ @@ -4789,8 +4873,7 @@ nsCSSFrameConstructor::FindSVGData(Element* aElement, // and do the PassesConditionalProcessingTests call in // nsSVGOuterSVGFrame::Init. static const FrameConstructionData sOuterSVGData = - FCDATA_DECL(FCDATA_SKIP_ABSPOS_PUSH | FCDATA_DISALLOW_GENERATED_CONTENT, - NS_NewSVGOuterSVGFrame); + FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructOuterSVG); return &sOuterSVGData; } diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h index 966fb750613..75292fce24e 100644 --- a/layout/base/nsCSSFrameConstructor.h +++ b/layout/base/nsCSSFrameConstructor.h @@ -1351,6 +1351,18 @@ private: nsStyleContext* aStyleContext); // SVG - rods + /** + * Construct an nsSVGOuterSVGFrame, the anonymous child that wraps its real + * children, and its descendant frames. This is the FrameConstructionData + * callback used for the job. + */ + nsresult ConstructOuterSVG(nsFrameConstructorState& aState, + FrameConstructionItem& aItem, + nsIFrame* aParentFrame, + const nsStyleDisplay* aDisplay, + nsFrameItems& aFrameItems, + nsIFrame** aNewFrame); + static const FrameConstructionData* FindSVGData(Element* aElement, nsIAtom* aTag, PRInt32 aNameSpaceID, diff --git a/layout/generic/nsFrameIdList.h b/layout/generic/nsFrameIdList.h index f37812b3b1d..11e7658b862 100644 --- a/layout/generic/nsFrameIdList.h +++ b/layout/generic/nsFrameIdList.h @@ -147,6 +147,7 @@ FRAME_ID(nsSVGLinearGradientFrame) FRAME_ID(nsSVGMarkerFrame) FRAME_ID(nsSVGMaskFrame) FRAME_ID(nsSVGOuterSVGFrame) +FRAME_ID(nsSVGOuterSVGAnonChildFrame) FRAME_ID(nsSVGPaintServerFrame) FRAME_ID(nsSVGPathGeometryFrame) FRAME_ID(nsSVGPatternFrame) diff --git a/layout/style/nsCSSAnonBoxList.h b/layout/style/nsCSSAnonBoxList.h index 8ac6c201440..e6883edbe01 100644 --- a/layout/style/nsCSSAnonBoxList.h +++ b/layout/style/nsCSSAnonBoxList.h @@ -81,4 +81,5 @@ CSS_ANON_BOX(moztreeprogressmeter, ":-moz-tree-progressmeter") CSS_ANON_BOX(moztreedropfeedback, ":-moz-tree-drop-feedback") #endif +CSS_ANON_BOX(mozSVGOuterSVGAnonChild, ":-moz-svg-outer-svg-anon-child") CSS_ANON_BOX(mozSVGForeignContent, ":-moz-svg-foreign-content") diff --git a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp index 8ec30f728a9..799b1af8c01 100644 --- a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp +++ b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp @@ -391,29 +391,32 @@ nsSVGOuterSVGFrame::Reflow(nsPresContext* aPresContext, NotifyViewportOrTransformChanged(changeBits); } - // Now that we've marked the necessary children as dirty, call - // UpdateBounds() on them: + nsSVGOuterSVGAnonChildFrame *anonKid = + static_cast(GetFirstPrincipalChild()); - mCallingUpdateBounds = true; + if (!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) { + // Now that we've marked the necessary children as dirty, call + // UpdateBounds() on them: - if (!(mState & NS_STATE_SVG_NONDISPLAY_CHILD)) { - nsIFrame* kid = mFrames.FirstChild(); - while (kid) { - nsISVGChildFrame* SVGFrame = do_QueryFrame(kid); - if (SVGFrame && !(kid->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) { - SVGFrame->UpdateBounds(); - } - kid = kid->GetNextSibling(); - } + mCallingUpdateBounds = true; + + // Update the mRects and visual overflow rects of all our descendants, + // including our anonymous wrapper kid: + anonKid->UpdateBounds(); + NS_ABORT_IF_FALSE(!anonKid->GetNextSibling(), + "We should have one anonymous child frame wrapping our real children"); + + mCallingUpdateBounds = false; } - mCallingUpdateBounds = false; - // Make sure we scroll if we're too big: // XXX Use the bounding box of our descendants? (See bug 353460 comment 14.) aDesiredSize.SetOverflowAreasToDesiredBounds(); FinishAndStoreOverflow(&aDesiredSize); + // Set our anonymous kid's offset from our border box: + anonKid->SetPosition(GetContentRectRelativeToSelf().TopLeft()); + NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsSVGOuterSVGFrame::Reflow: size=%d,%d", aDesiredSize.width, aDesiredSize.height)); @@ -471,9 +474,12 @@ nsDisplayOuterSVG::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, nsPoint rectCenter(rectAtOrigin.x + rectAtOrigin.width / 2, rectAtOrigin.y + rectAtOrigin.height / 2); + nsSVGOuterSVGAnonChildFrame *anonKid = + static_cast( + outerSVGFrame->GetFirstPrincipalChild()); nsIFrame* frame = nsSVGUtils::HitTestChildren( - outerSVGFrame, rectCenter + outerSVGFrame->GetPosition() - - outerSVGFrame->GetContentRect().TopLeft()); + anonKid, rectCenter + outerSVGFrame->GetPosition() - + outerSVGFrame->GetContentRect().TopLeft()); if (frame) { aOutFrames->AppendElement(frame); } @@ -546,8 +552,8 @@ nsSVGOuterSVGFrame::AttributeChanged(PRInt32 aNameSpaceID, // make sure our cached transform matrix gets (lazily) updated mCanvasTM = nsnull; - nsSVGUtils::NotifyChildrenOfSVGChange( - this, aAttribute == nsGkAtoms::viewBox ? + nsSVGUtils::NotifyChildrenOfSVGChange(GetFirstPrincipalChild(), + aAttribute == nsGkAtoms::viewBox ? TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED : TRANSFORM_CHANGED); static_cast(mContent)->ChildrenOnlyTransformChanged(); @@ -676,7 +682,38 @@ nsSVGOuterSVGFrame::NotifyViewportOrTransformChanged(PRUint32 aFlags) } } - nsSVGUtils::NotifyChildrenOfSVGChange(this, aFlags); + nsSVGUtils::NotifyChildrenOfSVGChange(GetFirstPrincipalChild(), aFlags); +} + +//---------------------------------------------------------------------- +// nsISVGChildFrame methods: + +NS_IMETHODIMP +nsSVGOuterSVGFrame::PaintSVG(nsRenderingContext* aContext, + const nsIntRect *aDirtyRect) +{ + NS_ASSERTION(GetFirstPrincipalChild()->GetType() == + nsGkAtoms::svgOuterSVGAnonChildFrame && + !GetFirstPrincipalChild()->GetNextSibling(), + "We should have a single, anonymous, child"); + nsSVGOuterSVGAnonChildFrame *anonKid = + static_cast(GetFirstPrincipalChild()); + return anonKid->PaintSVG(aContext, aDirtyRect); +} + +SVGBBox +nsSVGOuterSVGFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, + PRUint32 aFlags) +{ + NS_ASSERTION(GetFirstPrincipalChild()->GetType() == + nsGkAtoms::svgOuterSVGAnonChildFrame && + !GetFirstPrincipalChild()->GetNextSibling(), + "We should have a single, anonymous, child"); + // We must defer to our child so that we don't include our + // content->PrependLocalTransformsTo() transforms. + nsSVGOuterSVGAnonChildFrame *anonKid = + static_cast(GetFirstPrincipalChild()); + return anonKid->GetBBoxContribution(aToBBoxUserspace, aFlags); } //---------------------------------------------------------------------- @@ -705,24 +742,6 @@ nsSVGOuterSVGFrame::GetCanvasTM(PRUint32 aFor) return *mCanvasTM; } -bool -nsSVGOuterSVGFrame::HasChildrenOnlyTransform(gfxMatrix *aTransform) const -{ - nsSVGSVGElement *content = static_cast(mContent); - - bool hasTransform = content->HasChildrenOnlyTransform(); - - if (hasTransform && aTransform) { - // Outer- doesn't use x/y, so we can pass eChildToUserSpace here. - gfxMatrix identity; - *aTransform = - content->PrependLocalTransformsTo(identity, - nsSVGElement::eChildToUserSpace); - } - - return hasTransform; -} - //---------------------------------------------------------------------- // Implementation helpers @@ -777,3 +796,55 @@ nsSVGOuterSVGFrame::VerticalScrollbarNotNeeded() const mLengthAttributes[nsSVGSVGElement::HEIGHT]; return height.IsPercentage() && height.GetBaseValInSpecifiedUnits() <= 100; } + + +//---------------------------------------------------------------------- +// Implementation of nsSVGOuterSVGAnonChildFrame + +nsIFrame* +NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell, + nsStyleContext* aContext) +{ + return new (aPresShell) nsSVGOuterSVGAnonChildFrame(aContext); +} + +NS_IMPL_FRAMEARENA_HELPERS(nsSVGOuterSVGAnonChildFrame) + +#ifdef DEBUG +NS_IMETHODIMP +nsSVGOuterSVGAnonChildFrame::Init(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame* aPrevInFlow) +{ + NS_ABORT_IF_FALSE(aParent->GetType() == nsGkAtoms::svgOuterSVGFrame, + "Unexpected parent"); + return nsSVGOuterSVGAnonChildFrameBase::Init(aContent, aParent, aPrevInFlow); +} +#endif + +nsIAtom * +nsSVGOuterSVGAnonChildFrame::GetType() const +{ + return nsGkAtoms::svgOuterSVGAnonChildFrame; +} + +bool +nsSVGOuterSVGAnonChildFrame::HasChildrenOnlyTransform(gfxMatrix *aTransform) const +{ + // We must claim our nsSVGOuterSVGFrame's children-only transforms as our own + // so that the children we are used to wrap are transformed properly. + + nsSVGSVGElement *content = static_cast(mContent); + + bool hasTransform = content->HasChildrenOnlyTransform(); + + if (hasTransform && aTransform) { + // Outer- doesn't use x/y, so we can pass eChildToUserSpace here. + gfxMatrix identity; + *aTransform = + content->PrependLocalTransformsTo(identity, + nsSVGElement::eChildToUserSpace); + } + + return hasTransform; +} diff --git a/layout/svg/base/src/nsSVGOuterSVGFrame.h b/layout/svg/base/src/nsSVGOuterSVGFrame.h index 56dce8480c8..55a51771009 100644 --- a/layout/svg/base/src/nsSVGOuterSVGFrame.h +++ b/layout/svg/base/src/nsSVGOuterSVGFrame.h @@ -76,6 +76,15 @@ public: nsIAtom* aAttribute, PRInt32 aModType); + virtual nsIFrame* GetContentInsertionFrame() { + // Any children must be added to our single anonymous inner frame kid. + NS_ABORT_IF_FALSE(GetFirstPrincipalChild() && + GetFirstPrincipalChild()->GetType() == + nsGkAtoms::svgOuterSVGAnonChildFrame, + "Where is our anonymous child?"); + return GetFirstPrincipalChild()->GetContentInsertionFrame(); + } + virtual bool IsSVGTransformed(gfxMatrix *aOwnTransform, gfxMatrix *aFromParentTransform) const { // Outer- can transform its children with viewBox, currentScale and @@ -86,10 +95,23 @@ public: // nsISVGSVGFrame interface: virtual void NotifyViewportOrTransformChanged(PRUint32 aFlags); + // nsISVGChildFrame methods: + NS_IMETHOD PaintSVG(nsRenderingContext* aContext, + const nsIntRect *aDirtyRect); + + virtual SVGBBox GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, + PRUint32 aFlags); + // nsSVGContainerFrame methods: virtual gfxMatrix GetCanvasTM(PRUint32 aFor); - virtual bool HasChildrenOnlyTransform(gfxMatrix *aTransform) const; + virtual bool HasChildrenOnlyTransform(gfxMatrix *aTransform) const { + // Our anonymous wrapper child must claim our children-only transforms as + // its own so that our real children (the frames it wraps) are transformed + // by them, and we must pretend we don't have any children-only transforms + // so that our anonymous child is _not_ transformed by them. + return false; + } /** * Return true only if the height is unspecified (defaulting to 100%) or else @@ -124,4 +146,81 @@ protected: bool mIsRootContent; }; +//////////////////////////////////////////////////////////////////////// +// nsSVGOuterSVGAnonChildFrame class + +typedef nsSVGDisplayContainerFrame nsSVGOuterSVGAnonChildFrameBase; + +/** + * nsSVGOuterSVGFrames have a single direct child that is an instance of this + * class, and which is used to wrap their real child frames. Such anonymous + * wrapper frames created from this class exist because SVG frames need their + * GetPosition() offset to be their offset relative to "user space" (in app + * units) so that they can play nicely with nsDisplayTransform. This is fine + * for all SVG frames except for direct children of an nsSVGOuterSVGFrame, + * since an nsSVGOuterSVGFrame can have CSS border and padding (unlike other + * SVG frames). The direct children can't include the offsets due to any such + * border/padding in their mRects since that would break nsDisplayTransform, + * but not including these offsets would break other parts of the Mozilla code + * that assume a frame's mRect contains its border-box-to-parent-border-box + * offset, in particular nsIFrame::GetOffsetTo and the functions that depend on + * it. Wrapping an nsSVGOuterSVGFrame's children in an instance of this class + * with its GetPosition() set to its nsSVGOuterSVGFrame's border/padding offset + * keeps both nsDisplayTransform and nsIFrame::GetOffsetTo happy. + * + * The reason that this class inherit from nsSVGDisplayContainerFrame rather + * than simply from nsContainerFrame is so that we can avoid having special + * handling for these inner wrappers in multiple parts of the SVG code. For + * example, the implementations of IsSVGTransformed and GetCanvasTM assume + * nsSVGContainerFrame instances all the way up to the nsSVGOuterSVGFrame. + */ +class nsSVGOuterSVGAnonChildFrame + : public nsSVGOuterSVGAnonChildFrameBase +{ + friend nsIFrame* + NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell, + nsStyleContext* aContext); + + nsSVGOuterSVGAnonChildFrame(nsStyleContext* aContext) + : nsSVGOuterSVGAnonChildFrameBase(aContext) + {} + +public: + NS_DECL_FRAMEARENA_HELPERS + +#ifdef DEBUG + NS_IMETHOD Init(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame* aPrevInFlow); + + NS_IMETHOD GetFrameName(nsAString& aResult) const { + return MakeFrameName(NS_LITERAL_STRING("SVGOuterSVGAnonChild"), aResult); + } +#endif + + /** + * Get the "type" of the frame + * + * @see nsGkAtoms::svgOuterSVGAnonChildFrame + */ + virtual nsIAtom* GetType() const; + + virtual bool IsSVGTransformed(gfxMatrix *aOwnTransform, + gfxMatrix *aFromParentTransform) const { + // Outer- can transform its children with viewBox, currentScale and + // currentTranslate, but it itself is not transformed by _SVG_ transforms. + return false; + } + + // nsSVGContainerFrame methods: + virtual gfxMatrix GetCanvasTM(PRUint32 aFor) { + // GetCanvasTM returns the transform from an SVG frame to the frame's + // nsSVGOuterSVGFrame's content box, so we do not include any x/y offset + // set on us for any CSS border or padding on our nsSVGOuterSVGFrame. + return static_cast(mParent)->GetCanvasTM(aFor); + } + + virtual bool HasChildrenOnlyTransform(gfxMatrix *aTransform) const; +}; + #endif diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index 6432519c829..983aad8a702 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -703,7 +703,6 @@ nsSVGUtils::InvalidateBounds(nsIFrame *aFrame, bool aDuringUpdate, NS_ASSERTION(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG, "SVG frames must always have an nsSVGOuterSVGFrame ancestor!"); - invalidArea.MoveBy(aFrame->GetContentRect().TopLeft() - aFrame->GetPosition()); static_cast(aFrame)->InvalidateWithFlags(invalidArea, aFlags);