Bug 1465572: Ensure <slot> disables whitespace optimizations. r?bz draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sat, 02 Jun 2018 09:35:19 +0200
changeset 803244 84597d88e93fdd91012aa2fb22115a6b8c3bf1fc
parent 803243 da9fa6fd4497086060bcbe16de0da2d1cb30f8bc
push id112049
push userbmo:emilio@crisal.io
push dateSat, 02 Jun 2018 07:46:09 +0000
reviewersbz
bugs1465572
milestone62.0a1
Bug 1465572: Ensure <slot> disables whitespace optimizations. r?bz The whitespace optimization code only knows about the light tree. It's not a great idea to try to put flattened tree children of a slot through there, since the children may not be assigned to the same slot, or to any slot (in which case we crash). We should probably rename XBLInvolved to ShadowDOMOrXBLInvolved too, I guess. Note that the ShadowRoot case already sets the bit on Init(). MozReview-Commit-ID: 91lmE7OxlnA
dom/base/ChildIterator.cpp
layout/base/nsCSSFrameConstructor.cpp
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/css/css-scoping/whitespace-crash-001.html
--- a/dom/base/ChildIterator.cpp
+++ b/dom/base/ChildIterator.cpp
@@ -149,21 +149,26 @@ FlattenedChildIterator::Init(bool aIgnor
 }
 
 bool
 FlattenedChildIterator::ComputeWhetherXBLIsInvolved() const
 {
   MOZ_ASSERT(mXBLInvolved.isNothing());
   // We set mXBLInvolved to true if either the node we're iterating has a
   // binding with content attached to it (in which case it is handled in Init),
-  // or the node is generated XBL content and has an <xbl:children> child.
+  // the node is generated XBL content and has an <xbl:children> child, or the
+  // node is a <slot> element.
   if (!mParent->GetBindingParent()) {
     return false;
   }
 
+  if (mParentAsSlot) {
+    return true;
+  }
+
   for (nsIContent* child = mParent->GetFirstChild();
        child;
        child = child->GetNextSibling()) {
     if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
       MOZ_ASSERT(child->GetBindingParent());
       return true;
     }
   }
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -7690,17 +7690,17 @@ nsCSSFrameConstructor::ContentRangeInser
 
       frameType = insertion.mParentFrame->Type();
     }
   }
 
   AutoFrameConstructionItemList items(this);
   ParentType parentType = GetParentType(frameType);
   FlattenedChildIterator iter(insertion.mContainer);
-  bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild());
+  bool haveNoXBLChildren = !iter.XBLInvolved() || !iter.GetNextChild();
   if (aStartChild->GetPreviousSibling() &&
       parentType == eTypeBlock && haveNoXBLChildren) {
     // If there's a text node in the normal content list just before the
     // new nodes, and it has no frame, make a frame construction item for
     // it, because it might need a frame now.  No need to do this if our
     // parent type is not block, though, since WipeContainingBlock
     // already handles that sitation.
     AddTextItemIfNeeded(state, insertion, aStartChild->GetPreviousSibling(),
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -129044,16 +129044,28 @@
       [
        "/css/css-scoping/reference/green-box.html",
        "=="
       ]
      ],
      {}
     ]
    ],
+   "css/css-scoping/whitespace-crash-001.html": [
+    [
+     "/css/css-scoping/whitespace-crash-001.html",
+     [
+      [
+       "/css/css-scoping/reference/green-box.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-scrollbars/viewport-scrollbar-body.html": [
     [
      "/css/css-scrollbars/viewport-scrollbar-body.html",
      [
       [
        "/css/css-scrollbars/viewport-scrollbar-body-ref.html",
        "=="
       ]
@@ -520035,16 +520047,20 @@
   "css/css-scoping/stylesheet-title-001.html": [
    "2e49b6d74d2021144444ca77e62acbc6aeffac2a",
    "reftest"
   ],
   "css/css-scoping/stylesheet-title-002.html": [
    "5816d3d7af3c4bef07f4a299ab65c74b7b8d80f9",
    "testharness"
   ],
+  "css/css-scoping/whitespace-crash-001.html": [
+   "ffcc7ce387110d170772e0c9178991a2377753ad",
+   "reftest"
+  ],
   "css/css-scroll-anchoring/OWNERS": [
    "d9c8054b356c9273a054a83abeb9be0626c23921",
    "support"
   ],
   "css/css-scroll-anchoring/README.md": [
    "31205944cbcf321f7aa77e3bef0f8835cc7b6d13",
    "support"
   ],
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scoping/whitespace-crash-001.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Scoping: Dynamic shadow root creation and whitespace optimization crash.</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="help" href="https://drafts.csswg.org/css-scoping/#selectors-data-model">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1465572">
+<link rel="match" href="reference/green-box.html"/>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<!--
+  It's important for the test-case that there's whitespace inside the host,
+  and that it's not assigned to any slot.
+-->
+<div id="host">
+  <div style="display: inline" slot="the-slot"></div>
+</div>
+<script>
+  // Flush layout before creating a ShadowRoot, so that the whitespace ends up
+  // suppressed.
+  document.body.offsetTop;
+  host.attachShadow({ mode: "open" }).innerHTML = `
+    <style>
+      ::slotted(div) {
+        width: 100px;
+        height: 100px;
+        background: green;
+      }
+    </style>
+    <slot name="the-slot"></slot>
+  `;
+  document.body.offsetTop;
+  host.firstElementChild.style.display = "block"; // or anything else that reframes the <div>.
+</script>