mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 769742 - Account for nsSVGOuterSVGFrames' border/padding offset by giving nsSVGOuterSVGFrame an anonymous child to wrap its real children. r=roc.
This commit is contained in:
parent
09ff7e2e99
commit
f410406b60
@ -1750,6 +1750,7 @@ GK_ATOM(svgLinearGradientFrame, "SVGLinearGradientFrame")
|
|||||||
GK_ATOM(svgMarkerFrame, "SVGMarkerFrame")
|
GK_ATOM(svgMarkerFrame, "SVGMarkerFrame")
|
||||||
GK_ATOM(svgMaskFrame, "SVGMaskFrame")
|
GK_ATOM(svgMaskFrame, "SVGMaskFrame")
|
||||||
GK_ATOM(svgOuterSVGFrame, "SVGOuterSVGFrame")
|
GK_ATOM(svgOuterSVGFrame, "SVGOuterSVGFrame")
|
||||||
|
GK_ATOM(svgOuterSVGAnonChildFrame, "SVGOuterSVGAnonChildFrame")
|
||||||
GK_ATOM(svgPathGeometryFrame, "SVGPathGeometryFrame")
|
GK_ATOM(svgPathGeometryFrame, "SVGPathGeometryFrame")
|
||||||
GK_ATOM(svgPatternFrame, "SVGPatternFrame")
|
GK_ATOM(svgPatternFrame, "SVGPatternFrame")
|
||||||
GK_ATOM(svgRadialGradientFrame, "SVGRadialGradientFrame")
|
GK_ATOM(svgRadialGradientFrame, "SVGRadialGradientFrame")
|
||||||
|
@ -139,6 +139,8 @@ NS_NewHTMLVideoFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
|
|||||||
nsIFrame*
|
nsIFrame*
|
||||||
NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
|
NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
|
||||||
nsIFrame*
|
nsIFrame*
|
||||||
|
NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
|
||||||
|
nsIFrame*
|
||||||
NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
|
NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
|
||||||
nsIFrame*
|
nsIFrame*
|
||||||
NS_NewSVGPathGeometryFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
|
NS_NewSVGPathGeometryFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
|
||||||
@ -2407,25 +2409,30 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
|
|||||||
#endif
|
#endif
|
||||||
if (aDocElement->IsSVG()) {
|
if (aDocElement->IsSVG()) {
|
||||||
if (aDocElement->Tag() == nsGkAtoms::svg) {
|
if (aDocElement->Tag() == nsGkAtoms::svg) {
|
||||||
contentFrame = NS_NewSVGOuterSVGFrame(mPresShell, styleContext);
|
// We're going to call the right function ourselves, so no need to give a
|
||||||
if (NS_UNLIKELY(!contentFrame)) {
|
// function to this FrameConstructionData.
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
// XXXbz on the other hand, if we converted this whole function to
|
||||||
InitAndRestoreFrame(state, aDocElement,
|
// FrameConstructionData/Item, then we'd need the right function
|
||||||
state.GetGeometricParent(display,
|
// here... but would probably be able to get away with less code in this
|
||||||
mDocElementContainingBlock),
|
// function in general.
|
||||||
nsnull, contentFrame);
|
// Use a null PendingBinding, since our binding is not in fact pending.
|
||||||
|
static const FrameConstructionData rootSVGData = FCDATA_DECL(0, nsnull);
|
||||||
|
nsRefPtr<nsStyleContext> 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;
|
nsFrameItems frameItems;
|
||||||
rv = state.AddChild(contentFrame, frameItems, aDocElement,
|
rv = ConstructOuterSVG(state, item, mDocElementContainingBlock,
|
||||||
styleContext, mDocElementContainingBlock);
|
styleContext->GetStyleDisplay(),
|
||||||
if (NS_FAILED(rv) || frameItems.IsEmpty()) {
|
frameItems, &contentFrame);
|
||||||
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
}
|
if (!contentFrame || frameItems.IsEmpty())
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
*aNewFrame = frameItems.FirstChild();
|
*aNewFrame = frameItems.FirstChild();
|
||||||
processChildren = true;
|
NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
|
||||||
} else {
|
} else {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
@ -2498,8 +2505,9 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
|
|||||||
// Still need to process the child content
|
// Still need to process the child content
|
||||||
nsFrameItems childItems;
|
nsFrameItems childItems;
|
||||||
|
|
||||||
NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame),
|
NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame) &&
|
||||||
"Only XUL and SVG frames should reach here");
|
!contentFrame->IsFrameOfType(nsIFrame::eSVG),
|
||||||
|
"Only XUL frames should reach here");
|
||||||
// Use a null PendingBinding, since our binding is not in fact pending.
|
// Use a null PendingBinding, since our binding is not in fact pending.
|
||||||
ProcessChildren(state, aDocElement, styleContext, contentFrame, true,
|
ProcessChildren(state, aDocElement, styleContext, contentFrame, true,
|
||||||
childItems, false, nsnull);
|
childItems, false, nsnull);
|
||||||
@ -4702,6 +4710,82 @@ nsCSSFrameConstructor::FindMathMLData(Element* aElement,
|
|||||||
ArrayLength(sMathMLData));
|
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<nsStyleContext> 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 <svg> elements can be floated or positioned. All other SVG
|
// Only outer <svg> elements can be floated or positioned. All other SVG
|
||||||
// should be in-flow.
|
// should be in-flow.
|
||||||
#define SIMPLE_SVG_FCDATA(_func) \
|
#define SIMPLE_SVG_FCDATA(_func) \
|
||||||
@ -4789,8 +4873,7 @@ nsCSSFrameConstructor::FindSVGData(Element* aElement,
|
|||||||
// and do the PassesConditionalProcessingTests call in
|
// and do the PassesConditionalProcessingTests call in
|
||||||
// nsSVGOuterSVGFrame::Init.
|
// nsSVGOuterSVGFrame::Init.
|
||||||
static const FrameConstructionData sOuterSVGData =
|
static const FrameConstructionData sOuterSVGData =
|
||||||
FCDATA_DECL(FCDATA_SKIP_ABSPOS_PUSH | FCDATA_DISALLOW_GENERATED_CONTENT,
|
FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructOuterSVG);
|
||||||
NS_NewSVGOuterSVGFrame);
|
|
||||||
return &sOuterSVGData;
|
return &sOuterSVGData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1351,6 +1351,18 @@ private:
|
|||||||
nsStyleContext* aStyleContext);
|
nsStyleContext* aStyleContext);
|
||||||
|
|
||||||
// SVG - rods
|
// 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,
|
static const FrameConstructionData* FindSVGData(Element* aElement,
|
||||||
nsIAtom* aTag,
|
nsIAtom* aTag,
|
||||||
PRInt32 aNameSpaceID,
|
PRInt32 aNameSpaceID,
|
||||||
|
@ -147,6 +147,7 @@ FRAME_ID(nsSVGLinearGradientFrame)
|
|||||||
FRAME_ID(nsSVGMarkerFrame)
|
FRAME_ID(nsSVGMarkerFrame)
|
||||||
FRAME_ID(nsSVGMaskFrame)
|
FRAME_ID(nsSVGMaskFrame)
|
||||||
FRAME_ID(nsSVGOuterSVGFrame)
|
FRAME_ID(nsSVGOuterSVGFrame)
|
||||||
|
FRAME_ID(nsSVGOuterSVGAnonChildFrame)
|
||||||
FRAME_ID(nsSVGPaintServerFrame)
|
FRAME_ID(nsSVGPaintServerFrame)
|
||||||
FRAME_ID(nsSVGPathGeometryFrame)
|
FRAME_ID(nsSVGPathGeometryFrame)
|
||||||
FRAME_ID(nsSVGPatternFrame)
|
FRAME_ID(nsSVGPatternFrame)
|
||||||
|
@ -81,4 +81,5 @@ CSS_ANON_BOX(moztreeprogressmeter, ":-moz-tree-progressmeter")
|
|||||||
CSS_ANON_BOX(moztreedropfeedback, ":-moz-tree-drop-feedback")
|
CSS_ANON_BOX(moztreedropfeedback, ":-moz-tree-drop-feedback")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
CSS_ANON_BOX(mozSVGOuterSVGAnonChild, ":-moz-svg-outer-svg-anon-child")
|
||||||
CSS_ANON_BOX(mozSVGForeignContent, ":-moz-svg-foreign-content")
|
CSS_ANON_BOX(mozSVGForeignContent, ":-moz-svg-foreign-content")
|
||||||
|
@ -391,29 +391,32 @@ nsSVGOuterSVGFrame::Reflow(nsPresContext* aPresContext,
|
|||||||
NotifyViewportOrTransformChanged(changeBits);
|
NotifyViewportOrTransformChanged(changeBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsSVGOuterSVGAnonChildFrame *anonKid =
|
||||||
|
static_cast<nsSVGOuterSVGAnonChildFrame*>(GetFirstPrincipalChild());
|
||||||
|
|
||||||
|
if (!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
|
||||||
// Now that we've marked the necessary children as dirty, call
|
// Now that we've marked the necessary children as dirty, call
|
||||||
// UpdateBounds() on them:
|
// UpdateBounds() on them:
|
||||||
|
|
||||||
mCallingUpdateBounds = true;
|
mCallingUpdateBounds = true;
|
||||||
|
|
||||||
if (!(mState & NS_STATE_SVG_NONDISPLAY_CHILD)) {
|
// Update the mRects and visual overflow rects of all our descendants,
|
||||||
nsIFrame* kid = mFrames.FirstChild();
|
// including our anonymous wrapper kid:
|
||||||
while (kid) {
|
anonKid->UpdateBounds();
|
||||||
nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
|
NS_ABORT_IF_FALSE(!anonKid->GetNextSibling(),
|
||||||
if (SVGFrame && !(kid->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
|
"We should have one anonymous child frame wrapping our real children");
|
||||||
SVGFrame->UpdateBounds();
|
|
||||||
}
|
|
||||||
kid = kid->GetNextSibling();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mCallingUpdateBounds = false;
|
mCallingUpdateBounds = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure we scroll if we're too big:
|
// Make sure we scroll if we're too big:
|
||||||
// XXX Use the bounding box of our descendants? (See bug 353460 comment 14.)
|
// XXX Use the bounding box of our descendants? (See bug 353460 comment 14.)
|
||||||
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||||
FinishAndStoreOverflow(&aDesiredSize);
|
FinishAndStoreOverflow(&aDesiredSize);
|
||||||
|
|
||||||
|
// Set our anonymous kid's offset from our border box:
|
||||||
|
anonKid->SetPosition(GetContentRectRelativeToSelf().TopLeft());
|
||||||
|
|
||||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||||
("exit nsSVGOuterSVGFrame::Reflow: size=%d,%d",
|
("exit nsSVGOuterSVGFrame::Reflow: size=%d,%d",
|
||||||
aDesiredSize.width, aDesiredSize.height));
|
aDesiredSize.width, aDesiredSize.height));
|
||||||
@ -471,8 +474,11 @@ nsDisplayOuterSVG::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
|||||||
nsPoint rectCenter(rectAtOrigin.x + rectAtOrigin.width / 2,
|
nsPoint rectCenter(rectAtOrigin.x + rectAtOrigin.width / 2,
|
||||||
rectAtOrigin.y + rectAtOrigin.height / 2);
|
rectAtOrigin.y + rectAtOrigin.height / 2);
|
||||||
|
|
||||||
|
nsSVGOuterSVGAnonChildFrame *anonKid =
|
||||||
|
static_cast<nsSVGOuterSVGAnonChildFrame*>(
|
||||||
|
outerSVGFrame->GetFirstPrincipalChild());
|
||||||
nsIFrame* frame = nsSVGUtils::HitTestChildren(
|
nsIFrame* frame = nsSVGUtils::HitTestChildren(
|
||||||
outerSVGFrame, rectCenter + outerSVGFrame->GetPosition() -
|
anonKid, rectCenter + outerSVGFrame->GetPosition() -
|
||||||
outerSVGFrame->GetContentRect().TopLeft());
|
outerSVGFrame->GetContentRect().TopLeft());
|
||||||
if (frame) {
|
if (frame) {
|
||||||
aOutFrames->AppendElement(frame);
|
aOutFrames->AppendElement(frame);
|
||||||
@ -546,8 +552,8 @@ nsSVGOuterSVGFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||||||
// make sure our cached transform matrix gets (lazily) updated
|
// make sure our cached transform matrix gets (lazily) updated
|
||||||
mCanvasTM = nsnull;
|
mCanvasTM = nsnull;
|
||||||
|
|
||||||
nsSVGUtils::NotifyChildrenOfSVGChange(
|
nsSVGUtils::NotifyChildrenOfSVGChange(GetFirstPrincipalChild(),
|
||||||
this, aAttribute == nsGkAtoms::viewBox ?
|
aAttribute == nsGkAtoms::viewBox ?
|
||||||
TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED : TRANSFORM_CHANGED);
|
TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED : TRANSFORM_CHANGED);
|
||||||
|
|
||||||
static_cast<nsSVGSVGElement*>(mContent)->ChildrenOnlyTransformChanged();
|
static_cast<nsSVGSVGElement*>(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<nsSVGOuterSVGAnonChildFrame*>(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<nsSVGOuterSVGAnonChildFrame*>(GetFirstPrincipalChild());
|
||||||
|
return anonKid->GetBBoxContribution(aToBBoxUserspace, aFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@ -705,24 +742,6 @@ nsSVGOuterSVGFrame::GetCanvasTM(PRUint32 aFor)
|
|||||||
return *mCanvasTM;
|
return *mCanvasTM;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
nsSVGOuterSVGFrame::HasChildrenOnlyTransform(gfxMatrix *aTransform) const
|
|
||||||
{
|
|
||||||
nsSVGSVGElement *content = static_cast<nsSVGSVGElement*>(mContent);
|
|
||||||
|
|
||||||
bool hasTransform = content->HasChildrenOnlyTransform();
|
|
||||||
|
|
||||||
if (hasTransform && aTransform) {
|
|
||||||
// Outer-<svg> doesn't use x/y, so we can pass eChildToUserSpace here.
|
|
||||||
gfxMatrix identity;
|
|
||||||
*aTransform =
|
|
||||||
content->PrependLocalTransformsTo(identity,
|
|
||||||
nsSVGElement::eChildToUserSpace);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hasTransform;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Implementation helpers
|
// Implementation helpers
|
||||||
|
|
||||||
@ -777,3 +796,55 @@ nsSVGOuterSVGFrame::VerticalScrollbarNotNeeded() const
|
|||||||
mLengthAttributes[nsSVGSVGElement::HEIGHT];
|
mLengthAttributes[nsSVGSVGElement::HEIGHT];
|
||||||
return height.IsPercentage() && height.GetBaseValInSpecifiedUnits() <= 100;
|
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<nsSVGSVGElement*>(mContent);
|
||||||
|
|
||||||
|
bool hasTransform = content->HasChildrenOnlyTransform();
|
||||||
|
|
||||||
|
if (hasTransform && aTransform) {
|
||||||
|
// Outer-<svg> doesn't use x/y, so we can pass eChildToUserSpace here.
|
||||||
|
gfxMatrix identity;
|
||||||
|
*aTransform =
|
||||||
|
content->PrependLocalTransformsTo(identity,
|
||||||
|
nsSVGElement::eChildToUserSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasTransform;
|
||||||
|
}
|
||||||
|
@ -76,6 +76,15 @@ public:
|
|||||||
nsIAtom* aAttribute,
|
nsIAtom* aAttribute,
|
||||||
PRInt32 aModType);
|
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,
|
virtual bool IsSVGTransformed(gfxMatrix *aOwnTransform,
|
||||||
gfxMatrix *aFromParentTransform) const {
|
gfxMatrix *aFromParentTransform) const {
|
||||||
// Outer-<svg> can transform its children with viewBox, currentScale and
|
// Outer-<svg> can transform its children with viewBox, currentScale and
|
||||||
@ -86,10 +95,23 @@ public:
|
|||||||
// nsISVGSVGFrame interface:
|
// nsISVGSVGFrame interface:
|
||||||
virtual void NotifyViewportOrTransformChanged(PRUint32 aFlags);
|
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:
|
// nsSVGContainerFrame methods:
|
||||||
virtual gfxMatrix GetCanvasTM(PRUint32 aFor);
|
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
|
* Return true only if the height is unspecified (defaulting to 100%) or else
|
||||||
@ -124,4 +146,81 @@ protected:
|
|||||||
bool mIsRootContent;
|
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-<svg> 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<nsSVGOuterSVGFrame*>(mParent)->GetCanvasTM(aFor);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool HasChildrenOnlyTransform(gfxMatrix *aTransform) const;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -703,7 +703,6 @@ nsSVGUtils::InvalidateBounds(nsIFrame *aFrame, bool aDuringUpdate,
|
|||||||
|
|
||||||
NS_ASSERTION(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG,
|
NS_ASSERTION(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG,
|
||||||
"SVG frames must always have an nsSVGOuterSVGFrame ancestor!");
|
"SVG frames must always have an nsSVGOuterSVGFrame ancestor!");
|
||||||
invalidArea.MoveBy(aFrame->GetContentRect().TopLeft() - aFrame->GetPosition());
|
|
||||||
|
|
||||||
static_cast<nsSVGOuterSVGFrame*>(aFrame)->InvalidateWithFlags(invalidArea,
|
static_cast<nsSVGOuterSVGFrame*>(aFrame)->InvalidateWithFlags(invalidArea,
|
||||||
aFlags);
|
aFlags);
|
||||||
|
Loading…
Reference in New Issue
Block a user