diff --git a/test/integration/autolinker_spec.mjs b/test/integration/autolinker_spec.mjs index 7de697d7409b7..a39c18f7931ec 100644 --- a/test/integration/autolinker_spec.mjs +++ b/test/integration/autolinker_spec.mjs @@ -16,11 +16,19 @@ import { closePages, loadAndWait } from "./test_utils.mjs"; describe("autolinker", function () { - describe("mozilla.org.pdf", function () { + describe("bug1019475_2.pdf", function () { let pages; beforeAll(async () => { - pages = await loadAndWait("mozilla.org.pdf", ".annotationLayer"); + pages = await loadAndWait( + "bug1019475_2.pdf", + ".annotationLayer", + null, + null, + { + enableAutoLinking: true, + } + ); }); afterAll(async () => { @@ -43,11 +51,19 @@ describe("autolinker", function () { }); }); - describe("link.pdf", function () { + describe("bug1019475_1.pdf", function () { let pages; beforeAll(async () => { - pages = await loadAndWait("link.pdf", ".annotationLayer"); + pages = await loadAndWait( + "bug1019475_1.pdf", + ".annotationLayer", + null, + null, + { + enableAutoLinking: true, + } + ); }); afterAll(async () => { @@ -57,16 +73,16 @@ describe("autolinker", function () { it("must not add links when unnecessary", async () => { await Promise.all( pages.map(async ([browserName, page]) => { - const links = await page.$$eval( + const linkIds = await page.$$eval( ".annotationLayer > .linkAnnotation > a", annotations => annotations.map(a => a.getAttribute("data-element-id")) ); - expect(links.length).withContext(`In ${browserName}`).toEqual(3); - links.forEach(link => - expect(link) + expect(linkIds.length).withContext(`In ${browserName}`).toEqual(3); + linkIds.forEach(id => + expect(id) .withContext(`In ${browserName}`) - .not.toEqual("undefined") + .not.toContain("added_link_") ); }) ); diff --git a/web/annotation_layer_builder.js b/web/annotation_layer_builder.js index 40a6b0c3c21f3..c293a8c0b6c7e 100644 --- a/web/annotation_layer_builder.js +++ b/web/annotation_layer_builder.js @@ -94,11 +94,16 @@ class AnnotationLayerBuilder { * @param {PageViewport} viewport * @param {Object} options * @param {string} intent (default value is 'display') - * @param {Array} inferredLinkAnnotations + * @param {Array} [inferredLinkAnnotations] * @returns {Promise} A promise that is resolved when rendering of the * annotations is complete. */ - async render(viewport, options, intent = "display", inferredLinkAnnotations) { + async render( + viewport, + options, + intent = "display", + inferredLinkAnnotations = null + ) { if (this.div) { if (this._cancelled || !this.annotationLayer) { return; @@ -120,60 +125,11 @@ class AnnotationLayerBuilder { return; } - const uniqueLinks = inferredLinkAnnotations.filter(link => { - for (const annotation of annotations) { - const annotationRects = annot => { - if (annot.quadPoints) { - const rects = []; - for (let i = 2, ii = annot.quadPoints.length; i < ii; i += 8) { - const trX = annot.quadPoints[i]; - const trY = annot.quadPoints[i + 1]; - const blX = annot.quadPoints[i + 2]; - const blY = annot.quadPoints[i + 3]; - rects.push(blX, blY, trX, trY); - } - return rects; - } - return [annotation.rect]; - }; - - const intersectAnnotations = (annot1, annot2) => { - const intersections = []; - const annot1Rects = annotationRects(annot1); - const annot2Rects = annotationRects(annot2); - for (const rect1 of annot1Rects) { - for (const rect2 of annot2Rects) { - const intersection = Util.intersect(rect1, rect2); - if (intersection) { - intersections.push(intersection); - } - } - } - return intersections; - }; - - const areaRects = rects => { - let totalArea = 0; - for (const rect of rects) { - totalArea += - Math.abs(rect[2] - rect[0]) * Math.abs(rect[3] - rect[1]); - } - return totalArea; - }; - - let intersections; // TODO: Add a test case to verify that we can find the intersection between two annotations with quadPoints properly. - if ( - annotation.annotationType === AnnotationType.LINK && - annotation.url === link.url && - (intersections = intersectAnnotations(annotation, link)).length > 0 && - areaRects(intersections) / areaRects(annotationRects(link)) > 0.5 // If the overlap is more than 50%. - ) { - return false; - } - } - return true; - }); - annotations.push(...uniqueLinks); + if (inferredLinkAnnotations?.length) { + annotations.push( + ...this.#checkInferredLinks(inferredLinkAnnotations, annotations) + ); + } // Create an annotation layer div and render the annotations // if there is at least one annotation. @@ -266,6 +222,61 @@ class AnnotationLayerBuilder { section.inert = disableFormElements; } } + + #checkInferredLinks(inferredLinks, annotations) { + return inferredLinks.filter(link => { + for (const annotation of annotations) { + const annotationRects = annot => { + if (annot.quadPoints) { + const rects = []; + for (let i = 2, ii = annot.quadPoints.length; i < ii; i += 8) { + const trX = annot.quadPoints[i]; + const trY = annot.quadPoints[i + 1]; + const blX = annot.quadPoints[i + 2]; + const blY = annot.quadPoints[i + 3]; + rects.push(blX, blY, trX, trY); + } + return rects; + } + return [annot.rect]; + }; + + const intersectAnnotations = (annot1, annot2) => { + const intersections = []; + const annot1Rects = annotationRects(annot1); + const annot2Rects = annotationRects(annot2); + for (const rect1 of annot1Rects) { + for (const rect2 of annot2Rects) { + const intersection = Util.intersect(rect1, rect2); + if (intersection) { + intersections.push(intersection); + } + } + } + return intersections; + }; + + const areaRects = rects => { + let totalArea = 0; + for (const rect of rects) { + totalArea += Math.abs((rect[2] - rect[0]) * (rect[3] - rect[1])); + } + return totalArea; + }; + + let intersections; // TODO: Add a test case to verify that we can find the intersection between two annotations with quadPoints properly. + if ( + annotation.annotationType === AnnotationType.LINK && + annotation.url === link.url && + (intersections = intersectAnnotations(annotation, link)).length > 0 && + areaRects(intersections) / areaRects(annotationRects(link)) > 0.5 // If the overlap is more than 50%. + ) { + return false; + } + } + return true; + }); + } } export { AnnotationLayerBuilder }; diff --git a/web/pdf_page_view.js b/web/pdf_page_view.js index 0187d028bb0c8..35c69971a8266 100644 --- a/web/pdf_page_view.js +++ b/web/pdf_page_view.js @@ -153,7 +153,7 @@ class PDFPageView { regularAnnotations: true, }; - #inferredLinkAnnotations = []; + #inferredLinkAnnotations = null; #layers = [null, null, null, null]; diff --git a/web/pdfjs.js b/web/pdfjs.js index 7ac129513be5a..ac5d6432cf6ae 100644 --- a/web/pdfjs.js +++ b/web/pdfjs.js @@ -15,12 +15,14 @@ const { AbortException, + AnnotationBorderStyleType, AnnotationEditorLayer, AnnotationEditorParamsType, AnnotationEditorType, AnnotationEditorUIManager, AnnotationLayer, AnnotationMode, + AnnotationType, build, ColorPicker, createValidAbsoluteUrl, @@ -62,12 +64,14 @@ const { export { AbortException, + AnnotationBorderStyleType, AnnotationEditorLayer, AnnotationEditorParamsType, AnnotationEditorType, AnnotationEditorUIManager, AnnotationLayer, AnnotationMode, + AnnotationType, build, ColorPicker, createValidAbsoluteUrl,