1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-19 06:38:07 +02:00

Merge pull request #19469 from Snuffleupagus/bug-1947248

[api-major] Apply the `userUnit` using CSS, to fix the text/annotation layers (bug 1947248)
This commit is contained in:
Jonas Jenwald 2025-02-11 23:13:46 +01:00 committed by GitHub
commit d6f63d0e4b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 237 additions and 46 deletions

View file

@ -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 = [];

View file

@ -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);

View file

@ -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;
}
@ -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]);
@ -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");
@ -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))`
: "",
},
};

View file

@ -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],
@ -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) {

View file

@ -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();
@ -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);
@ -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();

View file

@ -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.

View file

@ -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,
@ -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(
@ -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({
@ -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({
@ -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;

View file

@ -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

Binary file not shown.

File diff suppressed because one or more lines are too long

View file

@ -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",

View file

@ -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;
@ -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;

View file

@ -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;
}
@ -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;
}
}
@ -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;
@ -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%;
@ -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;
@ -323,7 +323,7 @@
}
.popup * {
font-size: calc(9px * var(--scale-factor));
font-size: calc(9px * var(--total-scale-factor));
}
.popup > .header {
@ -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 {

View file

@ -147,6 +147,8 @@ class PDFPageView {
#textLayerMode = TextLayerMode.ENABLE;
#userUnit = 1;
#useThumbnailCanvas = {
directDrawing: true,
initialOptionalContent: true,
@ -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;
@ -323,7 +334,7 @@ class PDFPageView {
}
setLayerDimensions(
this.div,
div,
viewport,
/* mustFlip = */ true,
/* mustRotate = */ false

View file

@ -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;

View file

@ -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)`;