diff --git a/src/display/editor/editor.js b/src/display/editor/editor.js index 371f70596..04aeea3b9 100644 --- a/src/display/editor/editor.js +++ b/src/display/editor/editor.js @@ -258,8 +258,7 @@ class AnnotationEditor { this.x = (x + tx) / width; this.y = (y + ty) / height; - this.div.style.left = `${100 * this.x}%`; - this.div.style.top = `${100 * this.y}%`; + this.fixAndSetPosition(); } /** @@ -274,8 +273,41 @@ class AnnotationEditor { this.x += x / width; this.y += y / height; - this.div.style.left = `${100 * this.x}%`; - this.div.style.top = `${100 * this.y}%`; + this.fixAndSetPosition(); + } + + fixAndSetPosition() { + const [pageWidth, pageHeight] = this.pageDimensions; + let { x, y, width, height } = this; + width *= pageWidth; + height *= pageHeight; + x *= pageWidth; + y *= pageHeight; + + switch (this.rotation) { + case 0: + x = Math.max(0, Math.min(pageWidth - width, x)); + y = Math.max(0, Math.min(pageHeight - height, y)); + break; + case 90: + x = Math.max(0, Math.min(pageWidth - height, x)); + y = Math.min(pageHeight, Math.max(width, y)); + break; + case 180: + x = Math.min(pageWidth, Math.max(width, x)); + y = Math.min(pageHeight, Math.max(height, y)); + break; + case 270: + x = Math.min(pageWidth, Math.max(height, x)); + y = Math.max(0, Math.min(pageHeight - width, y)); + break; + } + + this.x = x / pageWidth; + this.y = y / pageHeight; + + this.div.style.left = `${(100 * this.x).toFixed(2)}%`; + this.div.style.top = `${(100 * this.y).toFixed(2)}%`; } /** @@ -383,6 +415,17 @@ class AnnotationEditor { this.div.addEventListener("focusin", this.#boundFocusin); this.div.addEventListener("focusout", this.#boundFocusout); + const [parentWidth, parentHeight] = this.parentDimensions; + if (this.parentRotation % 180 !== 0) { + this.div.style.maxWidth = `${((100 * parentHeight) / parentWidth).toFixed( + 2 + )}%`; + this.div.style.maxHeight = `${( + (100 * parentWidth) / + parentHeight + ).toFixed(2)}%`; + } + const [tx, ty] = this.getInitialTranslation(); this.translate(tx, ty); diff --git a/src/display/editor/freetext.js b/src/display/editor/freetext.js index 59a248b67..cc20bf45a 100644 --- a/src/display/editor/freetext.js +++ b/src/display/editor/freetext.js @@ -357,6 +357,7 @@ class FreeTextEditor extends AnnotationEditor { this.width = rect.height / parentWidth; this.height = rect.width / parentHeight; } + this.fixAndSetPosition(); } /** diff --git a/src/display/editor/ink.js b/src/display/editor/ink.js index 2f1bd8730..efda7cecb 100644 --- a/src/display/editor/ink.js +++ b/src/display/editor/ink.js @@ -838,6 +838,7 @@ class InkEditor extends AnnotationEditor { const [parentWidth, parentHeight] = this.parentDimensions; this.width = width / parentWidth; this.height = height / parentHeight; + this.fixAndSetPosition(); if (this.#disableEditing) { this.#setScaleFactor(width, height); diff --git a/src/display/editor/stamp.js b/src/display/editor/stamp.js index 19be57827..950bf8071 100644 --- a/src/display/editor/stamp.js +++ b/src/display/editor/stamp.js @@ -254,6 +254,7 @@ class StampEditor extends AnnotationEditor { this.width = width / parentWidth; this.height = height / parentHeight; this.setDims(width, height); + this.fixAndSetPosition(); if (this.#resizeTimeoutId !== null) { clearTimeout(this.#resizeTimeoutId); } diff --git a/test/integration/stamp_editor_spec.js b/test/integration/stamp_editor_spec.js index a16c770a9..eb2f3a52f 100644 --- a/test/integration/stamp_editor_spec.js +++ b/test/integration/stamp_editor_spec.js @@ -128,4 +128,51 @@ describe("Stamp Editor", () => { ); }); }); + + describe("Page overflow", () => { + let pages; + + beforeAll(async () => { + pages = await loadAndWait("empty.pdf", ".annotationEditorLayer", 50); + }); + + afterAll(async () => { + await closePages(pages); + }); + + it("must check that an added image stay within the page", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + if (browserName === "firefox") { + pending( + "Disabled in Firefox, because of https://bugzilla.mozilla.org/1553847." + ); + } + + await page.click("#editorStamp"); + + 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 { right, bottom } = el.getBoundingClientRect(); + return { x: right, y: bottom }; + }); + + await page.mouse.click(rect.x - 10, rect.y - 10); + const input = await page.$("#stampEditorFileInput"); + await input.uploadFile( + `${path.join(__dirname, "../images/firefox_logo.png")}` + ); + + await page.waitForTimeout(300); + + const { left } = await getEditorDimensions(page, 0); + + // The image is bigger than the page, so it has been scaled down to + // 75% of the page width. + expect(left).toEqual("25%"); + }) + ); + }); + }); }); diff --git a/test/integration/test_utils.js b/test/integration/test_utils.js index 23b315508..08a3a1002 100644 --- a/test/integration/test_utils.js +++ b/test/integration/test_utils.js @@ -161,7 +161,12 @@ function getEditorDimensions(page, id) { return page.evaluate(n => { const element = document.getElementById(`pdfjs_internal_editor_${n}`); const { style } = element; - return { width: style.width, height: style.height }; + return { + left: style.left, + top: style.top, + width: style.width, + height: style.height, + }; }, id); } exports.getEditorDimensions = getEditorDimensions; diff --git a/web/annotation_editor_layer_builder.css b/web/annotation_editor_layer_builder.css index 08c5252b9..312a190b6 100644 --- a/web/annotation_editor_layer_builder.css +++ b/web/annotation_editor_layer_builder.css @@ -88,6 +88,8 @@ z-index: 1; transform-origin: 0 0; cursor: auto; + max-width: 100%; + max-height: 100%; } .annotationEditorLayer :is(.inkEditor, .stampEditor) {