diff --git a/src/core/annotation.js b/src/core/annotation.js index 551f429e4..dd5ecbb67 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -628,8 +628,11 @@ class Annotation { * @private */ _isPrintable(flags) { + // In Acrobat, hidden flag cancels the print one + // (see annotation_hidden_print.pdf). return ( this._hasFlag(flags, AnnotationFlag.PRINT) && + !this._hasFlag(flags, AnnotationFlag.HIDDEN) && !this._hasFlag(flags, AnnotationFlag.INVISIBLE) ); } @@ -642,11 +645,13 @@ class Annotation { * @public * @memberof Annotation * @param {AnnotationStorage} [annotationStorage] - Storage for annotation + * @param {boolean} [_renderForms] - if true widgets are rendered thanks to + * the annotation layer. */ - mustBeViewed(annotationStorage) { - const hidden = annotationStorage?.get(this.data.id)?.hidden; - if (hidden !== undefined) { - return !hidden; + mustBeViewed(annotationStorage, _renderForms) { + const noView = annotationStorage?.get(this.data.id)?.noView; + if (noView !== undefined) { + return !noView; } return this.viewable && !this._hasFlag(this.flags, AnnotationFlag.HIDDEN); } @@ -661,9 +666,9 @@ class Annotation { * @param {AnnotationStorage} [annotationStorage] - Storage for annotation */ mustBePrinted(annotationStorage) { - const print = annotationStorage?.get(this.data.id)?.print; - if (print !== undefined) { - return print; + const noPrint = annotationStorage?.get(this.data.id)?.noPrint; + if (noPrint !== undefined) { + return !noPrint; } return this.printable; } @@ -1700,7 +1705,9 @@ class WidgetAnnotation extends Annotation { data.readOnly = this.hasFieldFlag(AnnotationFieldFlag.READONLY); data.required = this.hasFieldFlag(AnnotationFieldFlag.REQUIRED); - data.hidden = this._hasFlag(data.annotationFlags, AnnotationFlag.HIDDEN); + data.hidden = + this._hasFlag(data.annotationFlags, AnnotationFlag.HIDDEN) || + this._hasFlag(data.annotationFlags, AnnotationFlag.NOVIEW); } /** @@ -1739,6 +1746,26 @@ class WidgetAnnotation extends Annotation { return !!(this.data.fieldFlags & flag); } + /** @inheritdoc */ + _isViewable(flags) { + // We don't take into account the `NOVIEW` or `HIDDEN` flags here, + // since the visibility can be changed by js code, hence in case + // it's made viewable, we should render it (with visibility set to + // hidden). + return !this._hasFlag(flags, AnnotationFlag.INVISIBLE); + } + + /** @inheritdoc */ + mustBeViewed(annotationStorage, renderForms) { + if (renderForms) { + return this.viewable; + } + return ( + super.mustBeViewed(annotationStorage, renderForms) && + !this._hasFlag(this.flags, AnnotationFlag.NOVIEW) + ); + } + getRotationMatrix(annotationStorage) { let rotation = annotationStorage?.get(this.data.id)?.rotation; if (rotation === undefined) { diff --git a/src/core/document.js b/src/core/document.js index b8b3e3d7e..3909fea38 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -556,7 +556,8 @@ class Page { for (const annotation of annotations) { if ( intentAny || - (intentDisplay && annotation.mustBeViewed(annotationStorage)) || + (intentDisplay && + annotation.mustBeViewed(annotationStorage, renderForms)) || (intentPrint && annotation.mustBePrinted(annotationStorage)) ) { opListPromises.push( diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index 65d276263..bb341e6fd 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -342,24 +342,27 @@ class AnnotationElement { return shadow(this, "_commonActions", { display: event => { - const hidden = event.detail.display % 2 === 1; + const { display } = event.detail; + // See scripting/constants.js for the values of `Display`. + // 0 = visible, 1 = hidden, 2 = noPrint and 3 = noView. + const hidden = display % 2 === 1; this.container.style.visibility = hidden ? "hidden" : "visible"; this.annotationStorage.setValue(this.data.id, { - hidden, - print: event.detail.display === 0 || event.detail.display === 3, + noView: hidden, + noPrint: display === 1 || display === 2, }); }, print: event => { this.annotationStorage.setValue(this.data.id, { - print: event.detail.print, + noPrint: !event.detail.print, }); }, hidden: event => { - this.container.style.visibility = event.detail.hidden - ? "hidden" - : "visible"; + const { hidden } = event.detail; + this.container.style.visibility = hidden ? "hidden" : "visible"; this.annotationStorage.setValue(this.data.id, { - hidden: event.detail.hidden, + noPrint: hidden, + noView: hidden, }); }, focus: event => { diff --git a/test/integration/scripting_spec.js b/test/integration/scripting_spec.js index 887d8b7e7..d1e84fff5 100644 --- a/test/integration/scripting_spec.js +++ b/test/integration/scripting_spec.js @@ -2042,4 +2042,60 @@ describe("Interaction", () => { ); }); }); + + describe("in annotation_hidden_noview.pdf", () => { + let pages; + + beforeAll(async () => { + pages = await loadAndWait( + "annotation_hidden_noview.pdf", + getSelector("11R") + ); + }); + + afterAll(async () => { + await closePages(pages); + }); + + it("must check that invisible fields are made visible", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await page.waitForFunction( + "window.PDFViewerApplication.scriptingReady === true" + ); + + let visibility = await page.$eval( + getSelector("7R"), + el => getComputedStyle(el).visibility + ); + expect(visibility).withContext(`In ${browserName}`).toEqual("hidden"); + + visibility = await page.$eval( + getSelector("8R"), + el => getComputedStyle(el).visibility + ); + expect(visibility).withContext(`In ${browserName}`).toEqual("hidden"); + + await page.click(getSelector("11R")); + await page.waitForTimeout(10); + + visibility = await page.$eval( + getSelector("7R"), + el => getComputedStyle(el).visibility + ); + expect(visibility) + .withContext(`In ${browserName}`) + .toEqual("visible"); + + visibility = await page.$eval( + getSelector("8R"), + el => getComputedStyle(el).visibility + ); + expect(visibility) + .withContext(`In ${browserName}`) + .toEqual("visible"); + }) + ); + }); + }); }); diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 3bbc3766c..a396de778 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -606,3 +606,6 @@ !issue16633.pdf !bug1844576.pdf !bug1844583.pdf +!annotation_hidden_print.pdf +!annotation_hidden_noview.pdf +!widget_hidden_print.pdf diff --git a/test/pdfs/annotation_hidden_noview.pdf b/test/pdfs/annotation_hidden_noview.pdf new file mode 100644 index 000000000..9475158b6 Binary files /dev/null and b/test/pdfs/annotation_hidden_noview.pdf differ diff --git a/test/pdfs/annotation_hidden_print.pdf b/test/pdfs/annotation_hidden_print.pdf new file mode 100644 index 000000000..827a9320b Binary files /dev/null and b/test/pdfs/annotation_hidden_print.pdf differ diff --git a/test/pdfs/widget_hidden_print.pdf b/test/pdfs/widget_hidden_print.pdf new file mode 100644 index 000000000..ef9ebe460 Binary files /dev/null and b/test/pdfs/widget_hidden_print.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index 89cfbb913..dbff94481 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -3420,7 +3420,7 @@ "print": true, "annotationStorage": { "427R": { - "hidden": false, + "noPrint": false, "value": "hello world" } } @@ -8054,5 +8054,21 @@ "rotation": 0 } } + }, + { + "id": "widget_hidden_print", + "file": "pdfs/widget_hidden_print.pdf", + "md5": "0b8d5a8e8c7c7598232a79044c312cbb", + "rounds": 1, + "type": "eq", + "print": true + }, + { + "id": "annotation_hidden_print", + "file": "pdfs/annotation_hidden_print.pdf", + "md5": "5cfa86df9b080feeb4aa320ad68d6cbd", + "rounds": 1, + "type": "eq", + "print": true } ]