Bug 1414362 - Outline the flex container and items in the flexbox highlighter. r=pbro
MozReview-Commit-ID: Eg3dSTKPt3P
--- a/devtools/server/actors/highlighters/css-grid.js
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -3,16 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Services = require("Services");
const { AutoRefreshHighlighter } = require("./auto-refresh");
const {
CANVAS_SIZE,
+ DEFAULT_COLOR,
drawBubbleRect,
drawLine,
drawRect,
drawRoundedRect,
getBoundsFromPoints,
getCurrentMatrix,
getPathDescriptionFromPoints,
getPointsFromDiagonal,
@@ -34,18 +35,16 @@ const {
const { stringifyGridFragments } = require("devtools/server/actors/utils/css-grid-utils");
const { LocalizationHelper } = require("devtools/shared/l10n");
const LAYOUT_STRINGS_URI = "devtools/client/locales/layout.properties";
const LAYOUT_L10N = new LocalizationHelper(LAYOUT_STRINGS_URI);
const NEGATIVE_LINE_NUMBERS_PREF = "devtools.gridinspector.showNegativeLineNumbers";
-const DEFAULT_GRID_COLOR = "#4B0082";
-
const COLUMNS = "cols";
const ROWS = "rows";
const GRID_FONT_SIZE = 10;
const GRID_FONT_FAMILY = "sans-serif";
const GRID_AREA_NAME_FONT_SIZE = "20";
const GRID_LINES_PROPERTIES = {
@@ -421,17 +420,17 @@ class CssGridHighlighter extends AutoRef
return this.canvas.getCanvasContext("2d");
}
get canvas() {
return this.getElement("canvas");
}
get color() {
- return this.options.color || DEFAULT_GRID_COLOR;
+ return this.options.color || DEFAULT_COLOR;
}
/**
* Gets the grid gap pattern used to render the gap regions based on the device
* pixel ratio given.
*
* @param {Number} devicePixelRatio
* The device pixel ratio we want the pattern for.
--- a/devtools/server/actors/highlighters/flexbox.js
+++ b/devtools/server/actors/highlighters/flexbox.js
@@ -2,28 +2,43 @@
* 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 { AutoRefreshHighlighter } = require("./auto-refresh");
const {
CANVAS_SIZE,
+ DEFAULT_COLOR,
+ drawRect,
getCurrentMatrix,
updateCanvasElement,
updateCanvasPosition,
} = require("./utils/canvas");
const {
CanvasFrameAnonymousContentHelper,
createNode,
} = require("./utils/markup");
const {
+ getAdjustedQuads,
+ getDisplayPixelRatio,
setIgnoreLayoutChanges,
} = require("devtools/shared/layout/utils");
+const FLEXBOX_LINES_PROPERTIES = {
+ "edge": {
+ lineDash: [0, 0],
+ alpha: 1,
+ },
+ "item": {
+ lineDash: [2, 2],
+ alpha: 1,
+ },
+};
+
class FlexboxHighlighter extends AutoRefreshHighlighter {
constructor(highlighterEnv) {
super(highlighterEnv);
this.ID_CLASS_PREFIX = "flexbox-";
this.markup = new CanvasFrameAnonymousContentHelper(this.highlighterEnv,
this._buildMarkup.bind(this));
@@ -104,16 +119,31 @@ class FlexboxHighlighter extends AutoRef
get ctx() {
return this.canvas.getCanvasContext("2d");
}
getElement(id) {
return this.markup.getElement(this.ID_CLASS_PREFIX + id);
}
+ /**
+ * The AutoRefreshHighlighter's _hasMoved method returns true only if the
+ * element's quads have changed. Override it so it also returns true if the
+ * element and its flex items have changed.
+ */
+ _hasMoved() {
+ let hasMoved = AutoRefreshHighlighter.prototype._hasMoved.call(this);
+
+ // TODO: Implement a check of old and new flex container and flex items to react
+ // to any alignment and size changes. This is blocked on Bug 1414920 that implements
+ // a platform API to retrieve the flex container and flex item information.
+
+ return hasMoved;
+ }
+
_hide() {
setIgnoreLayoutChanges(true);
this._hideFlexbox();
setIgnoreLayoutChanges(false, this.highlighterEnv.document.documentElement);
}
_hideFlexbox() {
this.getElement("canvas").setAttribute("hidden", "true");
@@ -157,16 +187,87 @@ class FlexboxHighlighter extends AutoRef
* next time.
*/
onWillNavigate({ isTopLevel }) {
if (isTopLevel) {
this.hide();
}
}
+ renderFlexContainer() {
+ if (!this.currentQuads.content || !this.currentQuads.content[0]) {
+ return;
+ }
+
+ let { devicePixelRatio } = this.win;
+ let lineWidth = getDisplayPixelRatio(this.win);
+ let offset = (lineWidth / 2) % 1;
+
+ let canvasX = Math.round(this._canvasPosition.x * devicePixelRatio);
+ let canvasY = Math.round(this._canvasPosition.y * devicePixelRatio);
+
+ this.ctx.save();
+ this.ctx.translate(offset - canvasX, offset - canvasY);
+ this.ctx.setLineDash(FLEXBOX_LINES_PROPERTIES.edge.lineDash);
+ this.ctx.globalAlpha = FLEXBOX_LINES_PROPERTIES.edge.alpha;
+ this.ctx.lineWidth = lineWidth;
+ this.ctx.strokeStyle = DEFAULT_COLOR;
+
+ let { bounds } = this.currentQuads.content[0];
+
+ drawRect(this.ctx, 0, 0, bounds.width, bounds.height, this.currentMatrix);
+
+ this.ctx.stroke();
+ this.ctx.restore();
+ }
+
+ renderFlexItems() {
+ if (!this.currentQuads.content || !this.currentQuads.content[0]) {
+ return;
+ }
+
+ let { devicePixelRatio } = this.win;
+ let lineWidth = getDisplayPixelRatio(this.win);
+ let offset = (lineWidth / 2) % 1;
+
+ let canvasX = Math.round(this._canvasPosition.x * devicePixelRatio);
+ let canvasY = Math.round(this._canvasPosition.y * devicePixelRatio);
+
+ this.ctx.save();
+ this.ctx.translate(offset - canvasX, offset - canvasY);
+ this.ctx.setLineDash(FLEXBOX_LINES_PROPERTIES.item.lineDash);
+ this.ctx.globalAlpha = FLEXBOX_LINES_PROPERTIES.item.alpha;
+ this.ctx.lineWidth = lineWidth;
+ this.ctx.strokeStyle = DEFAULT_COLOR;
+
+ let { bounds } = this.currentQuads.content[0];
+ let flexItems = this.currentNode.children;
+
+ // TODO: Utilize the platform API that will be implemented in Bug 1414290 to
+ // retrieve the flex item properties.
+ for (let flexItem of flexItems) {
+ let quads = getAdjustedQuads(this.win, flexItem, "content");
+ if (!quads.length) {
+ continue;
+ }
+
+ // Adjust the flex item bounds relative to the current quads.
+ let { bounds: flexItemBounds } = quads[0];
+ let left = flexItemBounds.left - bounds.left;
+ let top = flexItemBounds.top - bounds.top;
+ let right = flexItemBounds.right - bounds.left;
+ let bottom = flexItemBounds.bottom - bounds.top;
+
+ drawRect(this.ctx, left, top, right, bottom, this.currentMatrix);
+ this.ctx.stroke();
+ }
+
+ this.ctx.restore();
+ }
+
_update() {
setIgnoreLayoutChanges(true);
let root = this.getElement("root");
// Hide the root element and force the reflow in order to get the proper window's
// dimensions without increasing them.
root.setAttribute("style", "display: none");
@@ -179,16 +280,19 @@ class FlexboxHighlighter extends AutoRef
updateCanvasElement(this.canvas, this._canvasPosition, this.win.devicePixelRatio);
// Update the current matrix used in our canvas' rendering
let { currentMatrix, hasNodeTransformations } = getCurrentMatrix(this.currentNode,
this.win);
this.currentMatrix = currentMatrix;
this.hasNodeTransformations = hasNodeTransformations;
+ this.renderFlexContainer();
+ this.renderFlexItems();
+
this._showFlexbox();
root.setAttribute("style",
`position: absolute; width: ${width}px; height: ${height}px; overflow: hidden`);
setIgnoreLayoutChanges(false, this.highlighterEnv.document.documentElement);
return true;
}
--- a/devtools/server/actors/highlighters/utils/canvas.js
+++ b/devtools/server/actors/highlighters/utils/canvas.js
@@ -30,16 +30,19 @@ const { getViewportDimensions } = requir
//
// Note:
// Once bug 1232491 lands, we could try to refactor this code to use the values from
// the displayport API instead.
//
// Using a fixed value should also solve bug 1348293.
const CANVAS_SIZE = 4096;
+// The default color used for the canvas' font, fill and stroke colors.
+const DEFAULT_COLOR = "#9400FF";
+
/**
* Draws an arrow-bubble rectangle in the provided canvas context.
*
* @param {CanvasRenderingContext2D} ctx
* The 2D canvas context.
* @param {Number} x
* The x-axis origin of the rectangle.
* @param {Number} y
@@ -421,16 +424,17 @@ function updateCanvasPosition(canvasPosi
// Update the canvas position with the calculated canvasX and canvasY positions.
canvasPosition.x = canvasX;
canvasPosition.y = canvasY;
return hasUpdated;
}
exports.CANVAS_SIZE = CANVAS_SIZE;
+exports.DEFAULT_COLOR = DEFAULT_COLOR;
exports.drawBubbleRect = drawBubbleRect;
exports.drawLine = drawLine;
exports.drawRect = drawRect;
exports.drawRoundedRect = drawRoundedRect;
exports.getBoundsFromPoints = getBoundsFromPoints;
exports.getCurrentMatrix = getCurrentMatrix;
exports.getPathDescriptionFromPoints = getPathDescriptionFromPoints;
exports.getPointsFromDiagonal = getPointsFromDiagonal;