diff --git a/src/core/annotation.js b/src/core/annotation.js index b0bbf8e1f..bcad74973 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -24,6 +24,7 @@ import { escapeString, getModificationDate, isAscii, + LINE_FACTOR, OPS, RenderingIntentFlag, shadow, @@ -55,11 +56,6 @@ import { StringStream } from "./stream.js"; import { writeDict } from "./writer.js"; import { XFAFactory } from "./xfa/factory.js"; -// Represent the percentage of the height of a single-line field over -// the font size. -// Acrobat seems to use this value. -const LINE_FACTOR = 1.35; - class AnnotationFactory { /** * Create an `Annotation` object of the correct type for the given reference @@ -1921,6 +1917,7 @@ class TextWidgetAnnotation extends WidgetAnnotation { !this.hasFieldFlag(AnnotationFieldFlag.PASSWORD) && !this.hasFieldFlag(AnnotationFieldFlag.FILESELECT) && this.data.maxLen !== null; + this.data.doNotScroll = this.hasFieldFlag(AnnotationFieldFlag.DONOTSCROLL); } _getCombAppearance(defaultAppearance, font, text, width, hPadding, vPadding) { @@ -2788,6 +2785,9 @@ class LinkAnnotation extends Annotation { this.data.quadPoints = quadPoints; } + // The color entry for a link annotation is the color of the border. + this.data.borderColor = this.data.borderColor || this.data.color; + Catalog.parseDestDictionary({ destDict: params.dict, resultObj: this.data, diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index 16c0bed48..66fd47d16 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -22,6 +22,7 @@ import { AnnotationBorderStyleType, AnnotationType, assert, + LINE_FACTOR, shadow, unreachable, Util, @@ -37,6 +38,7 @@ import { ColorConverters } from "../shared/scripting_utils.js"; import { XfaLayer } from "./xfa_layer.js"; const DEFAULT_TAB_INDEX = 1000; +const DEFAULT_FONT_SIZE = 9; const GetElementsByNameSet = new WeakSet(); function getRectDims(rect) { @@ -271,12 +273,12 @@ class AnnotationElement { break; } - const borderColor = data.borderColor || data.color || null; + const borderColor = data.borderColor || null; if (borderColor) { container.style.borderColor = Util.makeHexColor( - data.color[0] | 0, - data.color[1] | 0, - data.color[2] | 0 + borderColor[0] | 0, + borderColor[1] | 0, + borderColor[2] | 0 ); } else { // Transparent (invisible) border, so do not draw it at all. @@ -897,6 +899,53 @@ class WidgetAnnotationElement extends AnnotationElement { ? "transparent" : Util.makeHexColor(color[0], color[1], color[2]); } + + /** + * Apply text styles to the text in the element. + * + * @private + * @param {HTMLDivElement} element + * @memberof TextWidgetAnnotationElement + */ + _setTextStyle(element) { + const TEXT_ALIGNMENT = ["left", "center", "right"]; + const { fontColor } = this.data.defaultAppearanceData; + const fontSize = + this.data.defaultAppearanceData.fontSize || DEFAULT_FONT_SIZE; + + const style = element.style; + + // TODO: If the font-size is zero, calculate it based on the height and + // width of the element. + // Not setting `style.fontSize` will use the default font-size for now. + + // We don't use the font, as specified in the PDF document, for the + // element. Hence using the original `fontSize` could look bad, which is why + // it's instead based on the field height. + // If the height is "big" then it could lead to a too big font size + // so in this case use the one we've in the pdf (hence the min). + if (this.data.multiLine) { + const height = Math.abs(this.data.rect[3] - this.data.rect[1]); + const numberOfLines = Math.round(height / (LINE_FACTOR * fontSize)) || 1; + const lineHeight = height / numberOfLines; + style.fontSize = `${Math.min( + fontSize, + Math.round(lineHeight / LINE_FACTOR) + )}px`; + } else { + const height = Math.abs(this.data.rect[3] - this.data.rect[1]); + style.fontSize = `${Math.min( + fontSize, + Math.round(height / LINE_FACTOR) + )}px`; + } + + style.color = Util.makeHexColor(fontColor[0], fontColor[1], fontColor[2]); + + if (this.data.textAlignment !== null) { + style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment]; + } + } } class TextWidgetAnnotationElement extends WidgetAnnotationElement { @@ -944,10 +993,16 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement { if (this.data.multiLine) { element = document.createElement("textarea"); element.textContent = textContent; + if (this.data.doNotScroll) { + element.style.overflowY = "hidden"; + } } else { element = document.createElement("input"); element.type = "text"; element.setAttribute("value", textContent); + if (this.data.doNotScroll) { + element.style.overflowX = "hidden"; + } } GetElementsByNameSet.add(element); element.disabled = this.data.readOnly; @@ -1177,32 +1232,6 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement { this.container.appendChild(element); return this.container; } - - /** - * Apply text styles to the text in the element. - * - * @private - * @param {HTMLDivElement} element - * @memberof TextWidgetAnnotationElement - */ - _setTextStyle(element) { - const TEXT_ALIGNMENT = ["left", "center", "right"]; - const { fontSize, fontColor } = this.data.defaultAppearanceData; - const style = element.style; - - // TODO: If the font-size is zero, calculate it based on the height and - // width of the element. - // Not setting `style.fontSize` will use the default font-size for now. - if (fontSize) { - style.fontSize = `${fontSize}px`; - } - - style.color = Util.makeHexColor(fontColor[0], fontColor[1], fontColor[2]); - - if (this.data.textAlignment !== null) { - style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment]; - } - } } class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement { @@ -1413,10 +1442,8 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { value: this.data.fieldValue, }); - let { fontSize } = this.data.defaultAppearanceData; - if (!fontSize) { - fontSize = 9; - } + const fontSize = + this.data.defaultAppearanceData.fontSize || DEFAULT_FONT_SIZE; const fontSizeStyle = `calc(${fontSize}px * var(--zoom-factor))`; const selectElement = document.createElement("select"); @@ -1426,8 +1453,6 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { selectElement.setAttribute("id", id); selectElement.tabIndex = DEFAULT_TAB_INDEX; - selectElement.style.fontSize = `${fontSize}px`; - if (!this.data.combo) { // List boxes have a size and (optionally) multiple selection. selectElement.size = this.data.options.length; @@ -1606,6 +1631,12 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { }); } + if (this.data.combo) { + this._setTextStyle(selectElement); + } else { + // Just use the default font size... + // it's a bit hard to guess what is a good size. + } this._setBackgroundColor(selectElement); this._setDefaultPropertiesFromJS(selectElement); diff --git a/src/shared/util.js b/src/shared/util.js index 5e5529e41..665b59d39 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -18,6 +18,10 @@ import "./compatibility.js"; const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; +// Represent the percentage of the height of a single-line field over +// the font size. Acrobat seems to use this value. +const LINE_FACTOR = 1.35; + /** * Refer to the `WorkerTransport.getRenderingIntent`-method in the API, to see * how these flags are being used: @@ -1162,6 +1166,7 @@ export { isArrayBuffer, isArrayEqual, isAscii, + LINE_FACTOR, MissingPDFException, objectFromMap, objectSize, diff --git a/test/driver.js b/test/driver.js index 87b9f5000..bd943b0cb 100644 --- a/test/driver.js +++ b/test/driver.js @@ -751,7 +751,9 @@ class Driver { transform, }; if (renderForms) { - renderContext.annotationMode = AnnotationMode.ENABLE_FORMS; + renderContext.annotationMode = task.annotationStorage + ? AnnotationMode.ENABLE_STORAGE + : AnnotationMode.ENABLE_FORMS; } else if (renderPrint) { if (task.annotationStorage) { renderContext.annotationMode = AnnotationMode.ENABLE_STORAGE; diff --git a/test/pdfs/issue14301.pdf.link b/test/pdfs/issue14301.pdf.link new file mode 100644 index 000000000..63b5eeeb2 --- /dev/null +++ b/test/pdfs/issue14301.pdf.link @@ -0,0 +1,2 @@ +https://github.com/mozilla/pdf.js/files/7594316/formulairecerfa90nov00-1.pdf + diff --git a/test/test_manifest.json b/test/test_manifest.json index 8fd040b75..f88ba2255 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -6507,5 +6507,26 @@ "rounds": 1, "link": true, "type": "other" + }, + { "id": "issue14301", + "file": "pdfs/issue14301.pdf", + "md5": "9973936dcf8dd41daa62c04a4eb621f0", + "rounds": 1, + "link": true, + "firstPage": 2, + "lastPage": 2, + "type": "eq", + "forms": true, + "annotationStorage": { + "1832R": { + "value": "3" + }, + "1827R": { + "value": "2" + }, + "1808R": { + "value": "1" + } + } } ] diff --git a/web/annotation_layer_builder.css b/web/annotation_layer_builder.css index f0aaec32e..68172ac6f 100644 --- a/web/annotation_layer_builder.css +++ b/web/annotation_layer_builder.css @@ -59,10 +59,9 @@ background-image: var(--annotation-unfocused-field-background); border: 1px solid transparent; box-sizing: border-box; - font-size: 9px; + font: 9px sans-serif; height: 100%; margin: 0; - padding: 0 3px; vertical-align: top; width: 100%; } @@ -76,8 +75,6 @@ } .annotationLayer .textWidgetAnnotation textarea { - font: message-box; - font-size: 9px; resize: none; } @@ -167,7 +164,6 @@ .annotationLayer .buttonWidgetAnnotation.checkBox input, .annotationLayer .buttonWidgetAnnotation.radioButton input { appearance: none; - padding: 0; } .annotationLayer .popupWrapper {