Skip to content

Commit 37890e6

Browse files
committed
[api-major] Apply the userUnit using CSS, to fix the text/annotation layers (bug 1947248)
Rather than modifying the "raw" dimensions of the page, we'll instead apply the `userUnit` as an *additional* scale-factor via CSS. *Please note:* It's not clear to me if this solution is fully correct either, or if there's other problems with it, but it at least *appears* to work. --- With these changes, the following CSS variables are now assumed to be available/set as necessary: `--total-scale-factor`, `--scale-factor`, `--user-unit`, `--scale-round-x`, and `--scale-round-y`.
1 parent e3cca6d commit 37890e6

16 files changed

+81
-46
lines changed

src/core/xfa/template.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1421,7 +1421,7 @@ class ChoiceList extends XFAObject {
14211421
const field = ui[$getParent]();
14221422
const fontSize = field.font?.size || 10;
14231423
const optionStyle = {
1424-
fontSize: `calc(${fontSize}px * var(--scale-factor))`,
1424+
fontSize: `calc(${fontSize}px * var(--total-scale-factor))`,
14251425
};
14261426
const children = [];
14271427

src/core/xfa/xhtml.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ function mapStyle(styleStr, node, richText) {
179179
}
180180

181181
if (richText && style.fontSize) {
182-
style.fontSize = `calc(${style.fontSize} * var(--scale-factor))`;
182+
style.fontSize = `calc(${style.fontSize} * var(--total-scale-factor))`;
183183
}
184184

185185
fixTextIndent(style);

src/display/annotation_layer.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -297,10 +297,10 @@ class AnnotationElement {
297297
const horizontalRadius = data.borderStyle.horizontalCornerRadius;
298298
const verticalRadius = data.borderStyle.verticalCornerRadius;
299299
if (horizontalRadius > 0 || verticalRadius > 0) {
300-
const radius = `calc(${horizontalRadius}px * var(--scale-factor)) / calc(${verticalRadius}px * var(--scale-factor))`;
300+
const radius = `calc(${horizontalRadius}px * var(--total-scale-factor)) / calc(${verticalRadius}px * var(--total-scale-factor))`;
301301
style.borderRadius = radius;
302302
} else if (this instanceof RadioButtonWidgetAnnotationElement) {
303-
const radius = `calc(${width}px * var(--scale-factor)) / calc(${height}px * var(--scale-factor))`;
303+
const radius = `calc(${width}px * var(--total-scale-factor)) / calc(${height}px * var(--total-scale-factor))`;
304304
style.borderRadius = radius;
305305
}
306306

@@ -1194,7 +1194,7 @@ class WidgetAnnotationElement extends AnnotationElement {
11941194
roundToOneDecimal(height / LINE_FACTOR)
11951195
);
11961196
}
1197-
style.fontSize = `calc(${computedFontSize}px * var(--scale-factor))`;
1197+
style.fontSize = `calc(${computedFontSize}px * var(--total-scale-factor))`;
11981198

11991199
style.color = Util.makeHexColor(fontColor[0], fontColor[1], fontColor[2]);
12001200

@@ -1553,7 +1553,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
15531553
const combWidth = fieldWidth / maxLen;
15541554

15551555
element.classList.add("comb");
1556-
element.style.letterSpacing = `calc(${combWidth}px * var(--scale-factor) - 1ch)`;
1556+
element.style.letterSpacing = `calc(${combWidth}px * var(--total-scale-factor) - 1ch)`;
15571557
}
15581558
} else {
15591559
element = document.createElement("div");
@@ -2279,7 +2279,7 @@ class PopupElement {
22792279
style: {
22802280
color: this.#fontColor,
22812281
fontSize: this.#fontSize
2282-
? `calc(${this.#fontSize}px * var(--scale-factor))`
2282+
? `calc(${this.#fontSize}px * var(--total-scale-factor))`
22832283
: "",
22842284
},
22852285
};

src/display/display_utils.js

+5-6
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,7 @@ class PageViewport {
213213
* @type {Object}
214214
*/
215215
get rawDims() {
216-
const { userUnit, viewBox } = this;
217-
const dims = viewBox.map(x => x * userUnit);
216+
const dims = this.viewBox;
218217

219218
return shadow(this, "rawDims", {
220219
pageWidth: dims[2] - dims[0],
@@ -597,13 +596,13 @@ function setLayerDimensions(
597596
const { style } = div;
598597
const useRound = FeatureTest.isCSSRoundSupported;
599598

600-
const w = `var(--scale-factor) * ${pageWidth}px`,
601-
h = `var(--scale-factor) * ${pageHeight}px`;
599+
const w = `var(--total-scale-factor) * ${pageWidth}px`,
600+
h = `var(--total-scale-factor) * ${pageHeight}px`;
602601
const widthStr = useRound
603-
? `round(down, ${w}, var(--scale-round-x, 1px))`
602+
? `round(down, ${w}, var(--scale-round-x))`
604603
: `calc(${w})`,
605604
heightStr = useRound
606-
? `round(down, ${h}, var(--scale-round-y, 1px))`
605+
? `round(down, ${h}, var(--scale-round-y))`
607606
: `calc(${h})`;
608607

609608
if (!mustFlip || viewport.rotation % 180 === 0) {

src/display/editor/freetext.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ class FreeTextEditor extends AnnotationEditor {
209209
*/
210210
#updateFontSize(fontSize) {
211211
const setFontsize = size => {
212-
this.editorDiv.style.fontSize = `calc(${size}px * var(--scale-factor))`;
212+
this.editorDiv.style.fontSize = `calc(${size}px * var(--total-scale-factor))`;
213213
this.translate(0, -(size - this.#fontSize) * this.parentScale);
214214
this.#fontSize = size;
215215
this.#setEditorDimensions();
@@ -570,7 +570,7 @@ class FreeTextEditor extends AnnotationEditor {
570570
this.editorDiv.contentEditable = true;
571571

572572
const { style } = this.editorDiv;
573-
style.fontSize = `calc(${this.#fontSize}px * var(--scale-factor))`;
573+
style.fontSize = `calc(${this.#fontSize}px * var(--total-scale-factor))`;
574574
style.color = this.#color;
575575

576576
this.div.append(this.editorDiv);
@@ -878,7 +878,7 @@ class FreeTextEditor extends AnnotationEditor {
878878
return content;
879879
}
880880
const { style } = content;
881-
style.fontSize = `calc(${this.#fontSize}px * var(--scale-factor))`;
881+
style.fontSize = `calc(${this.#fontSize}px * var(--total-scale-factor))`;
882882
style.color = this.#color;
883883

884884
content.replaceChildren();

src/display/text_layer.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ class TextLayer {
342342
top = tx[5] - fontAscent * Math.cos(angle);
343343
}
344344

345-
const scaleFactorStr = "calc(var(--scale-factor)*";
345+
const scaleFactorStr = "calc(var(--total-scale-factor) *";
346346
const divStyle = textDiv.style;
347347
// Setting the style properties individually, rather than all at once,
348348
// should be OK since the `textDiv` isn't appended to the document yet.

test/driver.js

+17-11
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,18 @@ class Rasterize {
215215
return { svg, foreignObject, style, div };
216216
}
217217

218+
static createRootCSS(viewport) {
219+
const { scale, userUnit } = viewport;
220+
return [
221+
":root {",
222+
" --scale-round-x: 1px; --scale-round-y: 1px;",
223+
` --scale-factor: ${scale};`,
224+
` --user-unit: ${userUnit};`,
225+
` --total-scale-factor: ${scale * userUnit};`,
226+
"}",
227+
].join("\n");
228+
}
229+
218230
static async annotationLayer(
219231
ctx,
220232
viewport,
@@ -232,9 +244,7 @@ class Rasterize {
232244
div.className = "annotationLayer";
233245

234246
const [common, overrides] = await this.annotationStylePromise;
235-
style.textContent =
236-
`${common}\n${overrides}\n` +
237-
`:root { --scale-factor: ${viewport.scale} }`;
247+
style.textContent = `${common}\n${overrides}\n${this.createRootCSS(viewport)}`;
238248

239249
const annotationViewport = viewport.clone({ dontFlip: true });
240250
const annotationImageMap = await convertCanvasesToImages(
@@ -293,9 +303,7 @@ class Rasterize {
293303
svg.setAttribute("font-size", 1);
294304

295305
const [common, overrides] = await this.textStylePromise;
296-
style.textContent =
297-
`${common}\n${overrides}\n` +
298-
`:root { --scale-factor: ${viewport.scale} }`;
306+
style.textContent = `${common}\n${overrides}\n${this.createRootCSS(viewport)}`;
299307

300308
// Rendering text layer as HTML.
301309
const textLayer = new TextLayer({
@@ -322,9 +330,7 @@ class Rasterize {
322330
svg.setAttribute("font-size", 1);
323331

324332
const [common, overrides] = await this.drawLayerStylePromise;
325-
style.textContent =
326-
`${common}\n${overrides}` +
327-
`:root { --scale-factor: ${viewport.scale} }`;
333+
style.textContent = `${common}\n${overrides}${this.createRootCSS(viewport)}`;
328334

329335
// Rendering text layer as HTML.
330336
const textLayer = new TextLayer({
@@ -346,9 +352,9 @@ class Rasterize {
346352
let x = parseFloat(left) / 100;
347353
let y = parseFloat(top) / 100;
348354
if (isNaN(x)) {
349-
posRegex ||= /^calc\(var\(--scale-factor\)\*(.*)px\)$/;
355+
posRegex ||= /^calc\(var\(--total-scale-factor\)\s*\*(.*)px\)$/;
350356
// The element is tagged so we've to extract the position from the
351-
// string, e.g. `calc(var(--scale-factor)*66.32px)`.
357+
// string, e.g. `calc(var(--total-scale-factor)*66.32px)`.
352358
let match = left.match(posRegex);
353359
if (match) {
354360
x = parseFloat(match[1]) / pageWidth;

test/pdfs/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,8 @@
559559
!poppler-85140-0.pdf
560560
!issue15012.pdf
561561
!issue19176.pdf
562+
!bug1947248_text.pdf
563+
!bug1947248_forms.pdf
562564
!issue15150.pdf
563565
!poppler-395-0-fuzzed.pdf
564566
!issue14165.pdf

test/pdfs/bug1947248_forms.pdf

11.8 KB
Binary file not shown.

test/pdfs/bug1947248_text.pdf

14.2 KB
Binary file not shown.

test/test_manifest.json

+15
Original file line numberDiff line numberDiff line change
@@ -2749,6 +2749,21 @@
27492749
"rounds": 1,
27502750
"type": "eq"
27512751
},
2752+
{
2753+
"id": "bug1947248-text",
2754+
"file": "pdfs/bug1947248_text.pdf",
2755+
"md5": "491f1df75b77d2762ff96ce51f5e019b",
2756+
"rounds": 1,
2757+
"type": "text"
2758+
},
2759+
{
2760+
"id": "bug1947248-forms",
2761+
"file": "pdfs/bug1947248_forms.pdf",
2762+
"md5": "456c974d7d4351719f36ef10e603d29c",
2763+
"rounds": 1,
2764+
"type": "eq",
2765+
"forms": true
2766+
},
27522767
{
27532768
"id": "issue4801",
27542769
"file": "pdfs/issue4801.pdf",

web/annotation_editor_layer_builder.css

+2-2
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@
123123
background: transparent;
124124
position: absolute;
125125
inset: 0;
126-
font-size: calc(100px * var(--scale-factor));
126+
font-size: calc(100px * var(--total-scale-factor));
127127
transform-origin: 0 0;
128128
cursor: auto;
129129

@@ -512,7 +512,7 @@
512512
}
513513

514514
.annotationEditorLayer .freeTextEditor {
515-
padding: calc(var(--freetext-padding) * var(--scale-factor));
515+
padding: calc(var(--freetext-padding) * var(--total-scale-factor));
516516
width: auto;
517517
height: auto;
518518
touch-action: none;

web/annotation_layer_builder.css

+13-13
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
}
5151

5252
.popupAnnotation .popup {
53-
outline: calc(1.5px * var(--scale-factor)) solid CanvasText !important;
53+
outline: calc(1.5px * var(--total-scale-factor)) solid CanvasText !important;
5454
background-color: ButtonFace !important;
5555
color: ButtonText !important;
5656
}
@@ -67,7 +67,7 @@
6767
}
6868

6969
.popupAnnotation.focused .popup {
70-
outline: calc(3px * var(--scale-factor)) solid Highlight !important;
70+
outline: calc(3px * var(--total-scale-factor)) solid Highlight !important;
7171
}
7272
}
7373

@@ -169,7 +169,7 @@
169169
background-image: var(--annotation-unfocused-field-background);
170170
border: 2px solid var(--input-unfocused-border-color);
171171
box-sizing: border-box;
172-
font: calc(9px * var(--scale-factor)) sans-serif;
172+
font: calc(9px * var(--total-scale-factor)) sans-serif;
173173
height: 100%;
174174
margin: 0;
175175
vertical-align: top;
@@ -296,7 +296,7 @@
296296

297297
.popupAnnotation {
298298
position: absolute;
299-
font-size: calc(9px * var(--scale-factor));
299+
font-size: calc(9px * var(--total-scale-factor));
300300
pointer-events: none;
301301
width: max-content;
302302
max-width: 45%;
@@ -305,11 +305,11 @@
305305

306306
.popup {
307307
background-color: rgb(255 255 153);
308-
box-shadow: 0 calc(2px * var(--scale-factor))
309-
calc(5px * var(--scale-factor)) rgb(136 136 136);
310-
border-radius: calc(2px * var(--scale-factor));
308+
box-shadow: 0 calc(2px * var(--total-scale-factor))
309+
calc(5px * var(--total-scale-factor)) rgb(136 136 136);
310+
border-radius: calc(2px * var(--total-scale-factor));
311311
outline: 1.5px solid rgb(255 255 74);
312-
padding: calc(6px * var(--scale-factor));
312+
padding: calc(6px * var(--total-scale-factor));
313313
cursor: pointer;
314314
font: message-box;
315315
white-space: normal;
@@ -323,7 +323,7 @@
323323
}
324324

325325
.popup * {
326-
font-size: calc(9px * var(--scale-factor));
326+
font-size: calc(9px * var(--total-scale-factor));
327327
}
328328

329329
.popup > .header {
@@ -336,19 +336,19 @@
336336

337337
.popup > .header .popupDate {
338338
display: inline-block;
339-
margin-left: calc(5px * var(--scale-factor));
339+
margin-left: calc(5px * var(--total-scale-factor));
340340
width: fit-content;
341341
}
342342

343343
.popupContent {
344344
border-top: 1px solid rgb(51 51 51);
345-
margin-top: calc(2px * var(--scale-factor));
346-
padding-top: calc(2px * var(--scale-factor));
345+
margin-top: calc(2px * var(--total-scale-factor));
346+
padding-top: calc(2px * var(--total-scale-factor));
347347
}
348348

349349
.richText > * {
350350
white-space: pre-wrap;
351-
font-size: calc(9px * var(--scale-factor));
351+
font-size: calc(9px * var(--total-scale-factor));
352352
}
353353

354354
.popupTriggerArea {

web/pdf_page_view.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ class PDFPageView {
147147

148148
#textLayerMode = TextLayerMode.ENABLE;
149149

150+
#userUnit = 1;
151+
150152
#useThumbnailCanvas = {
151153
directDrawing: true,
152154
initialOptionalContent: true,
@@ -314,7 +316,16 @@ class PDFPageView {
314316
}
315317

316318
#setDimensions() {
317-
const { viewport } = this;
319+
const { div, viewport } = this;
320+
321+
if (viewport.userUnit !== this.#userUnit) {
322+
if (viewport.userUnit !== 1) {
323+
div.style.setProperty("--user-unit", viewport.userUnit);
324+
} else {
325+
div.style.removeProperty("--user-unit");
326+
}
327+
this.#userUnit = viewport.userUnit;
328+
}
318329
if (this.pdfPage) {
319330
if (this.#previousRotation === viewport.rotation) {
320331
return;
@@ -323,7 +334,7 @@ class PDFPageView {
323334
}
324335

325336
setLayerDimensions(
326-
this.div,
337+
div,
327338
viewport,
328339
/* mustFlip = */ true,
329340
/* mustRotate = */ false

web/pdf_viewer.css

+2
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@
100100
}
101101

102102
.pdfViewer .page {
103+
--user-unit: 1;
104+
--total-scale-factor: calc(var(--scale-factor) * var(--user-unit));
103105
--scale-round-x: 1px;
104106
--scale-round-y: 1px;
105107

web/struct_tree_layer_builder.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ class StructTreeLayerBuilder {
204204
img.setAttribute("aria-label", removeNullCharacters(alt));
205205

206206
const { pageHeight, pageX, pageY } = this.#rawDims;
207-
const calc = "calc(var(--scale-factor)*";
207+
const calc = "calc(var(--total-scale-factor) *";
208208
const { style } = img;
209209
style.width = `${calc}${bbox[2] - bbox[0]}px)`;
210210
style.height = `${calc}${bbox[3] - bbox[1]}px)`;

0 commit comments

Comments
 (0)