Bug 1453196: Fix MathML reframing code when the root is a MathML element. r?bz draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sat, 14 Apr 2018 22:58:13 +0200
changeset 789944 7758288202d7efac2ba08c7536ce962a564c68be
parent 789880 9bcb687a53a86b56d600b995497e9786f0c17e27
child 789945 5c0415f49c1c0706aa051e72458c3331742b2209
push id108371
push userbmo:emilio@crisal.io
push dateMon, 30 Apr 2018 19:53:45 +0000
reviewersbz
bugs1453196
milestone61.0a1
Bug 1453196: Fix MathML reframing code when the root is a MathML element. r?bz MozReview-Commit-ID: CPd40oHIT5w
layout/base/crashtests/1453196.html
layout/base/crashtests/crashtests.list
layout/base/nsCSSFrameConstructor.cpp
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/1453196.html
@@ -0,0 +1,15 @@
+<html>
+  <head>
+     <script>
+       function start () {
+         try { o1 = document.createElementNS('http://www.w3.org/1998/Math/MathML', 'mtable') } catch (e) {}
+         try { o2 = document.createTextNode("\u202D") } catch (e) {}
+         try { document.documentElement.appendChild(o2) } catch (e) {}
+         try { o1.insertBefore(document.documentElement, o1.childNodes[0]) } catch (e) {}
+         try { document.appendChild(o1) } catch (e) {}
+         try { document.append(o2, undefined) } catch (e) {}
+      }
+      document.addEventListener('DOMContentLoaded', start)
+    </script>
+  </head>
+</html>
\ No newline at end of file
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -524,8 +524,9 @@ load 1429962.html
 pref(dom.webcomponents.shadowdom.enabled,true) load 1439016.html
 load 1442506.html
 load 1437155.html
 load 1443027-1.html
 load 1448841-1.html
 load 1452839.html
 load 1453702.html
 load 1453342.html
+load 1453196.html
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -9085,16 +9085,37 @@ nsCSSFrameConstructor::UpdateTableCellSp
   // longer be a table cell.
   NS_WARNING_ASSERTION(cellFrame, "Hint should only be posted on table cells!");
 
   if (cellFrame) {
     cellFrame->GetTableFrame()->RowOrColSpanChanged(cellFrame);
   }
 }
 
+static nsIContent*
+GetTopmostMathMLElement(nsIContent* aMathMLContent)
+{
+  MOZ_ASSERT(aMathMLContent->IsMathMLElement());
+  MOZ_ASSERT(aMathMLContent->GetPrimaryFrame());
+  MOZ_ASSERT(aMathMLContent->GetPrimaryFrame()->IsFrameOfType(nsIFrame::eMathML));
+  nsIContent* root = aMathMLContent;
+
+  for (nsIContent* parent = aMathMLContent->GetFlattenedTreeParent();
+       parent;
+       parent = parent->GetFlattenedTreeParent()) {
+    nsIFrame* frame = parent->GetPrimaryFrame();
+    if (!frame || !frame->IsFrameOfType(nsIFrame::eMathML)) {
+      break;
+    }
+    root = parent;
+  }
+
+  return root;
+}
+
 void
 nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
                                                 InsertionKind aInsertionKind)
 {
   MOZ_ASSERT(aContent);
 
   // If there is no document, we don't want to recreate frames for it.  (You
   // shouldn't generally be giving this method content without a document
@@ -9110,25 +9131,19 @@ nsCSSFrameConstructor::RecreateFramesFor
   // content (which would otherwise result in *two* nested reframe
   // containing block from ContentRemoved() and ContentInserted(),
   // below!).  We'd really like to optimize away one of those
   // containing block reframes, hence the code here.
 
   nsIFrame* frame = aContent->GetPrimaryFrame();
   if (frame && frame->IsFrameOfType(nsIFrame::eMathML)) {
     // Reframe the topmost MathML element to prevent exponential blowup
-    // (see bug 397518)
-    while (true) {
-      nsIContent* parentContent = aContent->GetParent();
-      nsIFrame* parentContentFrame = parentContent->GetPrimaryFrame();
-      if (!parentContentFrame || !parentContentFrame->IsFrameOfType(nsIFrame::eMathML))
-        break;
-      aContent = parentContent;
-      frame = parentContentFrame;
-    }
+    // (see bug 397518).
+    aContent = GetTopmostMathMLElement(aContent);
+    frame = aContent->GetPrimaryFrame();
   }
 
   if (frame) {
     nsIFrame* nonGeneratedAncestor = nsLayoutUtils::GetNonGeneratedAncestor(frame);
     if (nonGeneratedAncestor->GetContent() != aContent) {
       return RecreateFramesForContent(nonGeneratedAncestor->GetContent(),
                                       InsertionKind::Async);
     }