Bug 1572829 - Remove explicit children too when node has a shadow root. r=Jamie
authorEitan Isaacson <eitan@monotonous.org>
Wed, 28 Aug 2019 23:02:19 +0000
changeset 490488 170a5ba09a6f9847405bc522b4984f33dface562
parent 490487 907ee4a0aa61f2ef1dc60e9abb3c21971a00eaa4
child 490489 f71ac7e684fc2d2964e236ad944c72e1e73af756
push id36504
push userccoroiu@mozilla.com
push dateThu, 29 Aug 2019 04:08:39 +0000
treeherdermozilla-central@7004b8779a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersJamie
bugs1572829
milestone70.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 1572829 - Remove explicit children too when node has a shadow root. r=Jamie Differential Revision: https://phabricator.services.mozilla.com/D43488
accessible/generic/DocAccessible.cpp
accessible/tests/mochitest/treeupdate/test_delayed_removal.html
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1996,16 +1996,30 @@ void DocAccessible::ContentRemoved(nsICo
     ContentRemoved(acc);
   }
 
   dom::AllChildrenIterator iter =
       dom::AllChildrenIterator(aContentNode, nsIContent::eAllChildren, true);
   while (nsIContent* childNode = iter.GetNextChild()) {
     ContentRemoved(childNode);
   }
+
+  // If this node has a shadow root, remove its explicit children too.
+  // The host node may be removed after the shadow root was attached, and
+  // before we asynchronously prune the light DOM and construct the shadow DOM.
+  // If this is a case where the node does not have its own accessible, we will
+  // not recurse into its current children, so we need to use an
+  // ExplicitChildIterator in order to get its accessible children in the light
+  // DOM, since they are not accessible anymore via AllChildrenIterator.
+  if (aContentNode->GetShadowRoot()) {
+    dom::ExplicitChildIterator iter = dom::ExplicitChildIterator(aContentNode);
+    while (nsIContent* childNode = iter.GetNextChild()) {
+      ContentRemoved(childNode);
+    }
+  }
 }
 
 bool DocAccessible::RelocateARIAOwnedIfNeeded(nsIContent* aElement) {
   if (!aElement->HasID()) return false;
 
   AttrRelProviders* list = GetRelProviders(
       aElement->AsElement(), nsDependentAtomString(aElement->GetID()));
   if (list) {
--- a/accessible/tests/mochitest/treeupdate/test_delayed_removal.html
+++ b/accessible/tests/mochitest/treeupdate/test_delayed_removal.html
@@ -178,16 +178,28 @@
       getNode("c8_owned_container").hidden = true;
       await events;
 
       testAccessibleTree("c8",{ SECTION: [
         { EDITCOMBOBOX: [] }, // c8_owner
       ] });
     }
 
+    // Bug 1572829
+    async function removeShadowRootHost() {
+      info("removeShadowRootHost");
+      document.body.offsetTop; // Flush layout.
+
+      let event = waitForEvent(EVENT_REORDER, "c9", "removeShadowRootHost");
+      getNode("c9").firstElementChild.attachShadow({mode: "open"});
+      getNode("c9").firstElementChild.replaceWith("");
+
+      await event;
+    }
+
     async function doTest() {
       await hideDivFromInsideSpan();
 
       await showDivFromInsideSpan();
 
       await removeDivFromInsideSpan();
 
       await addCSSGeneratedContent();
@@ -195,16 +207,18 @@
       await removeCSSGeneratedContent();
 
       await intermediateNonAccessibleContainers();
 
       await intermediateNonAccessibleContainerBecomesAccessible();
 
       await removeRelocatedWhenDomAncestorHidden();
 
+      await removeShadowRootHost();
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
@@ -244,11 +258,15 @@
 
   <div id="c8">
     <div id="c8_owner" role="combobox" aria-owns="c8_owned"></div>
     <div id="c8_owned_container">
       <div id="c8_owned" role="listbox"></div>
     </div>
   </div>
 
+  <div id="c9">
+    <div><dir>a</dir></div>
+  </div>
+
   <div id="eventdump"></div>
 </body>
 </html>