diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index e2dc138a8..fdfdf7e26 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -2815,37 +2815,48 @@ class InkAnnotationElement extends AnnotationElement { // Create an invisible polyline with the same points that acts as the // trigger for the popup. const { - data: { rect, inkLists, borderStyle, popupRef }, + data: { rect, rotation, inkLists, borderStyle, popupRef }, } = 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( width, height, /* 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) { - // Convert the ink list to a single points string that the SVG - // 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); + for (let i = 0, ii = inkLists.length; i < ii; i++) { + const polyline = i < ii - 1 ? basePolyline.cloneNode() : basePolyline; this.#polylines.push(polyline); - polyline.setAttribute("points", points); - // 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"); - + polyline.setAttribute("points", inkLists[i].join(",")); svg.append(polyline); } diff --git a/test/integration/annotation_spec.mjs b/test/integration/annotation_spec.mjs index 52e33698d..7431a17d1 100644 --- a/test/integration/annotation_spec.mjs +++ b/test/integration/annotation_spec.mjs @@ -16,6 +16,7 @@ import { closePages, getQuerySelector, + getRect, getSelector, loadAndWait, } 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; + }) + ); + }); + }); + }); }); diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 9419dafdc..45949cc35 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -684,3 +684,4 @@ !issue19083.pdf !issue19120.pdf !bug1934157.pdf +!rotated_ink.pdf diff --git a/test/pdfs/rotated_ink.pdf b/test/pdfs/rotated_ink.pdf new file mode 100644 index 000000000..8b69361ea Binary files /dev/null and b/test/pdfs/rotated_ink.pdf differ