зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1411645 - Shapes highlighter: resize on one axis in transform mode for polygon and ellipse. r=pbro
MozReview-Commit-ID: 9Td88QCRPQg --HG-- extra : rebase_source : b5aaa71335964aad5d60a3bd7b623d9ec64341e6
This commit is contained in:
Родитель
0438db5068
Коммит
47961d34b3
|
@ -84,6 +84,7 @@ skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keybo
|
|||
[browser_inspector_highlighter-cssshape_04.js]
|
||||
[browser_inspector_highlighter-cssshape_05.js]
|
||||
[browser_inspector_highlighter-cssshape_06.js]
|
||||
[browser_inspector_highlighter-cssshape_07.js]
|
||||
[browser_inspector_highlighter-cssshape_iframe_01.js]
|
||||
[browser_inspector_highlighter-csstransform_01.js]
|
||||
[browser_inspector_highlighter-csstransform_02.js]
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/* 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 that shapes are updated correctly for scaling on one axis in transform mode.
|
||||
|
||||
const TEST_URL = URL_ROOT + "doc_inspector_highlighter_cssshapes.html";
|
||||
const HIGHLIGHTER_TYPE = "ShapesHighlighter";
|
||||
const SHAPE_IDS = ["#polygon-transform", "#ellipse"];
|
||||
|
||||
add_task(function* () {
|
||||
let inspector = yield openInspectorForURL(TEST_URL);
|
||||
let helper = yield getHighlighterHelperFor(HIGHLIGHTER_TYPE)(inspector);
|
||||
let {testActor} = inspector;
|
||||
|
||||
yield testOneDimScale(testActor, helper);
|
||||
|
||||
helper.finalize();
|
||||
});
|
||||
|
||||
function* testOneDimScale(testActor, helper) {
|
||||
for (let shape of SHAPE_IDS) {
|
||||
info(`Displaying ${shape}`);
|
||||
yield helper.show(shape, {mode: "cssClipPath", transformMode: true});
|
||||
let { mouse } = helper;
|
||||
|
||||
let { top, left, width, height } = yield getBoundingBoxInPx(testActor, helper, shape);
|
||||
|
||||
// if the top or left edges are not visible, move the shape so it is.
|
||||
if (top < 0 || left < 0) {
|
||||
let x = left + width / 2;
|
||||
let y = top + height / 2;
|
||||
let dx = Math.max(0, -left);
|
||||
let dy = Math.max(0, -top);
|
||||
yield mouse.down(x, y, shape);
|
||||
yield mouse.move(x + dx, y + dy, shape);
|
||||
yield mouse.up(x + dx, y + dy, shape);
|
||||
yield testActor.reflow();
|
||||
left += dx;
|
||||
top += dy;
|
||||
}
|
||||
let dx = width / 10;
|
||||
let dy = height / 10;
|
||||
|
||||
info("Scaling from w");
|
||||
yield mouse.down(left, top + height / 2, shape);
|
||||
yield mouse.move(left + dx, top + height / 2, shape);
|
||||
yield mouse.up(left + dx, top + height / 2, shape);
|
||||
yield testActor.reflow();
|
||||
|
||||
let wBB = yield getBoundingBoxInPx(testActor, helper, shape);
|
||||
is(wBB.top, top, `${shape} top not moved down after w scale`);
|
||||
isnot(wBB.left, left, `${shape} left moved right after w scale`);
|
||||
isnot(wBB.width, width, `${shape} width reduced after w scale`);
|
||||
is(wBB.height, height, `${shape} height not reduced after w scale`);
|
||||
|
||||
info("Scaling from e");
|
||||
yield mouse.down(wBB.left + wBB.width, wBB.top + wBB.height / 2, shape);
|
||||
yield mouse.move(wBB.left + wBB.width - dx, wBB.top + wBB.height / 2, shape);
|
||||
yield mouse.up(wBB.left + wBB.width - dx, wBB.top + wBB.height / 2, shape);
|
||||
yield testActor.reflow();
|
||||
|
||||
let eBB = yield getBoundingBoxInPx(testActor, helper, shape);
|
||||
is(eBB.top, wBB.top, `${shape} top not moved down after e scale`);
|
||||
is(eBB.left, wBB.left, `${shape} left not moved right after e scale`);
|
||||
isnot(eBB.width, wBB.width, `${shape} width reduced after e scale`);
|
||||
is(eBB.height, wBB.height, `${shape} height not reduced after e scale`);
|
||||
|
||||
info("Scaling from s");
|
||||
yield mouse.down(eBB.left + eBB.width / 2, eBB.top + eBB.height, shape);
|
||||
yield mouse.move(eBB.left + eBB.width / 2, eBB.top + eBB.height - dy, shape);
|
||||
yield mouse.up(eBB.left + eBB.width / 2, eBB.top + eBB.height - dy, shape);
|
||||
yield testActor.reflow();
|
||||
|
||||
let sBB = yield getBoundingBoxInPx(testActor, helper, shape);
|
||||
is(sBB.top, eBB.top, `${shape} top not moved down after w scale`);
|
||||
is(sBB.left, eBB.left, `${shape} left not moved right after w scale`);
|
||||
is(sBB.width, eBB.width, `${shape} width not reduced after w scale`);
|
||||
isnot(sBB.height, eBB.height, `${shape} height reduced after w scale`);
|
||||
|
||||
info("Scaling from n");
|
||||
yield mouse.down(sBB.left + sBB.width / 2, sBB.top, shape);
|
||||
yield mouse.move(sBB.left + sBB.width / 2, sBB.top + dy, shape);
|
||||
yield mouse.up(sBB.left + sBB.width / 2, sBB.top + dy, shape);
|
||||
yield testActor.reflow();
|
||||
|
||||
let nBB = yield getBoundingBoxInPx(testActor, helper, shape);
|
||||
isnot(nBB.top, sBB.top, `${shape} top moved down after n scale`);
|
||||
is(nBB.left, sBB.left, `${shape} left not moved right after n scale`);
|
||||
is(nBB.width, sBB.width, `${shape} width reduced after n scale`);
|
||||
isnot(nBB.height, sBB.height, `${shape} height not reduced after n scale`);
|
||||
}
|
||||
}
|
||||
|
||||
function* getBoundingBoxInPx(testActor, helper, shape = "#polygon") {
|
||||
let bbTop = parseFloat(yield helper.getElementAttribute("shapes-bounding-box", "y"));
|
||||
let bbLeft = parseFloat(yield helper.getElementAttribute("shapes-bounding-box", "x"));
|
||||
let bbWidth = parseFloat(yield helper.getElementAttribute("shapes-bounding-box",
|
||||
"width"));
|
||||
let bbHeight = parseFloat(yield helper.getElementAttribute("shapes-bounding-box",
|
||||
"height"));
|
||||
|
||||
let quads = yield testActor.getAllAdjustedQuads(shape);
|
||||
let { width, height } = quads.content[0].bounds;
|
||||
let computedStyle = yield helper.highlightedNode.getComputedStyle();
|
||||
let paddingTop = parseFloat(computedStyle["padding-top"].value);
|
||||
let paddingLeft = parseFloat(computedStyle["padding-left"].value);
|
||||
|
||||
return {
|
||||
top: paddingTop + height * bbTop / 100,
|
||||
left: paddingLeft + width * bbLeft / 100,
|
||||
width: width * bbWidth / 100,
|
||||
height: height * bbHeight / 100
|
||||
};
|
||||
}
|
|
@ -526,31 +526,39 @@ class ShapesHighlighter extends AutoRefreshHighlighter {
|
|||
let { width, height } = this.zoomAdjustedDimensions;
|
||||
|
||||
// How much points on each axis should be translated before scaling
|
||||
let transX = (type === "scale-se" || type === "scale-ne") ?
|
||||
let transX = (type === "scale-se" || type === "scale-ne" || type === "scale-e") ?
|
||||
minX / 100 * width : maxX / 100 * width;
|
||||
let transY = (type === "scale-se" || type === "scale-sw") ?
|
||||
let transY = (type === "scale-se" || type === "scale-sw" || type === "scale-s") ?
|
||||
minY / 100 * height : maxY / 100 * height;
|
||||
|
||||
let { percentX, percentY } = this.convertPageCoordsToPercent(x, y);
|
||||
let { percentX: percentPageX,
|
||||
percentY: percentPageY } = this.convertPageCoordsToPercent(pageX, pageY);
|
||||
// distance from original click to current mouse position, in %
|
||||
let distanceX = (type === "scale-se" || type === "scale-ne") ?
|
||||
let distanceX = (type === "scale-se" || type === "scale-ne" || type === "scale-e") ?
|
||||
percentPageX - percentX : percentX - percentPageX;
|
||||
let distanceY = (type === "scale-se" || type === "scale-sw") ?
|
||||
let distanceY = (type === "scale-se" || type === "scale-sw" || type === "scale-s") ?
|
||||
percentPageY - percentY : percentY - percentPageY;
|
||||
|
||||
// scale = 1 + proportion of distance to bounding box width/height of shape
|
||||
let scaleX = 1 + distanceX / (maxX - minX);
|
||||
let scaleY = 1 + distanceY / (maxY - minY);
|
||||
let scale = (scaleX + scaleY) / 2;
|
||||
let axis = "xy";
|
||||
if (type === "scale-e" || type === "scale-w") {
|
||||
scale = scaleX;
|
||||
axis = "x";
|
||||
} else if (type === "scale-n" || type === "scale-s") {
|
||||
scale = scaleY;
|
||||
axis = "y";
|
||||
}
|
||||
|
||||
if (this.shapeType === "polygon") {
|
||||
this._scalePolygon(pageX, pageY, transX, transY, scale);
|
||||
this._scalePolygon(pageX, pageY, transX, transY, scale, axis);
|
||||
} else if (this.shapeType === "circle") {
|
||||
this._scaleCircle(pageX, pageY, transX, transY, scale);
|
||||
} else if (this.shapeType === "ellipse") {
|
||||
this._scaleEllipse(pageX, pageY, transX, transY, scale);
|
||||
this._scaleEllipse(pageX, pageY, transX, transY, scale, axis);
|
||||
} else if (this.shapeType === "inset") {
|
||||
this._scaleInset(pageX, pageY, transX, transY, scale);
|
||||
}
|
||||
|
@ -564,15 +572,16 @@ class ShapesHighlighter extends AutoRefreshHighlighter {
|
|||
* @param {Number} transX the number of pixels to translate on the x axis before scaling
|
||||
* @param {Number} transY the number of pixels to translate on the y axis before scaling
|
||||
* @param {Number} scale the proportion to scale by
|
||||
* @param {String} axis the axis to scale on. "x", "y", or "xy" for both.
|
||||
*/
|
||||
_scalePolygon(pageX, pageY, transX, transY, scale) {
|
||||
_scalePolygon(pageX, pageY, transX, transY, scale, axis) {
|
||||
let { pointsInfo } = this[_dragging];
|
||||
|
||||
let polygonDef = (this.fillRule) ? `${this.fillRule}, ` : "";
|
||||
polygonDef += pointsInfo.map(point => {
|
||||
let { unitX, unitY, valueX, valueY, ratioX, ratioY } = point;
|
||||
let [newX, newY] = scalePoint(valueX, valueY, transX * ratioX,
|
||||
transY * ratioY, scale);
|
||||
transY * ratioY, scale, axis);
|
||||
return `${newX}${unitX} ${newY}${unitY}`;
|
||||
}).join(", ");
|
||||
polygonDef = (this.geometryBox) ? `polygon(${polygonDef}) ${this.geometryBox}` :
|
||||
|
@ -613,13 +622,14 @@ class ShapesHighlighter extends AutoRefreshHighlighter {
|
|||
* @param {Number} transX the number of pixels to translate on the x axis before scaling
|
||||
* @param {Number} transY the number of pixels to translate on the y axis before scaling
|
||||
* @param {Number} scale the proportion to scale by
|
||||
* @param {String} axis the axis to scale on. "x", "y", or "xy" for both.
|
||||
*/
|
||||
_scaleEllipse(pageX, pageY, transX, transY, scale) {
|
||||
_scaleEllipse(pageX, pageY, transX, transY, scale, axis) {
|
||||
let { unitX, unitY, unitRX, unitRY, valueX, valueY,
|
||||
ratioX, ratioY, ratioRX, ratioRY } = this[_dragging];
|
||||
|
||||
let [newCx, newCy] = scalePoint(valueX, valueY, transX * ratioX,
|
||||
transY * ratioY, scale);
|
||||
transY * ratioY, scale, axis);
|
||||
// As part of scaling, the center is translated to be tangent to the lines y=0 & x=0.
|
||||
// To get the new radii, we scale the new center back to that point and get the
|
||||
// distances to the line x=0 and y=0.
|
||||
|
@ -1082,6 +1092,10 @@ class ShapesHighlighter extends AutoRefreshHighlighter {
|
|||
{ pointName: "scale-ne", x: maxX, y: minY, cursor: "nesw-resize" },
|
||||
{ pointName: "scale-sw", x: minX, y: maxY, cursor: "nesw-resize" },
|
||||
{ pointName: "scale-nw", x: minX, y: minY, cursor: "nwse-resize" },
|
||||
{ pointName: "scale-n", x: centerX, y: minY, cursor: "ns-resize" },
|
||||
{ pointName: "scale-s", x: centerX, y: maxY, cursor: "ns-resize" },
|
||||
{ pointName: "scale-e", x: maxX, y: centerY, cursor: "ew-resize" },
|
||||
{ pointName: "scale-w", x: minX, y: centerY, cursor: "ew-resize" }
|
||||
];
|
||||
|
||||
for (let { pointName, x, y, cursor } of points) {
|
||||
|
@ -1226,7 +1240,7 @@ class ShapesHighlighter extends AutoRefreshHighlighter {
|
|||
let centerX = (minX + maxX) / 2;
|
||||
let centerY = (minY + maxY) / 2;
|
||||
|
||||
const points = [
|
||||
let points = [
|
||||
{ point: "translate", x: centerX, y: centerY },
|
||||
{ point: "scale-se", x: maxX, y: maxY },
|
||||
{ point: "scale-ne", x: maxX, y: minY },
|
||||
|
@ -1234,6 +1248,13 @@ class ShapesHighlighter extends AutoRefreshHighlighter {
|
|||
{ point: "scale-nw", x: minX, y: minY },
|
||||
];
|
||||
|
||||
if (this.shapeType === "polygon" || this.shapeType === "ellipse") {
|
||||
points.push({ point: "scale-n", x: centerX, y: minY },
|
||||
{ point: "scale-s", x: centerX, y: maxY },
|
||||
{ point: "scale-e", x: maxX, y: centerY },
|
||||
{ point: "scale-w", x: minX, y: centerY });
|
||||
}
|
||||
|
||||
for (let { point, x, y } of points) {
|
||||
if (pageX >= x - clickRadiusX && pageX <= x + clickRadiusX &&
|
||||
pageY >= y - clickRadiusY && pageY <= y + clickRadiusY) {
|
||||
|
@ -1879,6 +1900,10 @@ class ShapesHighlighter extends AutoRefreshHighlighter {
|
|||
let centerY = (minY + maxY) / 2;
|
||||
let markerPoints = [[centerX, centerY], [minX, minY],
|
||||
[maxX, minY], [minX, maxY], [maxX, maxY]];
|
||||
if (this.shapeType === "polygon" || this.shapeType === "ellipse") {
|
||||
markerPoints.push([minX, centerY], [maxX, centerY],
|
||||
[centerX, minY], [centerX, maxY]);
|
||||
}
|
||||
this._drawMarkers(markerPoints, width, height, zoom);
|
||||
|
||||
if (this.shapeType === "polygon") {
|
||||
|
|
|
@ -130,11 +130,12 @@ const roundTo = (value, exp) => {
|
|||
* @param {Number} transX the amount to translate the x coord by
|
||||
* @param {Number} transY the amount ot translate the y coord by
|
||||
* @param {Number} scale the scaling factor
|
||||
* @param {String} axis the axis to scale on. "x", "y", or "xy" for both.
|
||||
* @returns {Array} of the form [newX, newY], containing the coord pair after scaling.
|
||||
*/
|
||||
const scalePoint = (x, y, transX, transY, scale) => {
|
||||
let newX = (x - transX) * scale + transX;
|
||||
let newY = (y - transY) * scale + transY;
|
||||
const scalePoint = (x, y, transX, transY, scale, axis = "xy") => {
|
||||
let newX = (axis === "y") ? x : (x - transX) * scale + transX;
|
||||
let newY = (axis === "x") ? y : (y - transY) * scale + transY;
|
||||
return [newX, newY];
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче