Bug 1468402 - Part 1: Add isSubgrid to the grid actor form and getParentGridNode to the walker. r=pbro
authorGabriel Luong <gabriel.luong@gmail.com>
Tue, 30 Apr 2019 00:50:47 -0400
changeset 475414 11edf789501b21a00794a5fc17e8584d9bf85807
parent 475413 932a983ac0583c9c4311ec05b9779a0257bdb8ef
child 475415 3431614b512aa28711a0c22aa159145906a7532b
push id36061
push usercbrindusan@mozilla.com
push dateFri, 24 May 2019 21:49:59 +0000
treeherdermozilla-central@5d3e1ea77693 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspbro
bugs1468402
milestone69.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 1468402 - Part 1: Add isSubgrid to the grid actor form and getParentGridNode to the walker. r=pbro Differential Revision: https://phabricator.services.mozilla.com/D29317
devtools/server/actors/inspector/utils.js
devtools/server/actors/inspector/walker.js
devtools/server/actors/layout.js
devtools/shared/fronts/layout.js
devtools/shared/specs/inspector.js
--- a/devtools/server/actors/inspector/utils.js
+++ b/devtools/server/actors/inspector/utils.js
@@ -312,18 +312,48 @@ function getClosestBackgroundImage(node)
     }
 
     current = current.parentNode;
   }
 
   return "none";
 }
 
+/**
+ * If the provided node is a grid item, then return its parent grid.
+ *
+ * @param  {DOMNode} node
+ *         The node that is supposedly a grid item.
+ * @return {DOMNode|null}
+ *         The parent grid if found, null otherwise.
+ */
+function findGridParentContainerForNode(node) {
+  try {
+    while ((node = node.parentNode)) {
+      const display = node.ownerGlobal.getComputedStyle(node).display;
+
+      if (display.includes("grid")) {
+        return node;
+      } else if (display === "contents") {
+        // Continue walking up the tree since the parent node is a content element.
+        continue;
+      }
+
+      break;
+    }
+  } catch (e) {
+    // Getting the parentNode can fail when the supplied node is in shadow DOM.
+  }
+
+  return null;
+}
+
 module.exports = {
   allAnonymousContentTreeWalkerFilter,
+  findGridParentContainerForNode,
   getClosestBackgroundColor,
   getClosestBackgroundImage,
   getNodeDisplayName,
   imageToImageData,
   isNodeDead,
   nodeDocument,
   scrollbarTreeWalkerFilter,
   standardTreeWalkerFilter,
--- a/devtools/server/actors/inspector/walker.js
+++ b/devtools/server/actors/inspector/walker.js
@@ -23,16 +23,17 @@ loader.lazyRequireGetter(this, "isNative
 loader.lazyRequireGetter(this, "isShadowHost", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isShadowRoot", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isTemplateElement", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "loadSheet", "devtools/shared/layout/utils", true);
 
 loader.lazyRequireGetter(this, "throttle", "devtools/shared/throttle", true);
 
 loader.lazyRequireGetter(this, "allAnonymousContentTreeWalkerFilter", "devtools/server/actors/inspector/utils", true);
+loader.lazyRequireGetter(this, "findGridParentContainerForNode", "devtools/server/actors/inspector/utils", true);
 loader.lazyRequireGetter(this, "isNodeDead", "devtools/server/actors/inspector/utils", true);
 loader.lazyRequireGetter(this, "nodeDocument", "devtools/server/actors/inspector/utils", true);
 loader.lazyRequireGetter(this, "standardTreeWalkerFilter", "devtools/server/actors/inspector/utils", true);
 
 loader.lazyRequireGetter(this, "CustomElementWatcher", "devtools/server/actors/inspector/custom-element-watcher", true);
 loader.lazyRequireGetter(this, "DocumentWalker", "devtools/server/actors/inspector/document-walker", true);
 loader.lazyRequireGetter(this, "SKIP_TO_SIBLING", "devtools/server/actors/inspector/document-walker", true);
 loader.lazyRequireGetter(this, "NodeActor", "devtools/server/actors/inspector/node", true);
@@ -2206,16 +2207,29 @@ var WalkerActor = protocol.ActorClassWit
     if (!this.layoutActor) {
       this.layoutActor = new LayoutActor(this.conn, this.targetActor, this);
     }
 
     return this.layoutActor;
   },
 
   /**
+   * Returns the parent grid DOMNode of the given node if it exists, otherwise, it
+   * returns null.
+   */
+  getParentGridNode: function(node) {
+    if (isNodeDead(node)) {
+      return null;
+    }
+
+    const parentGridNode = findGridParentContainerForNode(node.rawNode);
+    return parentGridNode ? this._ref(parentGridNode) : null;
+  },
+
+  /**
    * Returns the offset parent DOMNode of the given node if it exists, otherwise, it
    * returns null.
    */
   getOffsetParent: function(node) {
     if (isNodeDead(node)) {
       return null;
     }
 
--- a/devtools/server/actors/layout.js
+++ b/devtools/server/actors/layout.js
@@ -1,31 +1,36 @@
 /* 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 { Cu } = require("chrome");
+const Services = require("Services");
 const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
 const {
   flexboxSpec,
   flexItemSpec,
   gridSpec,
   layoutSpec,
 } = require("devtools/shared/specs/layout");
 const { getStringifiableFragments } =
   require("devtools/server/actors/utils/css-grid-utils");
 
 loader.lazyRequireGetter(this, "CssLogic", "devtools/server/actors/inspector/css-logic", true);
+loader.lazyRequireGetter(this, "findGridParentContainerForNode", "devtools/server/actors/inspector/utils", true);
 loader.lazyRequireGetter(this, "getCSSStyleRules", "devtools/shared/inspector/css-logic", true);
 loader.lazyRequireGetter(this, "isCssPropertyKnown", "devtools/server/actors/css-properties", true);
 loader.lazyRequireGetter(this, "parseDeclarations", "devtools/shared/css/parsing-utils", true);
 loader.lazyRequireGetter(this, "nodeConstants", "devtools/shared/dom-node-constants");
 
+const SUBGRID_ENABLED =
+  Services.prefs.getBoolPref("layout.css.grid-template-subgrid-value.enabled");
+
 /**
  * Set of actors the expose the CSS layout information to the devtools protocol clients.
  *
  * The |Layout| actor is the main entry point. It is used to get various CSS
  * layout-related information from the document.
  *
  * The |Flexbox| actor provides the container node information to inspect the flexbox
  * container. It is also used to return an array of |FlexItem| actors which provide the
@@ -269,32 +274,42 @@ const GridActor = ActorClassWithSpec(gri
 
   form() {
     // Seralize the grid fragment data into JSON so protocol.js knows how to write
     // and read the data.
     const gridFragments = this.containerEl.getGridFragments();
     this.gridFragments = getStringifiableFragments(gridFragments);
 
     // Record writing mode and text direction for use by the grid outline.
-    const { direction, writingMode } = CssLogic.getComputedStyle(this.containerEl);
+    const {
+      direction,
+      gridTemplateColumns,
+      gridTemplateRows,
+      writingMode,
+    } = CssLogic.getComputedStyle(this.containerEl);
 
     const form = {
       actor: this.actorID,
       direction,
       gridFragments: this.gridFragments,
       writingMode,
     };
 
     // If the WalkerActor already knows the container element, then also return its
     // ActorID so we avoid the client from doing another round trip to get it in many
     // cases.
     if (this.walker.hasNode(this.containerEl)) {
       form.containerNodeActorID = this.walker.getNode(this.containerEl).actorID;
     }
 
+    if (SUBGRID_ENABLED) {
+      form.isSubgrid = gridTemplateRows === "subgrid" ||
+                       gridTemplateColumns === "subgrid";
+    }
+
     return form;
   },
 });
 
 /**
  * The CSS layout actor provides layout information for the given document.
  */
 const LayoutActor = ActorClassWithSpec(layoutSpec, {
@@ -450,42 +465,12 @@ const LayoutActor = ActorClassWithSpec(l
     return gridActors;
   },
 });
 
 function isNodeDead(node) {
   return !node || (node.rawNode && Cu.isDeadWrapper(node.rawNode));
 }
 
-/**
- * If the provided node is a grid item, then return its parent grid.
- *
- * @param  {DOMNode} node
- *         The node that is supposedly a grid item.
- * @return {DOMNode|null}
- *         The parent grid if found, null otherwise.
- */
-function findGridParentContainerForNode(node) {
-  try {
-    while ((node = node.parentNode)) {
-      const display = node.ownerGlobal.getComputedStyle(node).display;
-
-      if (display.includes("grid")) {
-        return node;
-      } else if (display === "contents") {
-        // Continue walking up the tree since the parent node is a content element.
-        continue;
-      }
-
-      break;
-    }
-  } catch (e) {
-    // Getting the parentNode can fail when the supplied node is in shadow DOM.
-  }
-
-  return null;
-}
-
-exports.findGridParentContainerForNode = findGridParentContainerForNode;
 exports.FlexboxActor = FlexboxActor;
 exports.FlexItemActor = FlexItemActor;
 exports.GridActor = GridActor;
 exports.LayoutActor = LayoutActor;
--- a/devtools/shared/fronts/layout.js
+++ b/devtools/shared/fronts/layout.js
@@ -108,16 +108,23 @@ class GridFront extends FrontClassWithSp
   /**
    * Getter for the grid fragments data.
    */
   get gridFragments() {
     return this._form.gridFragments;
   }
 
   /**
+   * Get whether or not the grid is a subgrid.
+   */
+  get isSubgrid() {
+    return !!this._form.isSubgrid;
+  }
+
+  /**
    * Get the writing mode of the grid container.
    * Added in Firefox 60.
    */
   get writingMode() {
     if (!this._form.writingMode) {
       return "horizontal-tb";
     }
 
--- a/devtools/shared/specs/inspector.js
+++ b/devtools/shared/specs/inspector.js
@@ -321,16 +321,24 @@ const walkerSpec = generateActorSpec({
       },
     },
     getLayoutInspector: {
       request: {},
       response: {
         actor: RetVal("layout"),
       },
     },
+    getParentGridNode: {
+      request: {
+        node: Arg(0, "nullable:domnode"),
+      },
+      response: {
+        node: RetVal("nullable:domnode"),
+      },
+    },
     getOffsetParent: {
       request: {
         node: Arg(0, "nullable:domnode"),
       },
       response: {
         node: RetVal("nullable:domnode"),
       },
     },