Merge pull request #19142 from calixteman/rotated_ink
Fix the clickable area for rotated ink annotations
This commit is contained in:
commit
36b1ba8eca
@ -2815,37 +2815,48 @@ class InkAnnotationElement extends AnnotationElement {
|
|||||||
// Create an invisible polyline with the same points that acts as the
|
// Create an invisible polyline with the same points that acts as the
|
||||||
// trigger for the popup.
|
// trigger for the popup.
|
||||||
const {
|
const {
|
||||||
data: { rect, inkLists, borderStyle, popupRef },
|
data: { rect, rotation, inkLists, borderStyle, popupRef },
|
||||||
} = this;
|
} = this;
|
||||||
const { width, height } = getRectDims(rect);
|
let { width, height } = getRectDims(rect);
|
||||||
|
let transform;
|
||||||
|
|
||||||
|
// PDF coordinates are calculated from a bottom left origin, so
|
||||||
|
// transform the polyline coordinates to a top left origin for the
|
||||||
|
// SVG element.
|
||||||
|
switch (rotation) {
|
||||||
|
case 90:
|
||||||
|
transform = `rotate(90) translate(${-rect[0]},${rect[3] - height}) scale(1,-1)`;
|
||||||
|
[width, height] = [height, width];
|
||||||
|
break;
|
||||||
|
case 180:
|
||||||
|
transform = `rotate(180) translate(${-rect[0] - width},${rect[3] - height}) scale(1,-1)`;
|
||||||
|
break;
|
||||||
|
case 270:
|
||||||
|
transform = `rotate(270) translate(${-rect[0] - width},${rect[3]}) scale(1,-1)`;
|
||||||
|
[width, height] = [height, width];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
transform = `translate(${-rect[0]},${rect[3]}) scale(1,-1)`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const svg = this.svgFactory.create(
|
const svg = this.svgFactory.create(
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
/* skipDimensions = */ true
|
/* skipDimensions = */ true
|
||||||
);
|
);
|
||||||
|
const basePolyline = this.svgFactory.createElement(this.svgElementName);
|
||||||
|
// Ensure that the 'stroke-width' is always non-zero, since otherwise it
|
||||||
|
// won't be possible to open/close the popup (note e.g. issue 11122).
|
||||||
|
basePolyline.setAttribute("stroke-width", borderStyle.width || 1);
|
||||||
|
basePolyline.setAttribute("stroke", "transparent");
|
||||||
|
basePolyline.setAttribute("fill", "transparent");
|
||||||
|
basePolyline.setAttribute("transform", transform);
|
||||||
|
|
||||||
for (const inkList of inkLists) {
|
for (let i = 0, ii = inkLists.length; i < ii; i++) {
|
||||||
// Convert the ink list to a single points string that the SVG
|
const polyline = i < ii - 1 ? basePolyline.cloneNode() : basePolyline;
|
||||||
// polyline element expects ("x1,y1 x2,y2 ..."). PDF coordinates are
|
|
||||||
// calculated from a bottom left origin, so transform the polyline
|
|
||||||
// coordinates to a top left origin for the SVG element.
|
|
||||||
let points = [];
|
|
||||||
for (let i = 0, ii = inkList.length; i < ii; i += 2) {
|
|
||||||
const x = inkList[i] - rect[0];
|
|
||||||
const y = rect[3] - inkList[i + 1];
|
|
||||||
points.push(`${x},${y}`);
|
|
||||||
}
|
|
||||||
points = points.join(" ");
|
|
||||||
|
|
||||||
const polyline = this.svgFactory.createElement(this.svgElementName);
|
|
||||||
this.#polylines.push(polyline);
|
this.#polylines.push(polyline);
|
||||||
polyline.setAttribute("points", points);
|
polyline.setAttribute("points", inkLists[i].join(","));
|
||||||
// Ensure that the 'stroke-width' is always non-zero, since otherwise it
|
|
||||||
// won't be possible to open/close the popup (note e.g. issue 11122).
|
|
||||||
polyline.setAttribute("stroke-width", borderStyle.width || 1);
|
|
||||||
polyline.setAttribute("stroke", "transparent");
|
|
||||||
polyline.setAttribute("fill", "transparent");
|
|
||||||
|
|
||||||
svg.append(polyline);
|
svg.append(polyline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
import {
|
import {
|
||||||
closePages,
|
closePages,
|
||||||
getQuerySelector,
|
getQuerySelector,
|
||||||
|
getRect,
|
||||||
getSelector,
|
getSelector,
|
||||||
loadAndWait,
|
loadAndWait,
|
||||||
} from "./test_utils.mjs";
|
} from "./test_utils.mjs";
|
||||||
@ -654,4 +655,38 @@ describe("ResetForm action", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Rotated annotation and its clickable area", () => {
|
||||||
|
describe("issue14438.pdf", () => {
|
||||||
|
let pages;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
pages = await loadAndWait(
|
||||||
|
"rotated_ink.pdf",
|
||||||
|
"[data-annotation-id='18R']"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await closePages(pages);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("must check that the clickable area has been rotated", async () => {
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
const rect = await getRect(page, "[data-annotation-id='18R']");
|
||||||
|
const promisePopup = page.waitForSelector(
|
||||||
|
"[data-annotation-id='19R']",
|
||||||
|
{ visible: true }
|
||||||
|
);
|
||||||
|
await page.mouse.move(
|
||||||
|
rect.x + rect.width * 0.1,
|
||||||
|
rect.y + rect.height * 0.9
|
||||||
|
);
|
||||||
|
await promisePopup;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -684,3 +684,4 @@
|
|||||||
!issue19083.pdf
|
!issue19083.pdf
|
||||||
!issue19120.pdf
|
!issue19120.pdf
|
||||||
!bug1934157.pdf
|
!bug1934157.pdf
|
||||||
|
!rotated_ink.pdf
|
||||||
|
|||||||
BIN
test/pdfs/rotated_ink.pdf
Normal file
BIN
test/pdfs/rotated_ink.pdf
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user