Skip to content

Commit 2882107

Browse files
committed
JS -- hidden annotations must be built in case a script show them
* in some pdf, there are actions with "event.source.hidden = ..." * in order to handle visibility when printing, annotationStorage is extended to store multiple properties (value, hidden, editable, ...)
1 parent 018fd43 commit 2882107

9 files changed

+210
-100
lines changed

src/core/annotation.js

+21-9
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,6 @@ class Annotation {
300300
_isViewable(flags) {
301301
return (
302302
!this._hasFlag(flags, AnnotationFlag.INVISIBLE) &&
303-
!this._hasFlag(flags, AnnotationFlag.HIDDEN) &&
304303
!this._hasFlag(flags, AnnotationFlag.NOVIEW)
305304
);
306305
}
@@ -311,11 +310,18 @@ class Annotation {
311310
_isPrintable(flags) {
312311
return (
313312
this._hasFlag(flags, AnnotationFlag.PRINT) &&
314-
!this._hasFlag(flags, AnnotationFlag.INVISIBLE) &&
315-
!this._hasFlag(flags, AnnotationFlag.HIDDEN)
313+
!this._hasFlag(flags, AnnotationFlag.INVISIBLE)
316314
);
317315
}
318316

317+
isHidden(annotationStorage) {
318+
const data = annotationStorage[this.data.id];
319+
if (data && "hidden" in data) {
320+
return data.hidden;
321+
}
322+
return this._hasFlag(this.flags, AnnotationFlag.HIDDEN);
323+
}
324+
319325
/**
320326
* @type {boolean}
321327
*/
@@ -984,7 +990,7 @@ class WidgetAnnotation extends Annotation {
984990
}
985991

986992
data.readOnly = this.hasFieldFlag(AnnotationFieldFlag.READONLY);
987-
data.hidden = this.hasFieldFlag(AnnotationFieldFlag.HIDDEN);
993+
data.hidden = this._hasFlag(data.annotationFlags, AnnotationFlag.HIDDEN);
988994

989995
// Hide signatures because we cannot validate them, and unset the fieldValue
990996
// since it's (most likely) a `Dict` which is non-serializable and will thus
@@ -1145,7 +1151,8 @@ class WidgetAnnotation extends Annotation {
11451151
}
11461152

11471153
async save(evaluator, task, annotationStorage) {
1148-
const value = annotationStorage[this.data.id];
1154+
const value =
1155+
annotationStorage[this.data.id] && annotationStorage[this.data.id].value;
11491156
if (value === this.data.fieldValue || value === undefined) {
11501157
return null;
11511158
}
@@ -1229,7 +1236,8 @@ class WidgetAnnotation extends Annotation {
12291236
if (!annotationStorage || isPassword) {
12301237
return null;
12311238
}
1232-
const value = annotationStorage[this.data.id];
1239+
const value =
1240+
annotationStorage[this.data.id] && annotationStorage[this.data.id].value;
12331241
if (value === undefined) {
12341242
// The annotation hasn't been rendered so use the appearance
12351243
return null;
@@ -1712,7 +1720,9 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
17121720
}
17131721

17141722
if (annotationStorage) {
1715-
const value = annotationStorage[this.data.id];
1723+
const value =
1724+
annotationStorage[this.data.id] &&
1725+
annotationStorage[this.data.id].value;
17161726
if (value === undefined) {
17171727
return super.getOperatorList(
17181728
evaluator,
@@ -1767,7 +1777,8 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
17671777
}
17681778

17691779
async _saveCheckbox(evaluator, task, annotationStorage) {
1770-
const value = annotationStorage[this.data.id];
1780+
const value =
1781+
annotationStorage[this.data.id] && annotationStorage[this.data.id].value;
17711782
if (value === undefined) {
17721783
return null;
17731784
}
@@ -1809,7 +1820,8 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
18091820
}
18101821

18111822
async _saveRadioButton(evaluator, task, annotationStorage) {
1812-
const value = annotationStorage[this.data.id];
1823+
const value =
1824+
annotationStorage[this.data.id] && annotationStorage[this.data.id].value;
18131825
if (value === undefined) {
18141826
return null;
18151827
}

src/core/document.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,10 @@ class Page {
347347
// is resolved with the complete operator list for a single annotation.
348348
const opListPromises = [];
349349
for (const annotation of annotations) {
350-
if (isAnnotationRenderable(annotation, intent)) {
350+
if (
351+
isAnnotationRenderable(annotation, intent) &&
352+
(intent !== "print" || !annotation.isHidden(annotationStorage))
353+
) {
351354
opListPromises.push(
352355
annotation
353356
.getOperatorList(

src/display/annotation_layer.js

+21-18
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,9 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
486486
// NOTE: We cannot set the values using `element.value` below, since it
487487
// prevents the AnnotationLayer rasterizer in `test/driver.js`
488488
// from parsing the elements correctly for the reference tests.
489-
const textContent = storage.getOrCreateValue(id, this.data.fieldValue);
489+
const textContent = storage.getOrCreateValue(id, {
490+
value: this.data.fieldValue,
491+
}).value;
490492

491493
if (this.data.multiLine) {
492494
element = document.createElement("textarea");
@@ -500,7 +502,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
500502
element.setAttribute("id", id);
501503

502504
element.addEventListener("input", function (event) {
503-
storage.setValue(id, event.target.value);
505+
storage.setValue(id, { value: event.target.value });
504506
});
505507

506508
element.addEventListener("blur", function (event) {
@@ -625,10 +627,9 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
625627
const storage = this.annotationStorage;
626628
const data = this.data;
627629
const id = data.id;
628-
const value = storage.getOrCreateValue(
629-
id,
630-
data.fieldValue && data.fieldValue !== "Off"
631-
);
630+
const value = storage.getOrCreateValue(id, {
631+
value: data.fieldValue && data.fieldValue !== "Off",
632+
}).value;
632633

633634
this.container.className = "buttonWidgetAnnotation checkBox";
634635

@@ -641,7 +642,7 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
641642
}
642643

643644
element.addEventListener("change", function (event) {
644-
storage.setValue(id, event.target.checked);
645+
storage.setValue(id, { value: event.target.checked });
645646
});
646647

647648
this.container.appendChild(element);
@@ -667,10 +668,9 @@ class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
667668
const storage = this.annotationStorage;
668669
const data = this.data;
669670
const id = data.id;
670-
const value = storage.getOrCreateValue(
671-
id,
672-
data.fieldValue === data.buttonValue
673-
);
671+
const value = storage.getOrCreateValue(id, {
672+
value: data.fieldValue === data.buttonValue,
673+
}).value;
674674

675675
const element = document.createElement("input");
676676
element.disabled = data.readOnly;
@@ -686,11 +686,11 @@ class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
686686
if (radio !== event.target) {
687687
storage.setValue(
688688
radio.parentNode.getAttribute("data-annotation-id"),
689-
false
689+
{ value: false }
690690
);
691691
}
692692
}
693-
storage.setValue(id, event.target.checked);
693+
storage.setValue(id, { value: event.target.checked });
694694
});
695695

696696
this.container.appendChild(element);
@@ -747,10 +747,10 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
747747
// two field types is implemented, we should use the same pattern as the
748748
// other interactive widgets where the return value of `getOrCreateValue` is
749749
// used and the full array of field values is stored.
750-
storage.getOrCreateValue(
751-
id,
752-
this.data.fieldValue.length > 0 ? this.data.fieldValue[0] : undefined
753-
);
750+
storage.getOrCreateValue(id, {
751+
value:
752+
this.data.fieldValue.length > 0 ? this.data.fieldValue[0] : undefined,
753+
});
754754

755755
const selectElement = document.createElement("select");
756756
selectElement.disabled = this.data.readOnly;
@@ -778,7 +778,7 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
778778
selectElement.addEventListener("input", function (event) {
779779
const options = event.target.options;
780780
const value = options[options.selectedIndex].value;
781-
storage.setValue(id, value);
781+
storage.setValue(id, { value });
782782
});
783783

784784
this.container.appendChild(selectElement);
@@ -1611,6 +1611,9 @@ class AnnotationLayer {
16111611
});
16121612
if (element.isRenderable) {
16131613
const rendered = element.render();
1614+
if (data.hidden) {
1615+
rendered.style.display = "none";
1616+
}
16141617
if (Array.isArray(rendered)) {
16151618
for (const renderedElement of rendered) {
16161619
parameters.div.appendChild(renderedElement);

src/display/annotation_storage.js

+14-2
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,22 @@ class AnnotationStorage {
5959
* @param {Object} value
6060
*/
6161
setValue(key, value) {
62-
if (this._storage.get(key) !== value) {
62+
const obj = this._storage.get(key);
63+
let modified = false;
64+
if (obj !== undefined) {
65+
for (const [entry, val] of Object.entries(value)) {
66+
if (obj[entry] !== val) {
67+
modified = true;
68+
obj[entry] = val;
69+
}
70+
}
71+
} else {
72+
this._storage.set(key, value);
73+
modified = true;
74+
}
75+
if (modified) {
6376
this._setModified();
6477
}
65-
this._storage.set(key, value);
6678
}
6779

6880
getAll() {

test/pdfs/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@
179179
!devicen.pdf
180180
!cmykjpeg.pdf
181181
!issue840.pdf
182+
!160F-2019.pdf
182183
!issue4402_reduced.pdf
183184
!issue845r.pdf
184185
!issue3405r.pdf

test/pdfs/160F-2019.pdf

321 KB
Binary file not shown.

0 commit comments

Comments
 (0)