From 76cd3244f46b7fb13576b7ef6dab1ca65b8eb4e5 Mon Sep 17 00:00:00 2001 From: violet Date: Thu, 21 Mar 2019 21:17:18 +0000 Subject: [PATCH] Bug 951904 - SVGTextFrame should always be reflowed even if it is inside a nonactive child of switch element r=longsonr SVGTextFrame is special, it should always be reflowed to get the correct metrics. Differential Revision: https://phabricator.services.mozilla.com/D22841 --HG-- extra : moz-landing-system : lando --- layout/svg/crashtests/951904-1.html | 34 +++++++++++++++++++ layout/svg/crashtests/crashtests.list | 1 + layout/svg/nsSVGSwitchFrame.cpp | 47 +++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 layout/svg/crashtests/951904-1.html diff --git a/layout/svg/crashtests/951904-1.html b/layout/svg/crashtests/951904-1.html new file mode 100644 index 000000000000..55cfa7f83664 --- /dev/null +++ b/layout/svg/crashtests/951904-1.html @@ -0,0 +1,34 @@ + + + + Bonjour + Hello + Hello + + + Lundi + + + + Au revoir + + + Mercredi + + + Goodbye + Goodbye + + + + + diff --git a/layout/svg/crashtests/crashtests.list b/layout/svg/crashtests/crashtests.list index 59e9b96f0f9a..12ca58329e29 100644 --- a/layout/svg/crashtests/crashtests.list +++ b/layout/svg/crashtests/crashtests.list @@ -182,6 +182,7 @@ load 898951-1.svg load 913990.html load 919371-1.xhtml load 950324-1.svg +load 951904-1.html load 952270-1.svg load 963086-1.svg load 974746-1.svg diff --git a/layout/svg/nsSVGSwitchFrame.cpp b/layout/svg/nsSVGSwitchFrame.cpp index de74ca8f3e84..a62a387da62b 100644 --- a/layout/svg/nsSVGSwitchFrame.cpp +++ b/layout/svg/nsSVGSwitchFrame.cpp @@ -10,6 +10,8 @@ #include "nsSVGGFrame.h" #include "mozilla/dom/SVGSwitchElement.h" #include "nsSVGUtils.h" +#include "SVGTextFrame.h" +#include "nsSVGContainerFrame.h" using namespace mozilla; using namespace mozilla::gfx; @@ -51,6 +53,8 @@ class nsSVGSwitchFrame final : public nsSVGGFrame { private: nsIFrame* GetActiveChildFrame(); + void ReflowAllSVGTextFramesInsideNonActiveChildren(nsIFrame* aActiveChild); + static void AlwaysReflowSVGTextFrameDoForOneKid(nsIFrame* aKid); }; //---------------------------------------------------------------------- @@ -135,6 +139,47 @@ nsIFrame* nsSVGSwitchFrame::GetFrameForPoint(const gfxPoint& aPoint) { return nullptr; } +void nsSVGSwitchFrame::AlwaysReflowSVGTextFrameDoForOneKid(nsIFrame* aKid) { + if (!NS_SUBTREE_DIRTY(aKid)) { + return; + } + + LayoutFrameType type = aKid->Type(); + if (type == LayoutFrameType::SVGText) { + MOZ_ASSERT(!aKid->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY), + "A non-display SVGTextFrame directly contained in a display " + "container?"); + static_cast(aKid)->ReflowSVG(); + } else if (aKid->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer) || + type == LayoutFrameType::SVGForeignObject || + !aKid->IsFrameOfType(nsIFrame::eSVG)) { + if (!aKid->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY)) { + for (nsIFrame* kid : aKid->PrincipalChildList()) { + AlwaysReflowSVGTextFrameDoForOneKid(kid); + } + } else { + // This child is in a nondisplay context, something like: + // + // ... + // + // + // We should not call ReflowSVG on it. + nsSVGContainerFrame::ReflowSVGNonDisplayText(aKid); + } + } +} + +void nsSVGSwitchFrame::ReflowAllSVGTextFramesInsideNonActiveChildren( + nsIFrame* aActiveChild) { + for (nsIFrame* kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) { + if (aActiveChild == kid) { + continue; + } + + AlwaysReflowSVGTextFrameDoForOneKid(kid); + } +} + void nsSVGSwitchFrame::ReflowSVG() { NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingReflowSVG(this), "This call is probably a wasteful mistake"); @@ -165,6 +210,8 @@ void nsSVGSwitchFrame::ReflowSVG() { nsOverflowAreas overflowRects; nsIFrame* child = GetActiveChildFrame(); + ReflowAllSVGTextFramesInsideNonActiveChildren(child); + nsSVGDisplayableFrame* svgChild = do_QueryFrame(child); if (svgChild) { MOZ_ASSERT(!(child->GetStateBits() & NS_FRAME_IS_NONDISPLAY),