diff --git a/src/core/annotation.js b/src/core/annotation.js index 690ecace3a852..add90e7c6e74e 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -1791,6 +1791,8 @@ class WidgetAnnotation extends Annotation { return mk.size > 0 ? mk : null; } + amendSavedDict(annotationStorage, dict) {} + async save(evaluator, task, annotationStorage) { const storageEntry = annotationStorage ? annotationStorage.get(this.data.id) @@ -1868,6 +1870,7 @@ class WidgetAnnotation extends Annotation { : stringToUTF16String(val, /* bigEndian = */ true); }; dict.set("V", Array.isArray(value) ? value.map(encoder) : encoder(value)); + this.amendSavedDict(annotationStorage, dict); const maybeMK = this._getMKDict(rotation); if (maybeMK) { @@ -3144,6 +3147,10 @@ class ChoiceWidgetAnnotation extends WidgetAnnotation { super(params); const { dict, xref } = params; + + this.indices = dict.getArray("I"); + this.hasIndices = Array.isArray(this.indices) && this.indices.length > 0; + // Determine the options. The options array may consist of strings or // arrays. If the array consists of arrays, then the first element of // each array is the export value and the second element of each array is @@ -3172,14 +3179,28 @@ class ChoiceWidgetAnnotation extends WidgetAnnotation { } } - // The field value can be `null` if no item is selected, a string if one - // item is selected or an array of strings if multiple items are selected. - // For consistency in the API and convenience in the display layer, we - // always make the field value an array with zero, one or multiple items. - if (typeof this.data.fieldValue === "string") { - this.data.fieldValue = [this.data.fieldValue]; - } else if (!this.data.fieldValue) { + if (!this.hasIndices) { + // The field value can be `null` if no item is selected, a string if one + // item is selected or an array of strings if multiple items are selected. + // For consistency in the API and convenience in the display layer, we + // always make the field value an array with zero, one or multiple items. + if (typeof this.data.fieldValue === "string") { + this.data.fieldValue = [this.data.fieldValue]; + } else if (!this.data.fieldValue) { + this.data.fieldValue = []; + } + } else { + // The specs say that we should have an indices array only with + // multiselectable Choice and the "V" entry should have the + // precedence, but Acrobat itself is using it whatever the + // the "V" entry is (see bug 1770750). this.data.fieldValue = []; + const ii = this.data.options.length; + for (const i of this.indices) { + if (Number.isInteger(i) && i >= 0 && i < ii) { + this.data.fieldValue.push(this.data.options[i].exportValue); + } + } } // Process field flags for the display layer. @@ -3212,6 +3233,28 @@ class ChoiceWidgetAnnotation extends WidgetAnnotation { }; } + amendSavedDict(annotationStorage, dict) { + if (!this.hasIndices) { + return; + } + const storageEntry = annotationStorage + ? annotationStorage.get(this.data.id) + : undefined; + let values = storageEntry && storageEntry.value; + if (!Array.isArray(values)) { + values = [values]; + } + const indices = []; + const { options } = this.data; + for (let i = 0, j = 0, ii = options.length; i < ii; i++) { + if (options[i].exportValue === values[j]) { + indices.push(i); + j += 1; + } + } + dict.set("I", indices); + } + async _getAppearance(evaluator, task, intent, annotationStorage) { if (this.data.combo) { return super._getAppearance(evaluator, task, intent, annotationStorage); diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 73ddec55f1915..17b77b87e4cad 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -573,3 +573,4 @@ !bug1811510.pdf !bug1815476.pdf !issue16021.pdf +!bug1770750.pdf diff --git a/test/pdfs/bug1770750.pdf b/test/pdfs/bug1770750.pdf new file mode 100755 index 0000000000000..1e5ee370605d1 Binary files /dev/null and b/test/pdfs/bug1770750.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index 75e67684c654d..2137c1ce7b23f 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -7356,5 +7356,13 @@ "md5": "78a12254cac90ba5219a4c5555ea35ed", "rounds": 1, "type": "eq" + }, + { + "id": "bug1770750-annotations", + "file": "pdfs/bug1770750.pdf", + "md5": "01e6d77eac90b4b08d75240d3db2b826", + "rounds": 1, + "type": "eq", + "annotations": true } ]