Bug 1465873 - part4: Update document-walker::parentNode() to return shadow roots;r=bgrins draft
authorJulian Descottes <jdescottes@mozilla.com>
Thu, 28 Jun 2018 11:38:46 +0200
changeset 814185 9dbae35e59b81283337281d7eae47e2d0b8f8800
parent 814184 892bbcc01923bdbf4819a0155d7f7fb7653557d1
child 814186 fcdb2d81471e05d8335968ddd81867929798ccd7
push id115123
push userjdescottes@mozilla.com
push dateWed, 04 Jul 2018 17:42:29 +0000
reviewersbgrins
bugs1465873
milestone63.0a1
Bug 1465873 - part4: Update document-walker::parentNode() to return shadow roots;r=bgrins MozReview-Commit-ID: GwAl9DCT3Fs
devtools/server/actors/inspector/document-walker.js
devtools/server/actors/inspector/walker.js
--- a/devtools/server/actors/inspector/document-walker.js
+++ b/devtools/server/actors/inspector/document-walker.js
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 
+loader.lazyRequireGetter(this, "isShadowRoot", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "nodeFilterConstants", "devtools/shared/dom-node-filter-constants");
 loader.lazyRequireGetter(this, "standardTreeWalkerFilter", "devtools/server/actors/inspector/utils", true);
 
 // SKIP_TO_* arguments are used with the DocumentWalker, driving the strategy to use if
 // the starting node is incompatible with the filter function of the walker.
 const SKIP_TO_PARENT = "SKIP_TO_PARENT";
 const SKIP_TO_SIBLING = "SKIP_TO_SIBLING";
 
@@ -68,16 +69,27 @@ DocumentWalker.prototype = {
   get currentNode() {
     return this.walker.currentNode;
   },
   set currentNode(val) {
     this.walker.currentNode = val;
   },
 
   parentNode: function() {
+    if (isShadowRoot(this.currentNode)) {
+      this.currentNode = this.currentNode.host;
+      return this.currentNode;
+    }
+
+    const parentNode = this.currentNode.parentNode;
+    // deep-tree-walker currently does not return shadowRoot elements as parentNodes.
+    if (parentNode && isShadowRoot(parentNode)) {
+      this.currentNode = parentNode;
+      return this.currentNode;
+    }
     return this.walker.parentNode();
   },
 
   nextNode: function() {
     const node = this.walker.currentNode;
     if (!node) {
       return null;
     }
--- a/devtools/server/actors/inspector/walker.js
+++ b/devtools/server/actors/inspector/walker.js
@@ -436,37 +436,42 @@ var WalkerActor = protocol.ActorClassWit
   documentElement: function(node) {
     const elt = isNodeDead(node)
               ? this.rootDoc.documentElement
               : nodeDocument(node.rawNode).documentElement;
     return this._ref(elt);
   },
 
   parentNode: function(node) {
+    const parent = this.rawParentNode(node);
+    if (parent) {
+      return this._ref(parent);
+    }
+
+    return null;
+  },
+
+  rawParentNode: function(node) {
     let parent;
     try {
       // If the node is the child of a shadow host, we can not use an anonymous walker to
       // get the shadow host parent.
       const walker = isDirectShadowHostChild(node.rawNode)
         ? this.getNonAnonymousWalker(node.rawNode)
         : this.getDocumentWalker(node.rawNode);
       parent = walker.parentNode();
     } catch (e) {
       // When getting the parent node for a child of a non-slotted shadow host child,
       // walker.parentNode() will throw if the walker is anonymous, because non-slotted
       // shadow host children are not accessible anywhere in the anonymous tree.
       const walker = this.getNonAnonymousWalker(node.rawNode);
       parent = walker.parentNode();
     }
 
-    if (parent) {
-      return this._ref(parent);
-    }
-
-    return null;
+    return parent;
   },
 
   /**
    * If the given NodeActor only has a single text node as a child with a text
    * content small enough to be inlined, return that child's NodeActor.
    *
    * @param NodeActor node
    */
@@ -567,27 +572,27 @@ var WalkerActor = protocol.ActorClassWit
   /**
    * Add any nodes between `node` and the walker's root node that have not
    * yet been seen by the client.
    */
   ensurePathToRoot: function(node, newParents = new Set()) {
     if (!node) {
       return newParents;
     }
-    const walker = this.getDocumentWalker(node.rawNode);
-    let cur;
-    while ((cur = walker.parentNode())) {
-      const parent = this.getNode(cur);
-      if (!parent) {
-        // This parent didn't exist, so hasn't been seen by the client yet.
-        newParents.add(this._ref(cur));
-      } else {
+    let parent = this.rawParentNode(node);
+    while (parent) {
+      let parentActor = this.getNode(parent);
+      if (parentActor) {
         // This parent did exist, so the client knows about it.
         return newParents;
       }
+      // This parent didn't exist, so hasn't been seen by the client yet.
+      parentActor = this._ref(parent);
+      newParents.add(parentActor);
+      parent = this.rawParentNode(parentActor);
     }
     return newParents;
   },
 
   /**
    * Return the number of children under the provided NodeActor.
    *
    * @param NodeActor node