Bug 873806 - Part 2: Make descendants of non-display nsSVGForeignObjectFrame also non-display. r=longsonr
authorCameron McCormack <cam@mcc.id.au>
Tue, 04 Jun 2013 00:15:29 +1000
changeset 145294 a4523b6a2e5f8c60a433039f52608883b8ba8431
parent 145293 8b8cd5ba2a1e419908f72f18fe69bdbef91a18d7
child 145295 0f19c792705d095694e0afbe1f1e55fca6a2b6af
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslongsonr
bugs873806
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 873806 - Part 2: Make descendants of non-display nsSVGForeignObjectFrame also non-display. r=longsonr
layout/svg/crashtests/873806-1.svg
layout/svg/crashtests/crashtests.list
layout/svg/nsSVGOuterSVGFrame.cpp
layout/svg/nsSVGTextFrame2.cpp
layout/svg/nsSVGUtils.cpp
layout/svg/nsSVGUtils.h
new file mode 100644
--- /dev/null
+++ b/layout/svg/crashtests/873806-1.svg
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+  <foreignObject requiredFeatures="fail">
+    <svg>
+      <text>a</text>
+    </svg>
+  </foreignObject>
+  <script>
+    document.querySelector("text").getBBox();
+  </script>
+</svg>
--- a/layout/svg/crashtests/crashtests.list
+++ b/layout/svg/crashtests/crashtests.list
@@ -158,9 +158,10 @@ load 842630-1.svg
 load 842909-1.svg
 load 843072-1.svg
 load 843917-1.svg
 load 847139-1.svg
 load 849688-1.svg
 load 849688-2.svg
 load 860378-1.svg
 load 868904-1.svg
+load 873806-1.svg
 load 877029-1.svg
--- a/layout/svg/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/nsSVGOuterSVGFrame.cpp
@@ -162,16 +162,29 @@ nsSVGOuterSVGFrame::Init(nsIContent* aCo
   // We don't create other SVG frames if PassesConditionalProcessingTests
   // returns false, but since we do create nsSVGOuterSVGFrame frames we
   // prevent them from painting by [ab]use NS_STATE_SVG_NONDISPLAY_CHILD. The
   // frame will be recreated via an nsChangeHint_ReconstructFrame restyle if
   // the value returned by PassesConditionalProcessingTests changes.
   SVGSVGElement *svg = static_cast<SVGSVGElement*>(aContent);
   if (!svg->PassesConditionalProcessingTests()) {
     AddStateBits(NS_STATE_SVG_NONDISPLAY_CHILD);
+  } else {
+    // If this outer <svg> element is the child of a <foreignObject> that
+    // is non-display, or is the child of a frame for HTML content that
+    // itself is a descendant of a non-display SVG frame, then we want to
+    // it non-display also.  The second case is not as simple to handle
+    // as copying a state bit from the parent, since non-SVG frames do
+    // not use NS_STATE_SVG_NONDISPLAY_CHILD.
+    for (nsIFrame* f = aParent; f; f = f->GetParent()) {
+      if (f->IsFrameOfType(eSVG)) {
+        AddStateBits(f->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD);
+        break;
+      }
+    }
   }
 
   nsSVGOuterSVGFrameBase::Init(aContent, aParent, aPrevInFlow);
 
   nsIDocument* doc = mContent->GetCurrentDoc();
   if (doc) {
     // we only care about our content's zoom and pan values if it's the root element
     if (doc->GetRootElement() == mContent) {
--- a/layout/svg/nsSVGTextFrame2.cpp
+++ b/layout/svg/nsSVGTextFrame2.cpp
@@ -3069,16 +3069,19 @@ nsSVGTextFrame2::DidSetStyleContext(nsSt
     // know it needs to be repainted.
     ReflowSVGNonDisplayText();
   }
 }
 
 void
 nsSVGTextFrame2::ReflowSVGNonDisplayText()
 {
+  MOZ_ASSERT(nsSVGUtils::AnyOuterSVGIsCallingReflowSVG(this),
+             "only call ReflowSVGNonDisplayText when an outer SVG frame is "
+             "under ReflowSVG");
   MOZ_ASSERT(mState & NS_STATE_SVG_NONDISPLAY_CHILD,
              "only call ReflowSVGNonDisplayText if the frame is "
              "NS_STATE_SVG_NONDISPLAY_CHILD");
 
   // We had a style change, so we mark this frame as dirty so that the next
   // time it is painted, we reflow the anonymous block frame.
   AddStateBits(NS_FRAME_IS_DIRTY);
 
@@ -4827,16 +4830,18 @@ nsSVGTextFrame2::UpdateGlyphPositioning(
   if (mState & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) {
     if (mState & NS_FRAME_IS_DIRTY) {
       // If we require a full reflow, ensure our kid is marked fully dirty.
       // (Note that our anonymous nsBlockFrame is not an nsISVGChildFrame, so
       // even when we are called via our ReflowSVG this will not be done for us
       // by nsSVGDisplayContainerFrame::ReflowSVG.)
       kid->AddStateBits(NS_FRAME_IS_DIRTY);
     }
+    MOZ_ASSERT(nsSVGUtils::AnyOuterSVGIsCallingReflowSVG(this),
+               "should be under ReflowSVG");
     nsPresContext::InterruptPreventer noInterrupts(PresContext());
     DoReflow();
   }
 
   if (mPositioningDirty) {
     DoGlyphPositioning();
   }
 }
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -446,16 +446,29 @@ nsSVGUtils::GetPostFilterVisualOverflowR
 }
 
 bool
 nsSVGUtils::OuterSVGIsCallingReflowSVG(nsIFrame *aFrame)
 {
   return GetOuterSVGFrame(aFrame)->IsCallingReflowSVG();
 }
 
+bool
+nsSVGUtils::AnyOuterSVGIsCallingReflowSVG(nsIFrame* aFrame)
+{
+  nsSVGOuterSVGFrame* outer = GetOuterSVGFrame(aFrame);
+  do {
+    if (outer->IsCallingReflowSVG()) {
+      return true;
+    }
+    outer = GetOuterSVGFrame(outer->GetParent());
+  } while (outer);
+  return false;
+}
+
 void
 nsSVGUtils::ScheduleReflowSVG(nsIFrame *aFrame)
 {
   NS_ABORT_IF_FALSE(aFrame->IsFrameOfType(nsIFrame::eSVG),
                     "Passed bad frame!");
 
   // If this is triggered, the callers should be fixed to call us before
   // ReflowSVG is called. If we try to mark dirty bits on frames while we're
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -516,16 +516,17 @@ public:
 
   /**
    * Find the first frame, starting with aStartFrame and going up its
    * parent chain, that is not an svgAFrame.
    */
   static nsIFrame* GetFirstNonAAncestorFrame(nsIFrame* aStartFrame);
 
   static bool OuterSVGIsCallingReflowSVG(nsIFrame *aFrame);
+  static bool AnyOuterSVGIsCallingReflowSVG(nsIFrame *aFrame);
 
   /*
    * Get any additional transforms that apply only to stroking
    * e.g. non-scaling-stroke
    */
   static gfxMatrix GetStrokeTransform(nsIFrame *aFrame);
 
   /**