diff --git a/.eslintignore b/.eslintignore
index 246d0c85d2ba..7a23df037109 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -113,6 +113,7 @@ devtools/server/*.jsm
!devtools/server/websocket-server.js
devtools/server/actors/**
!devtools/server/actors/inspector.js
+!devtools/server/actors/highlighters/css-grid.js
!devtools/server/actors/highlighters/eye-dropper.js
!devtools/server/actors/webbrowser.js
!devtools/server/actors/webextension.js
diff --git a/devtools/client/inspector/test/browser.ini b/devtools/client/inspector/test/browser.ini
index 43315a3f6519..5140cc86ada0 100644
--- a/devtools/client/inspector/test/browser.ini
+++ b/devtools/client/inspector/test/browser.ini
@@ -65,6 +65,7 @@ skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keybo
[browser_inspector_highlighter-04.js]
[browser_inspector_highlighter-by-type.js]
[browser_inspector_highlighter-comments.js]
+[browser_inspector_highlighter-cssgrid_01.js]
[browser_inspector_highlighter-csstransform_01.js]
[browser_inspector_highlighter-csstransform_02.js]
[browser_inspector_highlighter-embed.js]
diff --git a/devtools/client/inspector/test/browser_inspector_highlighter-cssgrid_01.js b/devtools/client/inspector/test/browser_inspector_highlighter-cssgrid_01.js
new file mode 100644
index 000000000000..ef21b88c9a3f
--- /dev/null
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-cssgrid_01.js
@@ -0,0 +1,77 @@
+/* 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";
+
+// Test the creation of the canvas highlighter element of the css grid highlighter.
+
+const TEST_URL = `
+
+
+
cell1
+
cell2
+
cell3
+
cell4
+
+`;
+
+const HIGHLIGHTER_TYPE = "CssGridHighlighter";
+
+add_task(function* () {
+ let {inspector, testActor} = yield openInspectorForURL(
+ "data:text/html;charset=utf-8," + encodeURIComponent(TEST_URL));
+ let front = inspector.inspector;
+ let highlighter = yield front.getHighlighterByType(HIGHLIGHTER_TYPE);
+
+ yield isHiddenByDefault(testActor, highlighter);
+ yield isVisibleWhenShown(testActor, inspector, highlighter);
+
+ yield highlighter.finalize();
+});
+
+function* isHiddenByDefault(testActor, highlighterFront) {
+ info("Checking that the highlighter is hidden by default");
+
+ let hidden = yield testActor.getHighlighterNodeAttribute(
+ "css-grid-canvas", "hidden", highlighterFront);
+ ok(hidden, "The highlighter is hidden by default");
+}
+
+function* isVisibleWhenShown(testActor, inspector, highlighterFront) {
+ info("Asking to show the highlighter on the test node");
+
+ let node = yield getNodeFront("#grid", inspector);
+ yield highlighterFront.show(node);
+
+ let hidden = yield testActor.getHighlighterNodeAttribute(
+ "css-grid-canvas", "hidden", highlighterFront);
+ ok(!hidden, "The highlighter is visible");
+
+ info("Hiding the highlighter");
+ yield highlighterFront.hide();
+
+ hidden = yield testActor.getHighlighterNodeAttribute(
+ "css-grid-canvas", "hidden", highlighterFront);
+ ok(hidden, "The highlighter is hidden");
+}
diff --git a/devtools/server/actors/highlighters.css b/devtools/server/actors/highlighters.css
index 83733ccc8fd5..e4156e41b5ce 100644
--- a/devtools/server/actors/highlighters.css
+++ b/devtools/server/actors/highlighters.css
@@ -404,6 +404,16 @@
shape-rendering: crispEdges;
}
+/* CSS Grid highlighter */
+
+:-moz-native-anonymous .css-grid-canvas {
+ position: absolute;
+ pointer-events: none;
+ top: 0;
+ left: 0;
+ image-rendering: -moz-crisp-edges;
+}
+
/* Eye dropper */
:-moz-native-anonymous .eye-dropper-root {
diff --git a/devtools/server/actors/highlighters.js b/devtools/server/actors/highlighters.js
index a72fa4f3450c..f943be036ba3 100644
--- a/devtools/server/actors/highlighters.js
+++ b/devtools/server/actors/highlighters.js
@@ -656,6 +656,10 @@ const { BoxModelHighlighter } = require("./highlighters/box-model");
register(BoxModelHighlighter);
exports.BoxModelHighlighter = BoxModelHighlighter;
+const { CssGridHighlighter } = require("./highlighters/css-grid");
+register(CssGridHighlighter);
+exports.CssGridHighlighter = CssGridHighlighter;
+
const { CssTransformHighlighter } = require("./highlighters/css-transform");
register(CssTransformHighlighter);
exports.CssTransformHighlighter = CssTransformHighlighter;
diff --git a/devtools/server/actors/highlighters/css-grid.js b/devtools/server/actors/highlighters/css-grid.js
new file mode 100644
index 000000000000..7564c6ec185d
--- /dev/null
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -0,0 +1,289 @@
+/* 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 { extend } = require("sdk/core/heritage");
+const { AutoRefreshHighlighter } = require("./auto-refresh");
+const { CanvasFrameAnonymousContentHelper, createNode } = require("./utils/markup");
+const {
+ getCurrentZoom,
+ setIgnoreLayoutChanges
+} = require("devtools/shared/layout/utils");
+const Services = require("Services");
+
+const CSS_GRID_ENABLED_PREF = "layout.css.grid.enabled";
+const LINE_DASH_ARRAY = [5, 3];
+const LINE_STROKE_STYLE = "#483D88";
+
+/**
+ * The CssGridHighlighter is the class that overlays a visual grid on top of
+ * display:grid elements.
+ *
+ * Usage example:
+ * let h = new CssGridHighlighter(env);
+ * h.show(node, options);
+ * h.hide();
+ * h.destroy();
+ *
+ * Available Options:
+ * - infiniteLines {Boolean}
+ * Displays an infinite line to represent the grid lines
+ */
+function CssGridHighlighter(highlighterEnv) {
+ AutoRefreshHighlighter.call(this, highlighterEnv);
+
+ this.markup = new CanvasFrameAnonymousContentHelper(this.highlighterEnv,
+ this._buildMarkup.bind(this));
+}
+
+CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
+ typeName: "CssGridHighlighter",
+
+ ID_CLASS_PREFIX: "css-grid-",
+
+ _buildMarkup() {
+ let container = createNode(this.win, {
+ attributes: {
+ "class": "highlighter-container"
+ }
+ });
+
+ // We use a