diff --git a/src/display/editor/editor.js b/src/display/editor/editor.js index 19e43579b..5c9feff64 100644 --- a/src/display/editor/editor.js +++ b/src/display/editor/editor.js @@ -68,8 +68,17 @@ class AnnotationEditor { this.div = null; this._uiManager = parameters.uiManager; - this.rotation = this.parent.viewport.rotation; - this.pageDimensions = this.parent.pageDimensions; + const { + rotation, + viewBox: [pageLLx, pageLLy, pageURx, pageURy], + } = this.parent.viewport; + this.rotation = rotation; + const pageWidth = pageURx - pageLLx; + const pageHeight = pageURy - pageLLy; + + this.pageDimensions = [pageWidth, pageHeight]; + this.pageTranslation = [pageLLx, pageLLy]; + const [width, height] = this.parentDimensions; this.x = parameters.x / width; this.y = parameters.y / height; @@ -341,6 +350,7 @@ class AnnotationEditor { getRect(tx, ty) { const scale = this.parentScale; const [pageWidth, pageHeight] = this.pageDimensions; + const [pageX, pageY] = this.pageTranslation; const shiftX = tx / scale; const shiftY = ty / scale; const x = this.x * pageWidth; @@ -351,31 +361,31 @@ class AnnotationEditor { switch (this.rotation) { case 0: return [ - x + shiftX, - pageHeight - y - shiftY - height, - x + shiftX + width, - pageHeight - y - shiftY, + x + shiftX + pageX, + pageHeight - y - shiftY - height + pageY, + x + shiftX + width + pageX, + pageHeight - y - shiftY + pageY, ]; case 90: return [ - x + shiftY, - pageHeight - y + shiftX, - x + shiftY + height, - pageHeight - y + shiftX + width, + x + shiftY + pageX, + pageHeight - y + shiftX + pageY, + x + shiftY + height + pageX, + pageHeight - y + shiftX + width + pageY, ]; case 180: return [ - x - shiftX - width, - pageHeight - y + shiftY, - x - shiftX, - pageHeight - y + shiftY + height, + x - shiftX - width + pageX, + pageHeight - y + shiftY + pageY, + x - shiftX + pageX, + pageHeight - y + shiftY + height + pageY, ]; case 270: return [ - x - shiftY - height, - pageHeight - y - shiftX - width, - x - shiftY, - pageHeight - y - shiftX, + x - shiftY - height + pageX, + pageHeight - y - shiftX - width + pageY, + x - shiftY + pageX, + pageHeight - y - shiftX + pageY, ]; default: throw new Error("Invalid rotation"); diff --git a/test/integration/freetext_editor_spec.js b/test/integration/freetext_editor_spec.js index 50443cfbb..c4ff6febc 100644 --- a/test/integration/freetext_editor_spec.js +++ b/test/integration/freetext_editor_spec.js @@ -547,24 +547,9 @@ describe("Editor", () => { await page.mouse.click(rect.x + 100, rect.y + 100); await page.type(`${getEditorSelector(currentId)} .internal`, data); - const editorRect = await page.$eval( - getEditorSelector(currentId), - el => { - const { x, y, width, height } = el.getBoundingClientRect(); - return { - x, - y, - width, - height, - }; - } - ); - // Commit. - await page.mouse.click( - editorRect.x, - editorRect.y + 2 * editorRect.height - ); + await page.keyboard.press("Escape"); + await page.waitForTimeout(10); await waitForSelectedEditor(page, getEditorSelector(currentId)); await waitForStorageEntries(page, currentId + 1); @@ -646,4 +631,88 @@ describe("Editor", () => { ); }); }); + + describe("issue 15789", () => { + let pages; + + beforeAll(async () => { + pages = await loadAndWait("issue15789.pdf", ".annotationEditorLayer"); + pages = await Promise.all( + pages.map(async ([browserName, page]) => { + await page.select("#scaleSelect", "1"); + return [browserName, page]; + }) + ); + }); + + afterAll(async () => { + await closePages(pages); + }); + + it("must take the media box into account", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await page.click("#editorFreeText"); + let currentId = 0; + + for (let step = 0; step < 3; step++) { + const rect = await page.$eval(".annotationEditorLayer", el => { + // With Chrome something is wrong when serializing a DomRect, + // hence we extract the values and just return them. + const { x, y, width, height } = el.getBoundingClientRect(); + return { x, y, width, height }; + }); + + const data = `Hello ${step}`; + const x = rect.x + 0.1 * rect.width; + const y = rect.y + 0.1 * rect.height; + await page.mouse.click(x, y); + await page.type(`${getEditorSelector(currentId)} .internal`, data); + + // Commit. + await page.keyboard.press("Escape"); + await page.waitForTimeout(10); + + await page.evaluate(() => { + document.getElementById("pageRotateCw").click(); + }); + currentId += 1; + await page.waitForTimeout(10); + } + + const serialize = proprName => + page.evaluate( + name => + [ + ...window.PDFViewerApplication.pdfDocument.annotationStorage.serializable.values(), + ].map(x => x[name]), + proprName + ); + + const rects = (await serialize("rect")).map(rect => + rect.slice(0, 2).map(x => Math.floor(x)) + ); + const expected = [ + [-28, 695], + [-38, -10], + [501, -20], + ]; + // Dimensions aren't exactly the same from a platform to an other + // so we're a bit tolerant here with the numbers. + // Anyway the goal is to check that the bottom left corner of the + // media box is taken into account. + // The pdf has a media box equals to [-99 -99 612.0 792.0]. + const diffs = rects.map( + (rect, i) => + Math.abs(rect[0] - expected[i][0]) < 10 && + Math.abs(rect[1] - expected[i][1]) < 10 + ); + + expect(diffs) + .withContext(`In ${browserName}`) + .toEqual([true, true, true]); + }) + ); + }); + }); }); diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index d7c000a7d..50738a2c2 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -559,3 +559,4 @@ !bug1802888.pdf !issue15759.pdf !issue15753.pdf +!issue15789.pdf diff --git a/test/pdfs/issue15789.pdf b/test/pdfs/issue15789.pdf new file mode 100755 index 000000000..44d814351 Binary files /dev/null and b/test/pdfs/issue15789.pdf differ