Don't print hidden annotatons (bug 1815196)

and handle correctly the NoView and NoPrint flags when they're changed
from JS.
This commit is contained in:
Calixte Denizet 2023-07-30 15:52:27 +02:00
parent 0e6d141edf
commit 71960bea64
9 changed files with 124 additions and 18 deletions

View File

@ -628,8 +628,11 @@ class Annotation {
* @private * @private
*/ */
_isPrintable(flags) { _isPrintable(flags) {
// In Acrobat, hidden flag cancels the print one
// (see annotation_hidden_print.pdf).
return ( return (
this._hasFlag(flags, AnnotationFlag.PRINT) && this._hasFlag(flags, AnnotationFlag.PRINT) &&
!this._hasFlag(flags, AnnotationFlag.HIDDEN) &&
!this._hasFlag(flags, AnnotationFlag.INVISIBLE) !this._hasFlag(flags, AnnotationFlag.INVISIBLE)
); );
} }
@ -642,11 +645,13 @@ class Annotation {
* @public * @public
* @memberof Annotation * @memberof Annotation
* @param {AnnotationStorage} [annotationStorage] - Storage for annotation * @param {AnnotationStorage} [annotationStorage] - Storage for annotation
* @param {boolean} [_renderForms] - if true widgets are rendered thanks to
* the annotation layer.
*/ */
mustBeViewed(annotationStorage) { mustBeViewed(annotationStorage, _renderForms) {
const hidden = annotationStorage?.get(this.data.id)?.hidden; const noView = annotationStorage?.get(this.data.id)?.noView;
if (hidden !== undefined) { if (noView !== undefined) {
return !hidden; return !noView;
} }
return this.viewable && !this._hasFlag(this.flags, AnnotationFlag.HIDDEN); return this.viewable && !this._hasFlag(this.flags, AnnotationFlag.HIDDEN);
} }
@ -661,9 +666,9 @@ class Annotation {
* @param {AnnotationStorage} [annotationStorage] - Storage for annotation * @param {AnnotationStorage} [annotationStorage] - Storage for annotation
*/ */
mustBePrinted(annotationStorage) { mustBePrinted(annotationStorage) {
const print = annotationStorage?.get(this.data.id)?.print; const noPrint = annotationStorage?.get(this.data.id)?.noPrint;
if (print !== undefined) { if (noPrint !== undefined) {
return print; return !noPrint;
} }
return this.printable; return this.printable;
} }
@ -1700,7 +1705,9 @@ class WidgetAnnotation extends Annotation {
data.readOnly = this.hasFieldFlag(AnnotationFieldFlag.READONLY); data.readOnly = this.hasFieldFlag(AnnotationFieldFlag.READONLY);
data.required = this.hasFieldFlag(AnnotationFieldFlag.REQUIRED); 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); 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) { getRotationMatrix(annotationStorage) {
let rotation = annotationStorage?.get(this.data.id)?.rotation; let rotation = annotationStorage?.get(this.data.id)?.rotation;
if (rotation === undefined) { if (rotation === undefined) {

View File

@ -556,7 +556,8 @@ class Page {
for (const annotation of annotations) { for (const annotation of annotations) {
if ( if (
intentAny || intentAny ||
(intentDisplay && annotation.mustBeViewed(annotationStorage)) || (intentDisplay &&
annotation.mustBeViewed(annotationStorage, renderForms)) ||
(intentPrint && annotation.mustBePrinted(annotationStorage)) (intentPrint && annotation.mustBePrinted(annotationStorage))
) { ) {
opListPromises.push( opListPromises.push(

View File

@ -342,24 +342,27 @@ class AnnotationElement {
return shadow(this, "_commonActions", { return shadow(this, "_commonActions", {
display: event => { 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.container.style.visibility = hidden ? "hidden" : "visible";
this.annotationStorage.setValue(this.data.id, { this.annotationStorage.setValue(this.data.id, {
hidden, noView: hidden,
print: event.detail.display === 0 || event.detail.display === 3, noPrint: display === 1 || display === 2,
}); });
}, },
print: event => { print: event => {
this.annotationStorage.setValue(this.data.id, { this.annotationStorage.setValue(this.data.id, {
print: event.detail.print, noPrint: !event.detail.print,
}); });
}, },
hidden: event => { hidden: event => {
this.container.style.visibility = event.detail.hidden const { hidden } = event.detail;
? "hidden" this.container.style.visibility = hidden ? "hidden" : "visible";
: "visible";
this.annotationStorage.setValue(this.data.id, { this.annotationStorage.setValue(this.data.id, {
hidden: event.detail.hidden, noPrint: hidden,
noView: hidden,
}); });
}, },
focus: event => { focus: event => {

View File

@ -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");
})
);
});
});
}); });

View File

@ -606,3 +606,6 @@
!issue16633.pdf !issue16633.pdf
!bug1844576.pdf !bug1844576.pdf
!bug1844583.pdf !bug1844583.pdf
!annotation_hidden_print.pdf
!annotation_hidden_noview.pdf
!widget_hidden_print.pdf

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -3420,7 +3420,7 @@
"print": true, "print": true,
"annotationStorage": { "annotationStorage": {
"427R": { "427R": {
"hidden": false, "noPrint": false,
"value": "hello world" "value": "hello world"
} }
} }
@ -8054,5 +8054,21 @@
"rotation": 0 "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
} }
] ]