--- a/devtools/server/actors/highlighters/css-grid.js
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -802,32 +802,38 @@ CssGridHighlighter.prototype = extend(Au
let dim = parseFloat(width.toPrecision(6)) +
" \u00D7 " +
parseFloat(height.toPrecision(6));
this.getElement("area-infobar-name").setTextContent(area.name);
this.getElement("area-infobar-dimensions").setTextContent(dim);
let container = this.getElement("area-infobar-container");
- this._moveInfobar(container, x1, x2, y1, y2);
+ this._moveInfobar(container, x1, x2, y1, y2, {
+ position: "bottom",
+ hideIfOffscreen: true
+ });
},
_updateGridCellInfobar(rowNumber, columnNumber, x1, x2, y1, y2) {
let width = x2 - x1;
let height = y2 - y1;
let dim = parseFloat(width.toPrecision(6)) +
" \u00D7 " +
parseFloat(height.toPrecision(6));
let position = `${rowNumber}\/${columnNumber}`;
this.getElement("cell-infobar-position").setTextContent(position);
this.getElement("cell-infobar-dimensions").setTextContent(dim);
let container = this.getElement("cell-infobar-container");
- this._moveInfobar(container, x1, x2, y1, y2);
+ this._moveInfobar(container, x1, x2, y1, y2, {
+ position: "top",
+ hideIfOffscreen: true
+ });
},
/**
* Update the grid information displayed in the grid line info bar.
*
* @param {String} gridLineNames
* Comma-separated string of names for the grid line.
* @param {Number} gridLineNumber
@@ -852,29 +858,29 @@ CssGridHighlighter.prototype = extend(Au
* The first x-coordinate of the grid rectangle.
* @param {Number} x2
* The second x-coordinate of the grid rectangle.
* @param {Number} y1
* The first y-coordinate of the grid rectangle.
* @param {Number} y2
* The second y-coordinate of the grid rectangle.
*/
- _moveInfobar(container, x1, x2, y1, y2) {
+ _moveInfobar(container, x1, x2, y1, y2, options) {
let bounds = {
bottom: y2,
height: y2 - y1,
left: x1,
right: x2,
top: y1,
width: x2 - x1,
x: x1,
y: y1,
};
- moveInfobar(container, bounds, this.win);
+ moveInfobar(container, bounds, this.win, options);
},
/**
* The <canvas>'s position needs to be updated if the page scrolls too much, in order
* to give the illusion that it always covers the viewport.
*/
_scrollUpdate() {
let hasPositionChanged = this.calculateCanvasPosition();
@@ -1375,18 +1381,18 @@ CssGridHighlighter.prototype = extend(Au
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._showGridAreaInfoBar();
this._updateGridAreaInfobar(area, x1, x2, y1, y2);
- this._showGridAreaInfoBar();
}
}
}
let areas = this.getElement("areas");
areas.setAttribute("d", paths.join(" "));
},
@@ -1425,18 +1431,18 @@ CssGridHighlighter.prototype = extend(Au
let path = "M" + x1 + "," + y1 + " " +
"L" + x2 + "," + y1 + " " +
"L" + x2 + "," + y2 + " " +
"L" + x1 + "," + y2;
let cells = this.getElement("cells");
cells.setAttribute("d", path);
+ this._showGridCellInfoBar();
this._updateGridCellInfobar(rowNumber, columnNumber, x1, x2, y1, y2);
- this._showGridCellInfoBar();
},
/**
* Render the grid line name highlight for the given grid fragment index, lineNumber,
* and dimensionType.
*
* @param {Number} gridFragmentIndex
* Index of the grid fragment to render the grid line highlight.
@@ -1474,18 +1480,18 @@ CssGridHighlighter.prototype = extend(Au
let x = dimensionType === COLUMNS
? linePos.start + (bounds.left / currentZoom)
: colXPosition.start + (bounds.left / currentZoom);
let y = dimensionType === ROWS
? linePos.start + (bounds.top / currentZoom)
: rowYPosition.start + (bounds.top / currentZoom);
+ this._showGridLineInfoBar();
this._updateGridLineInfobar(names.join(", "), lineNumber, x, y);
- this._showGridLineInfoBar();
},
/**
* Hide the highlighter, the canvas and the infobars.
*/
_hide() {
setIgnoreLayoutChanges(true);
this._hideGrid();
--- a/devtools/server/actors/highlighters/utils/markup.js
+++ b/devtools/server/actors/highlighters/utils/markup.js
@@ -558,63 +558,72 @@ exports.CanvasFrameAnonymousContentHelpe
* 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.
+ * @param {Object} [options={}]
+ * Advanced options for the infobar.
+ * @param {String} options.position
+ * Force the infobar to be displayed either on "top" or "bottom". Any other value
+ * will be ingnored.
+ * @param {Boolean} options.hideIfOffscreen
+ * If set to `true`, hides the infobar if it's offscreen, instead of automatically
+ * reposition it.
*/
-function moveInfobar(container, bounds, win) {
+function moveInfobar(container, bounds, win, options = {}) {
let zoom = getCurrentZoom(win);
let viewport = getViewportDimensions(win);
let { computedStyle } = container;
- // To simplify, we use the same arrow's size value as margin's value for all four sides.
- let margin = parseFloat(computedStyle
+ let margin = 2;
+ let arrowSize = parseFloat(computedStyle
.getPropertyValue("--highlighter-bubble-arrow-size"));
let containerHeight = parseFloat(computedStyle.getPropertyValue("height"));
let containerWidth = parseFloat(computedStyle.getPropertyValue("width"));
let containerHalfWidth = containerWidth / 2;
let viewportWidth = viewport.width * zoom;
let viewportHeight = viewport.height * zoom;
let { pageXOffset, pageYOffset } = win;
pageYOffset *= zoom;
pageXOffset *= zoom;
- containerHeight += margin;
// Defines the boundaries for the infobar.
let topBoundary = margin;
- let bottomBoundary = viewportHeight - containerHeight;
+ let bottomBoundary = viewportHeight - containerHeight - margin - 1;
let leftBoundary = containerHalfWidth + margin;
let rightBoundary = viewportWidth - containerHalfWidth - margin;
// Set the default values.
- let top = bounds.y - containerHeight;
- let bottom = bounds.bottom + margin;
+ let top = bounds.y - containerHeight - arrowSize;
+ let bottom = bounds.bottom + margin + arrowSize;
let left = bounds.x + bounds.width / 2;
let isOverlapTheNode = false;
let positionAttribute = "top";
let position = "absolute";
// Here we start the math.
// We basically want to position absolutely the infobar, except when is pointing to a
// node that is offscreen or partially offscreen, in a way that the infobar can't
// be placed neither on top nor on bottom.
// In such cases, the infobar will overlap the node, and to limit the latency given
// by APZ (See Bug 1312103) it will be positioned as "fixed".
// It's a sort of "position: sticky" (but positioned as absolute instead of relative).
let canBePlacedOnTop = top >= pageYOffset;
let canBePlacedOnBottom = bottomBoundary + pageYOffset - bottom > 0;
+ let forcedOnTop = options.position === "top";
+ let forcedOnBottom = options.position === "bottom";
- if (!canBePlacedOnTop && canBePlacedOnBottom) {
+ if ((!canBePlacedOnTop && canBePlacedOnBottom && !forcedOnTop) || forcedOnBottom) {
top = bottom;
positionAttribute = "bottom";
}
let isOffscreenOnTop = top < topBoundary + pageYOffset;
let isOffscreenOnBottom = top > bottomBoundary + pageYOffset;
let isOffscreenOnLeft = left < leftBoundary + pageXOffset;
let isOffscreenOnRight = left > rightBoundary + pageXOffset;
@@ -625,17 +634,20 @@ function moveInfobar(container, bounds,
} else if (isOffscreenOnBottom) {
top = bottomBoundary;
isOverlapTheNode = true;
} else if (isOffscreenOnLeft || isOffscreenOnRight) {
isOverlapTheNode = true;
top -= pageYOffset;
}
- if (isOverlapTheNode) {
+ if (isOverlapTheNode && options.hideIfOffscreen) {
+ container.setAttribute("hidden", "true");
+ return;
+ } else if (isOverlapTheNode) {
left = Math.min(Math.max(leftBoundary, left - pageXOffset), rightBoundary);
position = "fixed";
container.setAttribute("hide-arrow", "true");
} else {
position = "absolute";
container.removeAttribute("hide-arrow");
}