Bug 1249558 - Part 2: Display the grid info bar for a grid area highlight r=pbro
authorGabriel Luong <gabriel.luong@gmail.com>
Wed, 07 Sep 2016 16:44:11 -0400
changeset 313123 fcd122b8e0035342fce993bfa5a75fe1a4b8eb56
parent 313122 32a0c3b7b9923044adc93dde8c4debc8569ff840
child 313124 054d2453311b5adf511c5cfaa59e27db955405f7
push id30672
push usercbook@mozilla.com
push dateThu, 08 Sep 2016 10:00:36 +0000
treeherdermozilla-central@331524df5cab [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspbro
bugs1249558
milestone51.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 1249558 - Part 2: Display the grid info bar for a grid area highlight r=pbro
devtools/client/inspector/test/browser_inspector_highlighter-04.js
devtools/client/inspector/test/browser_inspector_highlighter-options.js
devtools/client/inspector/test/browser_inspector_infobar_01.js
devtools/client/inspector/test/browser_inspector_infobar_02.js
devtools/client/inspector/test/browser_inspector_infobar_03.js
devtools/client/inspector/test/browser_inspector_pseudoclass-lock.js
devtools/server/actors/highlighters.css
devtools/server/actors/highlighters/box-model.js
devtools/server/actors/highlighters/css-grid.js
devtools/server/actors/highlighters/utils/markup.js
--- a/devtools/client/inspector/test/browser_inspector_highlighter-04.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-04.js
@@ -14,22 +14,22 @@ const ELEMENTS = ["box-model-root",
                   "box-model-margin",
                   "box-model-border",
                   "box-model-padding",
                   "box-model-content",
                   "box-model-guide-top",
                   "box-model-guide-right",
                   "box-model-guide-bottom",
                   "box-model-guide-left",
-                  "box-model-nodeinfobar-container",
-                  "box-model-nodeinfobar-tagname",
-                  "box-model-nodeinfobar-id",
-                  "box-model-nodeinfobar-classes",
-                  "box-model-nodeinfobar-pseudo-classes",
-                  "box-model-nodeinfobar-dimensions"];
+                  "box-model-infobar-container",
+                  "box-model-infobar-tagname",
+                  "box-model-infobar-id",
+                  "box-model-infobar-classes",
+                  "box-model-infobar-pseudo-classes",
+                  "box-model-infobar-dimensions"];
 
 add_task(function* () {
   let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
 
   info("Show the box-model highlighter");
   let divFront = yield getNodeFront("div", inspector);
   yield toolbox.highlighter.showBoxModel(divFront);
 
--- a/devtools/client/inspector/test/browser_inspector_highlighter-options.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-options.js
@@ -19,17 +19,17 @@ const TEST_URL = `
 // - checkHighlighter: a generator (async) function that should check the
 //   highlighter is correct.
 const TEST_DATA = [
   {
     desc: "Guides and infobar should be shown by default",
     options: {},
     checkHighlighter: function* (testActor) {
       let hidden = yield testActor.getHighlighterNodeAttribute(
-        "box-model-nodeinfobar-container", "hidden");
+        "box-model-infobar-container", "hidden");
       ok(!hidden, "Node infobar is visible");
 
       hidden = yield testActor.getHighlighterNodeAttribute(
         "box-model-elements", "hidden");
       ok(!hidden, "SVG container is visible");
 
       for (let side of ["top", "right", "bottom", "left"]) {
         hidden = yield testActor.getHighlighterNodeAttribute(
@@ -59,18 +59,18 @@ const TEST_DATA = [
       }
     }
   },
   {
     desc: "Infobar can be hidden",
     options: {hideInfoBar: true},
     checkHighlighter: function* (testActor) {
       let hidden = yield testActor.getHighlighterNodeAttribute(
-        "box-model-nodeinfobar-container", "hidden");
-      is(hidden, "true", "nodeinfobar has been hidden");
+        "box-model-infobar-container", "hidden");
+      is(hidden, "true", "infobar has been hidden");
     }
   },
   {
     desc: "One region only can be shown (1)",
     options: {showOnly: "content"},
     checkHighlighter: function* (testActor) {
       let {d} = yield testActor.getHighlighterRegionPath("margin");
       ok(!d, "margin region is hidden");
--- a/devtools/client/inspector/test/browser_inspector_infobar_01.js
+++ b/devtools/client/inspector/test/browser_inspector_infobar_01.js
@@ -59,31 +59,31 @@ add_task(function* () {
 });
 
 function* testPosition(test, inspector, testActor) {
   info("Testing " + test.selector);
 
   yield selectAndHighlightNode(test.selector, inspector);
 
   let position = yield testActor.getHighlighterNodeAttribute(
-    "box-model-nodeinfobar-container", "position");
+    "box-model-infobar-container", "position");
   is(position, test.position, "Node " + test.selector + ": position matches");
 
   let tag = yield testActor.getHighlighterNodeTextContent(
-    "box-model-nodeinfobar-tagname");
+    "box-model-infobar-tagname");
   is(tag, test.tag, "node " + test.selector + ": tagName matches.");
 
   if (test.id) {
     let id = yield testActor.getHighlighterNodeTextContent(
-      "box-model-nodeinfobar-id");
+      "box-model-infobar-id");
     is(id, "#" + test.id, "node " + test.selector + ": id matches.");
   }
 
   let classes = yield testActor.getHighlighterNodeTextContent(
-    "box-model-nodeinfobar-classes");
+    "box-model-infobar-classes");
   is(classes, test.classes, "node " + test.selector + ": classes match.");
 
   if (test.dims) {
     let dims = yield testActor.getHighlighterNodeTextContent(
-      "box-model-nodeinfobar-dimensions");
+      "box-model-infobar-dimensions");
     is(dims, test.dims, "node " + test.selector + ": dims match.");
   }
 }
--- a/devtools/client/inspector/test/browser_inspector_infobar_02.js
+++ b/devtools/client/inspector/test/browser_inspector_infobar_02.js
@@ -40,11 +40,11 @@ add_task(function* () {
 });
 
 function* testNode(test, inspector, testActor) {
   info("Testing " + test.selector);
 
   yield selectAndHighlightNode(test.selector, inspector);
 
   let tag = yield testActor.getHighlighterNodeTextContent(
-    "box-model-nodeinfobar-tagname");
+    "box-model-infobar-tagname");
   is(tag, test.tag, "node " + test.selector + ": tagName matches.");
 }
--- a/devtools/client/inspector/test/browser_inspector_infobar_03.js
+++ b/devtools/client/inspector/test/browser_inspector_infobar_03.js
@@ -21,21 +21,21 @@ add_task(function* () {
 });
 
 function* testPositionAndStyle(test, inspector, testActor) {
   info("Testing " + test.selector);
 
   yield selectAndHighlightNode(test.selector, inspector);
 
   let style = yield testActor.getHighlighterNodeAttribute(
-    "box-model-nodeinfobar-container", "style");
+    "box-model-infobar-container", "style");
 
   is(style.split(";")[0], test.style,
     "Infobar shows on top of the page when page isn't scrolled");
 
   yield testActor.scrollWindow(0, 500);
 
   style = yield testActor.getHighlighterNodeAttribute(
-    "box-model-nodeinfobar-container", "style");
+    "box-model-infobar-container", "style");
 
   is(style.split(";")[0], test.style,
     "Infobar shows on top of the page even if the page is scrolled");
 }
--- a/devtools/client/inspector/test/browser_inspector_pseudoclass-lock.js
+++ b/devtools/client/inspector/test/browser_inspector_pseudoclass-lock.js
@@ -112,17 +112,17 @@ function* assertPseudoAddedToNode(inspec
   is(rules[1]._ruleEditor.rule.selectorText, "div:hover",
      "rule view is showing " + PSEUDO + " rule");
 
   info("Show the highlighter on #div-1");
   yield showPickerOn("#div-1", inspector);
 
   info("Check that the infobar selector contains the pseudo-class");
   let value = yield testActor.getHighlighterNodeTextContent(
-    "box-model-nodeinfobar-pseudo-classes");
+    "box-model-infobar-pseudo-classes");
   is(value, PSEUDO, "pseudo-class in infobar selector");
   yield inspector.toolbox.highlighter.hideBoxModel();
 }
 
 function* assertPseudoRemovedFromNode(testActor) {
   info("Make sure the pseudoclass lock is removed from #div-1 and its " +
        "ancestors");
 
@@ -138,12 +138,12 @@ function* assertPseudoRemovedFromView(in
   info("Check that the ruleview no longer contains the pseudo-class rule");
   let rules = ruleview.element.querySelectorAll(
     ".ruleview-rule.theme-separator");
   is(rules.length, 2, "rule view is showing 2 rules after removing lock");
 
   yield showPickerOn("#div-1", inspector);
 
   let value = yield testActor.getHighlighterNodeTextContent(
-    "box-model-nodeinfobar-pseudo-classes");
+    "box-model-infobar-pseudo-classes");
   is(value, "", "pseudo-class removed from infobar selector");
   yield inspector.toolbox.highlighter.hideBoxModel();
 }
--- a/devtools/server/actors/highlighters.css
+++ b/devtools/server/actors/highlighters.css
@@ -94,113 +94,113 @@
 :-moz-native-anonymous .box-model-guide-right,
 :-moz-native-anonymous .box-model-guide-bottom,
 :-moz-native-anonymous .box-model-guide-left {
   stroke: var(--highlighter-guide-color);
   stroke-dasharray: 5 3;
   shape-rendering: crispEdges;
 }
 
-/* Highlighter - Node Infobar */
+/* Highlighter - Infobar */
 
-:-moz-native-anonymous .box-model-nodeinfobar-container {
+:-moz-native-anonymous [class$=infobar-container] {
   position: absolute;
   max-width: 95%;
 
   font: message-box;
   font-size: 11px;
 }
 
-:-moz-native-anonymous .box-model-nodeinfobar {
+:-moz-native-anonymous [class$=infobar] {
   position: relative;
 
-  /* Centering the nodeinfobar in the container */
+  /* Centering the infobar in the container */
   left: -50%;
 
   padding: 5px;
   min-width: 75px;
 
   border-radius: 3px;
   background: var(--highlighter-bubble-background-color) no-repeat padding-box;
 
   color: var(--highlighter-bubble-text-color);
   text-shadow: none;
 
   border: 1px solid var(--highlighter-bubble-border-color);
 }
 
-:-moz-native-anonymous .box-model-nodeinfobar-container[hide-arrow] > .box-model-nodeinfobar {
+:-moz-native-anonymous [class$=infobar-container][hide-arrow] > [class$=infobar] {
   margin: 7px 0;
 }
 
 /* Arrows */
 
-:-moz-native-anonymous .box-model-nodeinfobar-container > .box-model-nodeinfobar:before {
+:-moz-native-anonymous [class$=infobar-container] > [class$=infobar]:before {
   left: calc(50% - 8px);
   border: 8px solid var(--highlighter-bubble-border-color);
 }
 
-:-moz-native-anonymous .box-model-nodeinfobar-container > .box-model-nodeinfobar:after {
+:-moz-native-anonymous [class$=infobar-container] > [class$=infobar]:after {
   left: calc(50% - 7px);
   border: 7px solid var(--highlighter-bubble-background-color);
 }
 
-:-moz-native-anonymous .box-model-nodeinfobar-container > .box-model-nodeinfobar:before,
-:-moz-native-anonymous .box-model-nodeinfobar-container > .box-model-nodeinfobar:after {
+:-moz-native-anonymous [class$=infobar-container] > [class$=infobar]:before,
+:-moz-native-anonymous [class$=infobar-container] > [class$=infobar]:after {
   content: "";
   display: none;
   position: absolute;
   height: 0;
   width: 0;
   border-left-color: transparent;
   border-right-color: transparent;
 }
 
-:-moz-native-anonymous .box-model-nodeinfobar-container[position="top"]:not([hide-arrow]) > .box-model-nodeinfobar:before,
-:-moz-native-anonymous .box-model-nodeinfobar-container[position="top"]:not([hide-arrow]) > .box-model-nodeinfobar:after {
+:-moz-native-anonymous [class$=infobar-container][position="top"]:not([hide-arrow]) > [class$=infobar]:before,
+:-moz-native-anonymous [class$=infobar-container][position="top"]:not([hide-arrow]) > [class$=infobar]:after {
   border-bottom: 0;
   top: 100%;
   display: block;
 }
 
-:-moz-native-anonymous .box-model-nodeinfobar-container[position="bottom"]:not([hide-arrow]) > .box-model-nodeinfobar:before,
-:-moz-native-anonymous .box-model-nodeinfobar-container[position="bottom"]:not([hide-arrow]) > .box-model-nodeinfobar:after {
+:-moz-native-anonymous [class$=infobar-container][position="bottom"]:not([hide-arrow]) > [class$=infobar]:before,
+:-moz-native-anonymous [class$=infobar-container][position="bottom"]:not([hide-arrow]) > [class$=infobar]:after {
   border-top: 0;
   bottom: 100%;
   display: block;
 }
 
-/* Text container */
+/* Text Container */
 
-:-moz-native-anonymous .box-model-nodeinfobar-text {
+:-moz-native-anonymous [class$=infobar-text] {
   overflow: hidden;
   white-space: nowrap;
   direction: ltr;
   padding-bottom: 1px;
   display: flex;
 }
 
-:-moz-native-anonymous .box-model-nodeinfobar-tagname {
+:-moz-native-anonymous .box-model-infobar-tagname {
   color: hsl(285,100%, 75%);
 }
 
-:-moz-native-anonymous .box-model-nodeinfobar-id {
+:-moz-native-anonymous .box-model-infobar-id {
   color: hsl(103, 46%, 54%);
   overflow: hidden;
   text-overflow: ellipsis;
 }
 
-:-moz-native-anonymous .box-model-nodeinfobar-classes,
-:-moz-native-anonymous .box-model-nodeinfobar-pseudo-classes {
+:-moz-native-anonymous .box-model-infobar-classes,
+:-moz-native-anonymous .box-model-infobar-pseudo-classes {
   color: hsl(200, 74%, 57%);
   overflow: hidden;
   text-overflow: ellipsis;
 }
 
-:-moz-native-anonymous .box-model-nodeinfobar-dimensions {
+:-moz-native-anonymous [class$=infobar-dimensions] {
   color: hsl(210, 30%, 85%);
   border-inline-start: 1px solid #5a6169;
   margin-inline-start: 6px;
   padding-inline-start: 6px;
 }
 
 /* CSS Grid Highlighter */
 
@@ -216,16 +216,20 @@
   opacity: 0.6;
 }
 
 :-moz-native-anonymous .css-grid-areas {
   fill: #CEC0ED;
   stroke: none;
 }
 
+:-moz-native-anonymous .css-grid-infobar-areaname {
+  color: hsl(285,100%, 75%);
+}
+
 /* CSS Transform Highlighter */
 
 :-moz-native-anonymous .css-transform-transformed {
   fill: var(--highlighter-content-color);
   opacity: 0.8;
 }
 
 :-moz-native-anonymous .css-transform-untransformed {
--- a/devtools/server/actors/highlighters/box-model.js
+++ b/devtools/server/actors/highlighters/box-model.js
@@ -2,33 +2,28 @@
  * 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 { extend } = require("sdk/core/heritage");
 const { AutoRefreshHighlighter } = require("./auto-refresh");
 const {
-  CanvasFrameAnonymousContentHelper,
+  CanvasFrameAnonymousContentHelper, moveInfobar,
   getBindingElementAndPseudo, hasPseudoClassLock, getComputedStyle,
   createSVGNode, createNode, isNodeValid } = require("./utils/markup");
-const { getCurrentZoom,
-  setIgnoreLayoutChanges } = require("devtools/shared/layout/utils");
+const { setIgnoreLayoutChanges } = require("devtools/shared/layout/utils");
 const inspector = require("devtools/server/actors/inspector");
 
 // Note that the order of items in this array is important because it is used
 // for drawing the BoxModelHighlighter's path elements correctly.
 const BOX_MODEL_REGIONS = ["margin", "border", "padding", "content"];
 const BOX_MODEL_SIDES = ["top", "right", "bottom", "left"];
 // Width of boxmodelhighlighter guides
 const GUIDE_STROKE_WIDTH = 1;
-// How high is the nodeinfobar (px).
-const NODE_INFOBAR_HEIGHT = 34;
-// What's the size of the nodeinfobar arrow (px).
-const NODE_INFOBAR_ARROW_SIZE = 9;
 // FIXME: add ":visited" and ":link" after bug 713106 is fixed
 const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
 
 /**
  * The BoxModelHighlighter draws the box model regions on top of a node.
  * If the node is a block box, then each region will be displayed as 1 polygon.
  * If the node is an inline box though, each region may be represented by 1 or
  * more polygons, depending on how many line boxes the inline element has.
@@ -68,27 +63,27 @@ const PSEUDO_CLASSES = [":hover", ":acti
  *         <path class="box-model-padding" points="..." />
  *         <path class="box-model-content" points="..." />
  *       </g>
  *       <line class="box-model-guide-top" x1="..." y1="..." x2="..." y2="..." />
  *       <line class="box-model-guide-right" x1="..." y1="..." x2="..." y2="..." />
  *       <line class="box-model-guide-bottom" x1="..." y1="..." x2="..." y2="..." />
  *       <line class="box-model-guide-left" x1="..." y1="..." x2="..." y2="..." />
  *     </svg>
- *     <div class="box-model-nodeinfobar-container">
- *       <div class="box-model-nodeinfobar-arrow highlighter-nodeinfobar-arrow-top" />
- *       <div class="box-model-nodeinfobar">
- *         <div class="box-model-nodeinfobar-text" align="center">
- *           <span class="box-model-nodeinfobar-tagname">Node name</span>
- *           <span class="box-model-nodeinfobar-id">Node id</span>
- *           <span class="box-model-nodeinfobar-classes">.someClass</span>
- *           <span class="box-model-nodeinfobar-pseudo-classes">:hover</span>
+ *     <div class="box-model-infobar-container">
+ *       <div class="box-model-infobar-arrow highlighter-infobar-arrow-top" />
+ *       <div class="box-model-infobar">
+ *         <div class="box-model-infobar-text" align="center">
+ *           <span class="box-model-infobar-tagname">Node name</span>
+ *           <span class="box-model-infobar-id">Node id</span>
+ *           <span class="box-model-infobar-classes">.someClass</span>
+ *           <span class="box-model-infobar-pseudo-classes">:hover</span>
  *         </div>
  *       </div>
- *       <div class="box-model-nodeinfobar-arrow box-model-nodeinfobar-arrow-bottom"/>
+ *       <div class="box-model-infobar-arrow box-model-infobar-arrow-bottom"/>
  *     </div>
  *   </div>
  * </div>
  */
 function BoxModelHighlighter(highlighterEnv) {
   AutoRefreshHighlighter.call(this, highlighterEnv);
 
   this.markup = new CanvasFrameAnonymousContentHelper(this.highlighterEnv,
@@ -181,81 +176,81 @@ BoxModelHighlighter.prototype = extend(A
       });
     }
 
     // Building the nodeinfo bar markup
 
     let infobarContainer = createNode(this.win, {
       parent: rootWrapper,
       attributes: {
-        "class": "nodeinfobar-container",
-        "id": "nodeinfobar-container",
+        "class": "infobar-container",
+        "id": "infobar-container",
         "position": "top",
         "hidden": "true"
       },
       prefix: this.ID_CLASS_PREFIX
     });
 
-    let nodeInfobar = createNode(this.win, {
+    let infobar = createNode(this.win, {
       parent: infobarContainer,
       attributes: {
-        "class": "nodeinfobar"
+        "class": "infobar"
       },
       prefix: this.ID_CLASS_PREFIX
     });
 
     let texthbox = createNode(this.win, {
-      parent: nodeInfobar,
+      parent: infobar,
       attributes: {
-        "class": "nodeinfobar-text"
+        "class": "infobar-text"
       },
       prefix: this.ID_CLASS_PREFIX
     });
     createNode(this.win, {
       nodeType: "span",
       parent: texthbox,
       attributes: {
-        "class": "nodeinfobar-tagname",
-        "id": "nodeinfobar-tagname"
+        "class": "infobar-tagname",
+        "id": "infobar-tagname"
       },
       prefix: this.ID_CLASS_PREFIX
     });
     createNode(this.win, {
       nodeType: "span",
       parent: texthbox,
       attributes: {
-        "class": "nodeinfobar-id",
-        "id": "nodeinfobar-id"
+        "class": "infobar-id",
+        "id": "infobar-id"
       },
       prefix: this.ID_CLASS_PREFIX
     });
     createNode(this.win, {
       nodeType: "span",
       parent: texthbox,
       attributes: {
-        "class": "nodeinfobar-classes",
-        "id": "nodeinfobar-classes"
+        "class": "infobar-classes",
+        "id": "infobar-classes"
       },
       prefix: this.ID_CLASS_PREFIX
     });
     createNode(this.win, {
       nodeType: "span",
       parent: texthbox,
       attributes: {
-        "class": "nodeinfobar-pseudo-classes",
-        "id": "nodeinfobar-pseudo-classes"
+        "class": "infobar-pseudo-classes",
+        "id": "infobar-pseudo-classes"
       },
       prefix: this.ID_CLASS_PREFIX
     });
     createNode(this.win, {
       nodeType: "span",
       parent: texthbox,
       attributes: {
-        "class": "nodeinfobar-dimensions",
-        "id": "nodeinfobar-dimensions"
+        "class": "infobar-dimensions",
+        "id": "infobar-dimensions"
       },
       prefix: this.ID_CLASS_PREFIX
     });
 
     return highlighterContainer;
   },
 
   /**
@@ -345,24 +340,24 @@ BoxModelHighlighter.prototype = extend(A
 
     setIgnoreLayoutChanges(false, this.currentNode.ownerDocument.documentElement);
   },
 
   /**
    * Hide the infobar
    */
   _hideInfobar: function () {
-    this.getElement("nodeinfobar-container").setAttribute("hidden", "true");
+    this.getElement("infobar-container").setAttribute("hidden", "true");
   },
 
   /**
    * Show the infobar
    */
   _showInfobar: function () {
-    this.getElement("nodeinfobar-container").removeAttribute("hidden");
+    this.getElement("infobar-container").removeAttribute("hidden");
     this._updateInfobar();
   },
 
   /**
    * Hide the box model
    */
   _hideBoxModel: function () {
     this.getElement("elements").setAttribute("hidden", "true");
@@ -374,17 +369,17 @@ BoxModelHighlighter.prototype = extend(A
   _showBoxModel: function () {
     this.getElement("elements").removeAttribute("hidden");
   },
 
   /**
    * Calculate an outer quad based on the quads returned by getAdjustedQuads.
    * The BoxModelHighlighter may highlight more than one boxes, so in this case
    * create a new quad that "contains" all of these quads.
-   * This is useful to position the guides and nodeinfobar.
+   * This is useful to position the guides and infobar.
    * This may happen if the BoxModelHighlighter is used to highlight an inline
    * element that spans line breaks.
    * @param {String} region The box-model region to get the outer quad for.
    * @return {Object} A quad-like object {p1,p2,p3,p4,bounds}
    */
   _getOuterQuad: function (region) {
     let quads = this.currentQuads[region];
     if (!quads.length) {
@@ -671,76 +666,28 @@ BoxModelHighlighter.prototype = extend(A
       pseudos += ":" + pseudo;
     }
 
     let rect = this._getOuterQuad("border").bounds;
     let dim = parseFloat(rect.width.toPrecision(6)) +
               " \u00D7 " +
               parseFloat(rect.height.toPrecision(6));
 
-    this.getElement("nodeinfobar-tagname").setTextContent(displayName);
-    this.getElement("nodeinfobar-id").setTextContent(id);
-    this.getElement("nodeinfobar-classes").setTextContent(classList);
-    this.getElement("nodeinfobar-pseudo-classes").setTextContent(pseudos);
-    this.getElement("nodeinfobar-dimensions").setTextContent(dim);
+    this.getElement("infobar-tagname").setTextContent(displayName);
+    this.getElement("infobar-id").setTextContent(id);
+    this.getElement("infobar-classes").setTextContent(classList);
+    this.getElement("infobar-pseudo-classes").setTextContent(pseudos);
+    this.getElement("infobar-dimensions").setTextContent(dim);
 
     this._moveInfobar();
   },
 
   /**
    * Move the Infobar to the right place in the highlighter.
    */
   _moveInfobar: function () {
     let bounds = this._getOuterBounds();
-    let winHeight = this.win.innerHeight * getCurrentZoom(this.win);
-    let winWidth = this.win.innerWidth * getCurrentZoom(this.win);
-    let winScrollY = this.win.scrollY;
-
-    // Ensure that containerBottom and containerTop are at least zero to avoid
-    // showing tooltips outside the viewport.
-    let containerBottom = Math.max(0, bounds.bottom) + NODE_INFOBAR_ARROW_SIZE;
-    let containerTop = Math.min(winHeight, bounds.top);
-    let container = this.getElement("nodeinfobar-container");
+    let container = this.getElement("infobar-container");
 
-    // Can the bar be above the node?
-    let top;
-    if (containerTop < NODE_INFOBAR_HEIGHT) {
-      // No. Can we move the bar under the node?
-      if (containerBottom + NODE_INFOBAR_HEIGHT > winHeight) {
-        // No. Let's move it inside. Can we show it at the top of the element?
-        if (containerTop < winScrollY) {
-          // No. Window is scrolled past the top of the element.
-          top = 0;
-        } else {
-          // Yes. Show it at the top of the element
-          top = containerTop;
-        }
-        container.setAttribute("position", "overlap");
-      } else {
-        // Yes. Let's move it under the node.
-        top = containerBottom;
-        container.setAttribute("position", "bottom");
-      }
-    } else {
-      // Yes. Let's move it on top of the node.
-      top = containerTop - NODE_INFOBAR_HEIGHT;
-      container.setAttribute("position", "top");
-    }
-
-    // Align the bar with the box's center if possible.
-    let left = bounds.right - bounds.width / 2;
-    // Make sure the while infobar is visible.
-    let buffer = 100;
-    if (left < buffer) {
-      left = buffer;
-      container.setAttribute("hide-arrow", "true");
-    } else if (left > winWidth - buffer) {
-      left = winWidth - buffer;
-      container.setAttribute("hide-arrow", "true");
-    } else {
-      container.removeAttribute("hide-arrow");
-    }
-
-    let style = "top:" + top + "px;left:" + left + "px;";
-    container.setAttribute("style", style);
+    moveInfobar(container, bounds, this.win);
   }
 });
 exports.BoxModelHighlighter = BoxModelHighlighter;
--- a/devtools/server/actors/highlighters/css-grid.js
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -4,17 +4,18 @@
 
 "use strict";
 
 const { extend } = require("sdk/core/heritage");
 const { AutoRefreshHighlighter } = require("./auto-refresh");
 const {
   CanvasFrameAnonymousContentHelper,
   createNode,
-  createSVGNode
+  createSVGNode,
+  moveInfobar,
 } = require("./utils/markup");
 const {
   getCurrentZoom,
   setIgnoreLayoutChanges
 } = require("devtools/shared/layout/utils");
 const Services = require("Services");
 
 const CSS_GRID_ENABLED_PREF = "layout.css.grid.enabled";
@@ -61,16 +62,24 @@ const GRID_LINES_PROPERTIES = {
  * Structure:
  * <div class="highlighter-container">
  *   <canvas id="css-grid-canvas" class="css-grid-canvas">
  *   <svg class="css-grid-elements" hidden="true">
  *     <g class="css-grid-regions">
  *       <path class="css-grid-areas" points="..." />
  *     </g>
  *   </svg>
+ *   <div class="css-grid-infobar-container">
+ *     <div class="css-grid-infobar">
+ *       <div class="css-grid-infobar-text">
+ *         <span class="css-grid-infobar-areaname">Grid Area Name</span>
+ *         <span class="css-grid-infobar-dimensions"Grid Area Dimensions></span>
+ *       </div>
+ *     </div>
+ *   </div>
  * </div>
  */
 function CssGridHighlighter(highlighterEnv) {
   AutoRefreshHighlighter.call(this, highlighterEnv);
 
   this.markup = new CanvasFrameAnonymousContentHelper(this.highlighterEnv,
     this._buildMarkup.bind(this));
 }
@@ -128,16 +137,62 @@ CssGridHighlighter.prototype = extend(Au
       parent: regions,
       attributes: {
         "class": "areas",
         "id": "areas"
       },
       prefix: this.ID_CLASS_PREFIX
     });
 
+    // Building the grid infobar markup
+    let infobarContainer = createNode(this.win, {
+      parent: container,
+      attributes: {
+        "class": "infobar-container",
+        "id": "infobar-container",
+        "position": "top",
+        "hidden": "true"
+      },
+      prefix: this.ID_CLASS_PREFIX
+    });
+
+    let infobar = createNode(this.win, {
+      parent: infobarContainer,
+      attributes: {
+        "class": "infobar"
+      },
+      prefix: this.ID_CLASS_PREFIX
+    });
+
+    let textbox = createNode(this.win, {
+      parent: infobar,
+      attributes: {
+        "class": "infobar-text"
+      },
+      prefix: this.ID_CLASS_PREFIX
+    });
+    createNode(this.win, {
+      nodeType: "span",
+      parent: textbox,
+      attributes: {
+        "class": "infobar-areaname",
+        "id": "infobar-areaname"
+      },
+      prefix: this.ID_CLASS_PREFIX
+    });
+    createNode(this.win, {
+      nodeType: "span",
+      parent: textbox,
+      attributes: {
+        "class": "infobar-dimensions",
+        "id": "infobar-dimensions"
+      },
+      prefix: this.ID_CLASS_PREFIX
+    });
+
     return container;
   },
 
   destroy() {
     AutoRefreshHighlighter.prototype.destroy.call(this);
     this.markup.destroy();
   },
 
@@ -241,16 +296,71 @@ CssGridHighlighter.prototype = extend(Au
     }
 
     this._showGrid();
 
     setIgnoreLayoutChanges(false, this.currentNode.ownerDocument.documentElement);
     return true;
   },
 
+  /**
+   * Update the grid information displayed in the grid info bar.
+   *
+   * @param  {GridArea} area
+   *         The grid area object.
+   * @param  {Number} x1
+   *         The first x-coordinate of the grid area rectangle.
+   * @param  {Number} x2
+   *         The second x-coordinate of the grid area rectangle.
+   * @param  {Number} y1
+   *         The first y-coordinate of the grid area rectangle.
+   * @param  {Number} y2
+   *         The second y-coordinate of the grid area rectangle.
+   */
+  _updateInfobar(area, x1, x2, y1, y2) {
+    let width = x2 - x1;
+    let height = y2 - y1;
+    let dim = parseFloat(width.toPrecision(6)) +
+              " \u00D7 " +
+              parseFloat(height.toPrecision(6));
+
+    this.getElement("infobar-areaname").setTextContent(area.name);
+    this.getElement("infobar-dimensions").setTextContent(dim);
+
+    this._moveInfobar(x1, x2, y1, y2);
+  },
+
+  /**
+   * Move the grid infobar to the right place in the highlighter.
+   *
+   * @param  {Number} x1
+   *         The first x-coordinate of the grid area rectangle.
+   * @param  {Number} x2
+   *         The second x-coordinate of the grid area rectangle.
+   * @param  {Number} y1
+   *         The first y-coordinate of the grid area rectangle.
+   * @param  {Number} y2
+   *         The second y-coordinate of the grid area rectangle.
+   */
+  _moveInfobar(x1, x2, y1, y2) {
+    let bounds = {
+      bottom: y2,
+      height: y2 - y1,
+      left: x1,
+      right: x2,
+      top: y1,
+      width: x2 - x1,
+      x: x1,
+      y: y1,
+    };
+    let container = this.getElement("infobar-container");
+
+    moveInfobar(container, bounds, this.win);
+  },
+
   clearCanvas() {
     let ratio = parseFloat((this.win.devicePixelRatio || 1).toFixed(2));
     let width = this.win.innerWidth;
     let height = this.win.innerHeight;
 
     // Resize the canvas taking the dpr into account so as to have crisp lines.
     this.canvas.setAttribute("width", width * ratio);
     this.canvas.setAttribute("height", height * ratio);
@@ -452,30 +562,37 @@ CssGridHighlighter.prototype = extend(Au
           (bounds.top / currentZoom);
         let y2 = rowEnd.start + (bounds.top / currentZoom);
 
         let path = "M" + x1 + "," + y1 + " " +
                    "L" + x2 + "," + y1 + " " +
                    "L" + x2 + "," + y2 + " " +
                    "L" + x1 + "," + y2;
         paths.push(path);
+
+        // Update and show the info bar when only displaying a single grid area.
+        if (areaName) {
+          this._updateInfobar(area, x1, x2, y1, y2);
+          this._showInfoBar();
+        }
       }
     }
 
     let box = this.getElement("areas");
     box.setAttribute("d", paths.join(" "));
   },
 
   /**
-   * Hide the highlighter and the canvas.
+   * Hide the highlighter, the canvas and the infobar.
    */
   _hide() {
     setIgnoreLayoutChanges(true);
     this._hideGrid();
     this._hideGridArea();
+    this._hideInfoBar();
     setIgnoreLayoutChanges(false, this.currentNode.ownerDocument.documentElement);
   },
 
   _hideGrid() {
     this.getElement("canvas").setAttribute("hidden", "true");
   },
 
   _showGrid() {
@@ -485,16 +602,24 @@ CssGridHighlighter.prototype = extend(Au
   _hideGridArea() {
     this.getElement("elements").setAttribute("hidden", "true");
   },
 
   _showGridArea() {
     this.getElement("elements").removeAttribute("hidden");
   },
 
+  _hideInfoBar() {
+    this.getElement("infobar-container").setAttribute("hidden", "true");
+  },
+
+  _showInfoBar() {
+    this.getElement("infobar-container").removeAttribute("hidden");
+  },
+
 });
 exports.CssGridHighlighter = CssGridHighlighter;
 
 /**
  * Stringify CSS Grid data as returned by node.getGridFragments.
  * This is useful to compare grid state at each update and redraw the highlighter if
  * needed.
  *
--- a/devtools/server/actors/highlighters/utils/markup.js
+++ b/devtools/server/actors/highlighters/utils/markup.js
@@ -32,16 +32,20 @@ exports.removePseudoClassLock = (...args
 
 exports.getCSSStyleRules = (...args) =>
   lazyContainer.DOMUtils.getCSSStyleRules(...args);
 
 const SVG_NS = "http://www.w3.org/2000/svg";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const STYLESHEET_URI = "resource://devtools/server/actors/" +
                        "highlighters.css";
+// How high is the infobar (px).
+const INFOBAR_HEIGHT = 34;
+// What's the size of the infobar arrow (px).
+const INFOBAR_ARROW_SIZE = 9;
 
 const _tokens = Symbol("classList/tokens");
 
 /**
  * Shims the element's `classList` for anonymous content elements; used
  * internally by `CanvasFrameAnonymousContentHelper.getElement()` method.
  */
 function ClassList(className) {
@@ -512,8 +516,79 @@ CanvasFrameAnonymousContentHelper.protot
       value += "transform-origin:top left;transform:scale(" + (1 / zoom) + ");";
       value += "width:" + (100 * zoom) + "%;height:" + (100 * zoom) + "%;";
     }
 
     this.setAttributeForElement(id, "style", value);
   }
 };
 exports.CanvasFrameAnonymousContentHelper = CanvasFrameAnonymousContentHelper;
+
+/**
+ * Move the infobar to the right place in the highlighter. This helper method is utilized
+ * in both css-grid.js and box-model.js to help position the infobar in an appropriate
+ * space over the highlighted node element or grid area. The infobar is used to display
+ * relevant information about the highlighted item (ex, node or grid name and dimensions).
+ *
+ * This method will first try to position the infobar to top or bottom of the container
+ * such that it has enough space for the height of the infobar. Afterwards, it will try
+ * to horizontally center align with the container element if possible.
+ *
+ * @param  {DOMNode} container
+ *         The container element which will be used to position the infobar.
+ * @param  {Object} bounds
+ *         The content bounds of the container element.
+ * @param  {Window} win
+ *         The window object.
+ */
+function moveInfobar(container, bounds, win) {
+  let winHeight = win.innerHeight * getCurrentZoom(win);
+  let winWidth = win.innerWidth * getCurrentZoom(win);
+  let winScrollY = win.scrollY;
+
+  // Ensure that containerBottom and containerTop are at least zero to avoid
+  // showing tooltips outside the viewport.
+  let containerBottom = Math.max(0, bounds.bottom) + INFOBAR_ARROW_SIZE;
+  let containerTop = Math.min(winHeight, bounds.top);
+
+  // Can the bar be above the node?
+  let top;
+  if (containerTop < INFOBAR_HEIGHT) {
+    // No. Can we move the bar under the node?
+    if (containerBottom + INFOBAR_HEIGHT > winHeight) {
+      // No. Let's move it inside. Can we show it at the top of the element?
+      if (containerTop < winScrollY) {
+        // No. Window is scrolled past the top of the element.
+        top = 0;
+      } else {
+        // Yes. Show it at the top of the element
+        top = containerTop;
+      }
+      container.setAttribute("position", "overlap");
+    } else {
+      // Yes. Let's move it under the node.
+      top = containerBottom;
+      container.setAttribute("position", "bottom");
+    }
+  } else {
+    // Yes. Let's move it on top of the node.
+    top = containerTop - INFOBAR_HEIGHT;
+    container.setAttribute("position", "top");
+  }
+
+  // Align the bar with the box's center if possible.
+  let left = bounds.right - bounds.width / 2;
+  // Make sure the while infobar is visible.
+  let buffer = 100;
+  if (left < buffer) {
+    left = buffer;
+    container.setAttribute("hide-arrow", "true");
+  } else if (left > winWidth - buffer) {
+    left = winWidth - buffer;
+    container.setAttribute("hide-arrow", "true");
+  } else {
+    container.removeAttribute("hide-arrow");
+  }
+
+  let style = "top:" + top + "px;left:" + left + "px;";
+  container.setAttribute("style", style);
+}
+exports.moveInfobar = moveInfobar;