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:
commit
d6f63d0e4b
16 changed files with 237 additions and 46 deletions
|
@ -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 = [];
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))`
|
||||
: "",
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
2
test/pdfs/.gitignore
vendored
2
test/pdfs/.gitignore
vendored
|
@ -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
|
||||
|
|
BIN
test/pdfs/bug1947248_forms.pdf
Normal file
BIN
test/pdfs/bug1947248_forms.pdf
Normal file
Binary file not shown.
156
test/pdfs/bug1947248_text.pdf
Normal file
156
test/pdfs/bug1947248_text.pdf
Normal file
File diff suppressed because one or more lines are too long
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)`;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue