зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1501226 - Support for CSS transforms in the Flexbox highlighter r=gl
In many places we were using bounds to calculate an objects dimensions but that obviously doesn't work when an object is rotated e.g. {F588303} Also, we were using `getBoxQuads()`, which gives the co-ordinates of the translated object. We were then applying the transform matrix to the canvas even though the coordinates came from the object **after** it was already transformed. Anyhow, now we get the dimensions of objects as if they are not transformed and then apply the transformation matrix, which gives a great result every time. Differential Revision: https://phabricator.services.mozilla.com/D9805 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
1b50b597e6
Коммит
af575ff9cd
|
@ -164,10 +164,11 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
|||
// Clear the pattern cache to avoid dead object exceptions (Bug 1342051).
|
||||
this.clearCache();
|
||||
|
||||
this.axes = null;
|
||||
this.crossAxisDirection = null;
|
||||
this.flexData = null;
|
||||
this.mainAxisDirection = null;
|
||||
this.crossAxisDirection = null;
|
||||
this.axes = null;
|
||||
this.transform = null;
|
||||
|
||||
AutoRefreshHighlighter.prototype.destroy.call(this);
|
||||
}
|
||||
|
@ -337,6 +338,10 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
|||
this.justifyContentValue = this.computedStyle.justifyContent;
|
||||
const newJustifyContent = this.justifyContentValue;
|
||||
|
||||
const oldTransform = this.transformValue;
|
||||
this.transformValue = this.computedStyle.transform;
|
||||
const newTransform = this.transformValue;
|
||||
|
||||
return hasMoved ||
|
||||
hasFlexDataChanged ||
|
||||
oldAlignItems !== newAlignItems ||
|
||||
|
@ -344,7 +349,8 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
|||
oldFlexWrap !== newFlexWrap ||
|
||||
oldJustifyContent !== newJustifyContent ||
|
||||
oldCrossAxisDirection !== newCrossAxisDirection ||
|
||||
oldMainAxisDirection !== newMainAxisDirection;
|
||||
oldMainAxisDirection !== newMainAxisDirection ||
|
||||
oldTransform !== newTransform;
|
||||
}
|
||||
|
||||
_hide() {
|
||||
|
@ -530,8 +536,8 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
|||
this.ctx.strokeStyle = this.color;
|
||||
this.ctx.fillStyle = this.getFlexContainerPattern(devicePixelRatio);
|
||||
|
||||
const { bounds } = this.currentQuads.content[0];
|
||||
drawRect(this.ctx, 0, 0, bounds.width, bounds.height, this.currentMatrix);
|
||||
const { clientWidth, clientHeight } = this.currentNode;
|
||||
drawRect(this.ctx, 0, 0, clientWidth, clientHeight, this.currentMatrix);
|
||||
|
||||
// Find current angle of outer flex element by measuring the angle of two arbitrary
|
||||
// points, then rotate canvas, so the hash pattern stays 45deg to the boundary.
|
||||
|
@ -556,6 +562,7 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
|||
const zoom = getCurrentZoom(this.win);
|
||||
const canvasX = Math.round(this._canvasPosition.x * devicePixelRatio * zoom);
|
||||
const canvasY = Math.round(this._canvasPosition.y * devicePixelRatio * zoom);
|
||||
const containerOffsets = getNodeRect(this.currentNode);
|
||||
|
||||
this.ctx.save();
|
||||
this.ctx.translate(offset - canvasX, offset - canvasY);
|
||||
|
@ -563,21 +570,18 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
|||
this.ctx.lineWidth = lineWidth;
|
||||
this.ctx.strokeStyle = this.color;
|
||||
|
||||
const { bounds } = this.currentQuads.content[0];
|
||||
|
||||
for (const flexLine of this.flexData.lines) {
|
||||
for (const flexItem of flexLine.items) {
|
||||
const quads = flexItem.quads;
|
||||
if (!quads.length) {
|
||||
const offsets = getNodeRect(flexItem.node);
|
||||
|
||||
if (!offsets) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Adjust the flex item bounds relative to the current quads.
|
||||
const { bounds: flexItemBounds } = quads[0];
|
||||
const left = Math.round(flexItemBounds.left / zoom - bounds.left);
|
||||
const top = Math.round(flexItemBounds.top / zoom - bounds.top);
|
||||
const right = Math.round(flexItemBounds.right / zoom - bounds.left);
|
||||
const bottom = Math.round(flexItemBounds.bottom / zoom - bounds.top);
|
||||
const left = offsets.left - containerOffsets.left;
|
||||
const top = offsets.top - containerOffsets.top;
|
||||
const right = offsets.right - containerOffsets.left;
|
||||
const bottom = offsets.bottom - containerOffsets.top;
|
||||
|
||||
clearRect(this.ctx, left, top, right, bottom, this.currentMatrix);
|
||||
drawRect(this.ctx, left, top, right, bottom, this.currentMatrix);
|
||||
|
@ -599,15 +603,14 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
|||
const zoom = getCurrentZoom(this.win);
|
||||
const canvasX = Math.round(this._canvasPosition.x * devicePixelRatio * zoom);
|
||||
const canvasY = Math.round(this._canvasPosition.y * devicePixelRatio * zoom);
|
||||
const { clientWidth, clientHeight } = this.currentNode;
|
||||
const options = { matrix: this.currentMatrix };
|
||||
|
||||
this.ctx.save();
|
||||
this.ctx.translate(offset - canvasX, offset - canvasY);
|
||||
this.ctx.lineWidth = lineWidth;
|
||||
this.ctx.strokeStyle = this.color;
|
||||
|
||||
const { bounds } = this.currentQuads.content[0];
|
||||
const options = { matrix: this.currentMatrix };
|
||||
|
||||
for (const flexLine of this.flexData.lines) {
|
||||
const { crossStart, crossSize } = flexLine;
|
||||
|
||||
|
@ -616,56 +619,56 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
|||
case "horizontal-lr vertical-bt":
|
||||
case "horizontal-rl vertical-tb":
|
||||
case "horizontal-rl vertical-bt":
|
||||
clearRect(this.ctx, 0, crossStart, bounds.width, crossStart + crossSize,
|
||||
clearRect(this.ctx, 0, crossStart, clientWidth, crossStart + crossSize,
|
||||
this.currentMatrix);
|
||||
|
||||
// Avoid drawing the start flex line when they overlap with the flex container.
|
||||
if (crossStart != 0) {
|
||||
drawLine(this.ctx, 0, crossStart, bounds.width, crossStart, options);
|
||||
drawLine(this.ctx, 0, crossStart, clientWidth, crossStart, options);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
|
||||
// Avoid drawing the end flex line when they overlap with the flex container.
|
||||
if (bounds.height - crossStart - crossSize >= lineWidth) {
|
||||
drawLine(this.ctx, 0, crossStart + crossSize, bounds.width,
|
||||
if (clientHeight - crossStart - crossSize >= lineWidth) {
|
||||
drawLine(this.ctx, 0, crossStart + crossSize, clientWidth,
|
||||
crossStart + crossSize, options);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
break;
|
||||
case "vertical-tb horizontal-lr":
|
||||
case "vertical-bt horizontal-rl":
|
||||
clearRect(this.ctx, crossStart, 0, crossStart + crossSize, bounds.height,
|
||||
clearRect(this.ctx, crossStart, 0, crossStart + crossSize, clientHeight,
|
||||
this.currentMatrix);
|
||||
|
||||
// Avoid drawing the start flex line when they overlap with the flex container.
|
||||
if (crossStart != 0) {
|
||||
drawLine(this.ctx, crossStart, 0, crossStart, bounds.height, options);
|
||||
drawLine(this.ctx, crossStart, 0, crossStart, clientHeight, options);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
|
||||
// Avoid drawing the end flex line when they overlap with the flex container.
|
||||
if (bounds.width - crossStart - crossSize >= lineWidth) {
|
||||
if (clientWidth - crossStart - crossSize >= lineWidth) {
|
||||
drawLine(this.ctx, crossStart + crossSize, 0, crossStart + crossSize,
|
||||
bounds.height, options);
|
||||
clientHeight, options);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
break;
|
||||
case "vertical-bt horizontal-lr":
|
||||
case "vertical-tb horizontal-rl":
|
||||
clearRect(this.ctx, bounds.width - crossStart, 0,
|
||||
bounds.width - crossStart - crossSize, bounds.height, this.currentMatrix);
|
||||
clearRect(this.ctx, clientWidth - crossStart, 0,
|
||||
clientWidth - crossStart - crossSize, clientHeight, this.currentMatrix);
|
||||
|
||||
// Avoid drawing the start flex line when they overlap with the flex container.
|
||||
if (crossStart != 0) {
|
||||
drawLine(this.ctx, bounds.width - crossStart, 0, bounds.width - crossStart,
|
||||
bounds.height, options);
|
||||
drawLine(this.ctx, clientWidth - crossStart, 0, clientWidth - crossStart,
|
||||
clientHeight, options);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
|
||||
// Avoid drawing the end flex line when they overlap with the flex container.
|
||||
if (bounds.width - crossStart - crossSize >= lineWidth) {
|
||||
drawLine(this.ctx, bounds.width - crossStart - crossSize, 0,
|
||||
bounds.width - crossStart - crossSize, bounds.height, options);
|
||||
if (clientWidth - crossStart - crossSize >= lineWidth) {
|
||||
drawLine(this.ctx, clientWidth - crossStart - crossSize, 0,
|
||||
clientWidth - crossStart - crossSize, clientHeight, options);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
break;
|
||||
|
@ -683,27 +686,27 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
|||
return;
|
||||
}
|
||||
|
||||
const zoom = getCurrentZoom(this.win);
|
||||
const { bounds } = this.currentQuads.content[0];
|
||||
const lineWidth = getDisplayPixelRatio(this.win);
|
||||
const { clientWidth, clientHeight } = this.currentNode;
|
||||
const containerOffsets = getNodeRect(this.currentNode);
|
||||
|
||||
// Draw a justify content pattern over the whole flex container.
|
||||
this.drawJustifyContent(0, 0, bounds.width, bounds.height, this.currentMatrix);
|
||||
this.drawJustifyContent(0, 0, clientWidth, clientHeight);
|
||||
|
||||
for (const flexLine of this.flexData.lines) {
|
||||
const { crossStart, crossSize } = flexLine;
|
||||
|
||||
for (const flexItem of flexLine.items) {
|
||||
const quads = flexItem.quads;
|
||||
if (!quads.length) {
|
||||
const offsets = getNodeRect(flexItem.node);
|
||||
|
||||
if (!offsets) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Adjust the flex item bounds relative to the current quads.
|
||||
const { bounds: flexItemBounds } = quads[0];
|
||||
const left = Math.round(flexItemBounds.left / zoom - bounds.left);
|
||||
const top = Math.round(flexItemBounds.top / zoom - bounds.top);
|
||||
const right = Math.round(flexItemBounds.right / zoom - bounds.left);
|
||||
const bottom = Math.round(flexItemBounds.bottom / zoom - bounds.top);
|
||||
const left = offsets.left - containerOffsets.left;
|
||||
const top = offsets.top - containerOffsets.top;
|
||||
const right = offsets.right - containerOffsets.left;
|
||||
const bottom = offsets.bottom - containerOffsets.top;
|
||||
|
||||
// Clear a rectangular are covering the alignment container.
|
||||
switch (this.axes) {
|
||||
|
@ -711,18 +714,22 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
|||
case "horizontal-lr vertical-bt":
|
||||
case "horizontal-rl vertical-tb":
|
||||
case "horizontal-rl vertical-bt":
|
||||
clearRect(this.ctx, left, Math.round(crossStart) + 2, right,
|
||||
Math.round(crossStart + crossSize) - 2, this.currentMatrix);
|
||||
clearRect(this.ctx,
|
||||
left, Math.round(crossStart) + 2 * lineWidth, right,
|
||||
Math.round(crossStart + crossSize) - 2 * lineWidth, this.currentMatrix);
|
||||
break;
|
||||
case "vertical-tb horizontal-lr":
|
||||
case "vertical-bt horizontal-rl":
|
||||
clearRect(this.ctx, Math.round(crossStart) + 1, top,
|
||||
Math.round(crossStart + crossSize), bottom, this.currentMatrix);
|
||||
clearRect(this.ctx,
|
||||
Math.round(crossStart) + lineWidth * 2, top,
|
||||
Math.round(crossStart + crossSize) - lineWidth, bottom, this.currentMatrix);
|
||||
break;
|
||||
case "vertical-bt horizontal-lr":
|
||||
case "vertical-tb horizontal-rl":
|
||||
clearRect(this.ctx, Math.round(bounds.width - crossStart - crossSize) + 1,
|
||||
top, Math.round(bounds.width - crossStart), bottom, this.currentMatrix);
|
||||
clearRect(this.ctx,
|
||||
Math.round(clientWidth - crossStart - crossSize) + lineWidth * 2, top,
|
||||
Math.round(clientWidth - crossStart) - lineWidth, bottom,
|
||||
this.currentMatrix);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -888,4 +895,55 @@ function compareFlexData(oldFlexData, newFlexData) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the untransformed coordinates for a node.
|
||||
*
|
||||
* @param {DOMNode} node
|
||||
* The node for which the coordinates are to be returned.
|
||||
*
|
||||
* @returns {Object}
|
||||
* {
|
||||
* left: left, // The absolute left coordinates of the node.
|
||||
* top: top, // The absolute top coordinates of the node.
|
||||
* right: right, // The absolute right coordinates of the node.
|
||||
* bottom: bottom, // The absolute left coordinates of the node.
|
||||
* width: width, // The width of the node.
|
||||
* height, // The Height of the node.
|
||||
* }
|
||||
*/
|
||||
function getNodeRect(node) {
|
||||
if (node.nodeType === node.TEXT_NODE) {
|
||||
// For now ignore text node flex items because we cannot get the
|
||||
// untransformed position and dimensions of a text node
|
||||
// (see https://bugzil.la/1505079).
|
||||
return null;
|
||||
}
|
||||
|
||||
const win = node.ownerGlobal;
|
||||
const style = win.getComputedStyle(node);
|
||||
const borderLeft = parseInt(style.borderLeftWidth, 10) || 0;
|
||||
const borderTop = parseInt(style.borderTopWidth, 10) || 0;
|
||||
const width = node.offsetWidth;
|
||||
const height = node.offsetHeight;
|
||||
|
||||
let left = 0;
|
||||
let top = 0;
|
||||
|
||||
while (node) {
|
||||
left += node.offsetLeft - node.scrollLeft + node.clientLeft;
|
||||
top += node.offsetTop - node.scrollTop + node.clientTop;
|
||||
|
||||
node = node.offsetParent;
|
||||
}
|
||||
|
||||
return {
|
||||
left: left - borderLeft,
|
||||
top: top - borderTop,
|
||||
right: left + width - borderLeft,
|
||||
bottom: top + height - borderTop,
|
||||
width: width,
|
||||
height: height,
|
||||
};
|
||||
}
|
||||
|
||||
exports.FlexboxHighlighter = FlexboxHighlighter;
|
||||
|
|
Загрузка…
Ссылка в новой задаче