Skip to content

[api-major] Apply the userUnit using CSS, to fix the text/annotation layers (bug 1947248) #19469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/core/xfa/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -1421,7 +1421,7 @@ class ChoiceList extends XFAObject {
const field = ui[$getParent]();
const fontSize = field.font?.size || 10;
const optionStyle = {
fontSize: `calc(${fontSize}px * var(--scale-factor))`,
fontSize: `calc(${fontSize}px * var(--total-scale-factor))`,
};
const children = [];

Expand Down
2 changes: 1 addition & 1 deletion src/core/xfa/xhtml.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ function mapStyle(styleStr, node, richText) {
}

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

fixTextIndent(style);
Expand Down
10 changes: 5 additions & 5 deletions src/display/annotation_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,10 @@ class AnnotationElement {
const horizontalRadius = data.borderStyle.horizontalCornerRadius;
const verticalRadius = data.borderStyle.verticalCornerRadius;
if (horizontalRadius > 0 || verticalRadius > 0) {
const radius = `calc(${horizontalRadius}px * var(--scale-factor)) / calc(${verticalRadius}px * var(--scale-factor))`;
const radius = `calc(${horizontalRadius}px * var(--total-scale-factor)) / calc(${verticalRadius}px * var(--total-scale-factor))`;
style.borderRadius = radius;
} else if (this instanceof RadioButtonWidgetAnnotationElement) {
const radius = `calc(${width}px * var(--scale-factor)) / calc(${height}px * var(--scale-factor))`;
const radius = `calc(${width}px * var(--total-scale-factor)) / calc(${height}px * var(--total-scale-factor))`;
style.borderRadius = radius;
}

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

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

Expand Down Expand Up @@ -1553,7 +1553,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
const combWidth = fieldWidth / maxLen;

element.classList.add("comb");
element.style.letterSpacing = `calc(${combWidth}px * var(--scale-factor) - 1ch)`;
element.style.letterSpacing = `calc(${combWidth}px * var(--total-scale-factor) - 1ch)`;
}
} else {
element = document.createElement("div");
Expand Down Expand Up @@ -2279,7 +2279,7 @@ class PopupElement {
style: {
color: this.#fontColor,
fontSize: this.#fontSize
? `calc(${this.#fontSize}px * var(--scale-factor))`
? `calc(${this.#fontSize}px * var(--total-scale-factor))`
: "",
},
};
Expand Down
11 changes: 5 additions & 6 deletions src/display/display_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,7 @@ class PageViewport {
* @type {Object}
*/
get rawDims() {
const { userUnit, viewBox } = this;
const dims = viewBox.map(x => x * userUnit);
const dims = this.viewBox;

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

const w = `var(--scale-factor) * ${pageWidth}px`,
h = `var(--scale-factor) * ${pageHeight}px`;
const w = `var(--total-scale-factor) * ${pageWidth}px`,
h = `var(--total-scale-factor) * ${pageHeight}px`;
const widthStr = useRound
? `round(down, ${w}, var(--scale-round-x, 1px))`
? `round(down, ${w}, var(--scale-round-x))`
: `calc(${w})`,
heightStr = useRound
? `round(down, ${h}, var(--scale-round-y, 1px))`
? `round(down, ${h}, var(--scale-round-y))`
: `calc(${h})`;

if (!mustFlip || viewport.rotation % 180 === 0) {
Expand Down
6 changes: 3 additions & 3 deletions src/display/editor/freetext.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ class FreeTextEditor extends AnnotationEditor {
*/
#updateFontSize(fontSize) {
const setFontsize = size => {
this.editorDiv.style.fontSize = `calc(${size}px * var(--scale-factor))`;
this.editorDiv.style.fontSize = `calc(${size}px * var(--total-scale-factor))`;
this.translate(0, -(size - this.#fontSize) * this.parentScale);
this.#fontSize = size;
this.#setEditorDimensions();
Expand Down Expand Up @@ -570,7 +570,7 @@ class FreeTextEditor extends AnnotationEditor {
this.editorDiv.contentEditable = true;

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

this.div.append(this.editorDiv);
Expand Down Expand Up @@ -878,7 +878,7 @@ class FreeTextEditor extends AnnotationEditor {
return content;
}
const { style } = content;
style.fontSize = `calc(${this.#fontSize}px * var(--scale-factor))`;
style.fontSize = `calc(${this.#fontSize}px * var(--total-scale-factor))`;
style.color = this.#color;

content.replaceChildren();
Expand Down
2 changes: 1 addition & 1 deletion src/display/text_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ class TextLayer {
top = tx[5] - fontAscent * Math.cos(angle);
}

const scaleFactorStr = "calc(var(--scale-factor)*";
const scaleFactorStr = "calc(var(--total-scale-factor) *";
const divStyle = textDiv.style;
// Setting the style properties individually, rather than all at once,
// should be OK since the `textDiv` isn't appended to the document yet.
Expand Down
28 changes: 17 additions & 11 deletions test/driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,18 @@ class Rasterize {
return { svg, foreignObject, style, div };
}

static createRootCSS(viewport) {
const { scale, userUnit } = viewport;
return [
":root {",
" --scale-round-x: 1px; --scale-round-y: 1px;",
` --scale-factor: ${scale};`,
` --user-unit: ${userUnit};`,
` --total-scale-factor: ${scale * userUnit};`,
"}",
].join("\n");
}

static async annotationLayer(
ctx,
viewport,
Expand All @@ -232,9 +244,7 @@ class Rasterize {
div.className = "annotationLayer";

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

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

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

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

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

// Rendering text layer as HTML.
const textLayer = new TextLayer({
Expand All @@ -346,9 +352,9 @@ class Rasterize {
let x = parseFloat(left) / 100;
let y = parseFloat(top) / 100;
if (isNaN(x)) {
posRegex ||= /^calc\(var\(--scale-factor\)\*(.*)px\)$/;
posRegex ||= /^calc\(var\(--total-scale-factor\)\s*\*(.*)px\)$/;
// The element is tagged so we've to extract the position from the
// string, e.g. `calc(var(--scale-factor)*66.32px)`.
// string, e.g. `calc(var(--total-scale-factor)*66.32px)`.
let match = left.match(posRegex);
if (match) {
x = parseFloat(match[1]) / pageWidth;
Expand Down
2 changes: 2 additions & 0 deletions test/pdfs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,8 @@
!poppler-85140-0.pdf
!issue15012.pdf
!issue19176.pdf
!bug1947248_text.pdf
!bug1947248_forms.pdf
!issue15150.pdf
!poppler-395-0-fuzzed.pdf
!issue14165.pdf
Expand Down
Binary file added test/pdfs/bug1947248_forms.pdf
Binary file not shown.
Binary file added test/pdfs/bug1947248_text.pdf
Binary file not shown.
15 changes: 15 additions & 0 deletions test/test_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2749,6 +2749,21 @@
"rounds": 1,
"type": "eq"
},
{
"id": "bug1947248-text",
"file": "pdfs/bug1947248_text.pdf",
"md5": "491f1df75b77d2762ff96ce51f5e019b",
"rounds": 1,
"type": "text"
},
{
"id": "bug1947248-forms",
"file": "pdfs/bug1947248_forms.pdf",
"md5": "456c974d7d4351719f36ef10e603d29c",
"rounds": 1,
"type": "eq",
"forms": true
},
{
"id": "issue4801",
"file": "pdfs/issue4801.pdf",
Expand Down
4 changes: 2 additions & 2 deletions web/annotation_editor_layer_builder.css
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
background: transparent;
position: absolute;
inset: 0;
font-size: calc(100px * var(--scale-factor));
font-size: calc(100px * var(--total-scale-factor));
transform-origin: 0 0;
cursor: auto;

Expand Down Expand Up @@ -512,7 +512,7 @@
}

.annotationEditorLayer .freeTextEditor {
padding: calc(var(--freetext-padding) * var(--scale-factor));
padding: calc(var(--freetext-padding) * var(--total-scale-factor));
width: auto;
height: auto;
touch-action: none;
Expand Down
26 changes: 13 additions & 13 deletions web/annotation_layer_builder.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
}

.popupAnnotation .popup {
outline: calc(1.5px * var(--scale-factor)) solid CanvasText !important;
outline: calc(1.5px * var(--total-scale-factor)) solid CanvasText !important;
background-color: ButtonFace !important;
color: ButtonText !important;
}
Expand All @@ -67,7 +67,7 @@
}

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

Expand Down Expand Up @@ -169,7 +169,7 @@
background-image: var(--annotation-unfocused-field-background);
border: 2px solid var(--input-unfocused-border-color);
box-sizing: border-box;
font: calc(9px * var(--scale-factor)) sans-serif;
font: calc(9px * var(--total-scale-factor)) sans-serif;
height: 100%;
margin: 0;
vertical-align: top;
Expand Down Expand Up @@ -296,7 +296,7 @@

.popupAnnotation {
position: absolute;
font-size: calc(9px * var(--scale-factor));
font-size: calc(9px * var(--total-scale-factor));
pointer-events: none;
width: max-content;
max-width: 45%;
Expand All @@ -305,11 +305,11 @@

.popup {
background-color: rgb(255 255 153);
box-shadow: 0 calc(2px * var(--scale-factor))
calc(5px * var(--scale-factor)) rgb(136 136 136);
border-radius: calc(2px * var(--scale-factor));
box-shadow: 0 calc(2px * var(--total-scale-factor))
calc(5px * var(--total-scale-factor)) rgb(136 136 136);
border-radius: calc(2px * var(--total-scale-factor));
outline: 1.5px solid rgb(255 255 74);
padding: calc(6px * var(--scale-factor));
padding: calc(6px * var(--total-scale-factor));
cursor: pointer;
font: message-box;
white-space: normal;
Expand All @@ -323,7 +323,7 @@
}

.popup * {
font-size: calc(9px * var(--scale-factor));
font-size: calc(9px * var(--total-scale-factor));
}

.popup > .header {
Expand All @@ -336,19 +336,19 @@

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

.popupContent {
border-top: 1px solid rgb(51 51 51);
margin-top: calc(2px * var(--scale-factor));
padding-top: calc(2px * var(--scale-factor));
margin-top: calc(2px * var(--total-scale-factor));
padding-top: calc(2px * var(--total-scale-factor));
}

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

.popupTriggerArea {
Expand Down
15 changes: 13 additions & 2 deletions web/pdf_page_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ class PDFPageView {

#textLayerMode = TextLayerMode.ENABLE;

#userUnit = 1;

#useThumbnailCanvas = {
directDrawing: true,
initialOptionalContent: true,
Expand Down Expand Up @@ -314,7 +316,16 @@ class PDFPageView {
}

#setDimensions() {
const { viewport } = this;
const { div, viewport } = this;

if (viewport.userUnit !== this.#userUnit) {
if (viewport.userUnit !== 1) {
div.style.setProperty("--user-unit", viewport.userUnit);
} else {
div.style.removeProperty("--user-unit");
}
this.#userUnit = viewport.userUnit;
}
if (this.pdfPage) {
if (this.#previousRotation === viewport.rotation) {
return;
Expand All @@ -323,7 +334,7 @@ class PDFPageView {
}

setLayerDimensions(
this.div,
div,
viewport,
/* mustFlip = */ true,
/* mustRotate = */ false
Expand Down
2 changes: 2 additions & 0 deletions web/pdf_viewer.css
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
}

.pdfViewer .page {
--user-unit: 1;
--total-scale-factor: calc(var(--scale-factor) * var(--user-unit));
--scale-round-x: 1px;
--scale-round-y: 1px;

Expand Down
2 changes: 1 addition & 1 deletion web/struct_tree_layer_builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ class StructTreeLayerBuilder {
img.setAttribute("aria-label", removeNullCharacters(alt));

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