@stll/folio-core 0.29.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/controller/folioEditor.d.ts +28 -1
- package/dist/controller/folioEditor.js +37 -26
- package/dist/controller/fontReadiness.js +28 -24
- package/dist/controller/hiddenEditorManager.d.ts +2 -7
- package/dist/controller/layoutPipeline.js +33 -3
- package/dist/controller/noteEditorManager.d.ts +3 -6
- package/dist/docx/metafileSvg.d.ts +12 -0
- package/dist/docx/metafileSvg.js +462 -0
- package/dist/docx/paragraphTextBoxEnrichment.js +55 -4
- package/dist/docx/parser.d.ts +2 -2
- package/dist/docx/parser.js +26 -0
- package/dist/docx/runParser.js +2 -1
- package/dist/docx/serializer/runSerializer.js +14 -2
- package/dist/docx/server/createBilingualDocument.d.ts +20 -3
- package/dist/docx/server/createBilingualDocument.js +153 -22
- package/dist/docx/styleParser.js +2 -1
- package/dist/docx/textBoxParser.js +14 -0
- package/dist/docx/vmlImageParser.js +72 -152
- package/dist/docx/vmlPreview.d.ts +31 -0
- package/dist/docx/vmlPreview.js +535 -0
- package/dist/docx/wrapTypes.d.ts +2 -36
- package/dist/docx/wrapTypes.js +1 -39
- package/dist/fonts/fontAlternates.d.ts +8 -0
- package/dist/fonts/fontAlternates.js +16 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +34 -3
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +5 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +3 -0
- package/dist/layout-bridge/convert/toFlowBlocks.js +78 -28
- package/dist/layout-bridge/dom/noteStoryDom.d.ts +1 -1
- package/dist/layout-bridge/engine/selectionRects.js +3 -1
- package/dist/layout-engine/index.js +65 -32
- package/dist/layout-engine/justifiedLineFit.d.ts +7 -0
- package/dist/layout-engine/justifiedLineFit.js +6 -0
- package/dist/layout-engine/keep-together.js +15 -10
- package/dist/layout-engine/measure/complexScriptFormatting.d.ts +6 -1
- package/dist/layout-engine/measure/complexScriptFormatting.js +11 -2
- package/dist/layout-engine/measure/floatingTablePosition.d.ts +16 -1
- package/dist/layout-engine/measure/floatingTablePosition.js +29 -6
- package/dist/layout-engine/measure/lineBreakProvider.js +67 -8
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
- package/dist/layout-engine/measure/listMarkerWidth.js +23 -10
- package/dist/layout-engine/measure/measureBlocks.d.ts +15 -0
- package/dist/layout-engine/measure/measureBlocks.js +197 -30
- package/dist/layout-engine/measure/measureContainer.js +20 -24
- package/dist/layout-engine/measure/measureHelpers.d.ts +1 -1
- package/dist/layout-engine/measure/measureHelpers.js +14 -8
- package/dist/layout-engine/measure/measureParagraph.js +111 -37
- package/dist/layout-engine/measure/measureTypes.d.ts +3 -0
- package/dist/layout-engine/measure/tabCalculator.d.ts +123 -0
- package/dist/layout-engine/measure/tabCalculator.js +144 -0
- package/dist/layout-engine/measure/tableCellFlow.d.ts +21 -1
- package/dist/layout-engine/measure/tableCellFlow.js +45 -8
- package/dist/layout-engine/measure/tableInlinePlacement.d.ts +10 -2
- package/dist/layout-engine/measure/tableInlinePlacement.js +17 -15
- package/dist/layout-engine/paginator.d.ts +26 -2
- package/dist/layout-engine/paginator.js +76 -14
- package/dist/layout-engine/paragraphSpacing.d.ts +3 -1
- package/dist/layout-engine/paragraphSpacing.js +4 -3
- package/dist/layout-engine/renderedBreakReconciliation.d.ts +14 -3
- package/dist/layout-engine/renderedBreakReconciliation.js +45 -14
- package/dist/layout-engine/section-breaks.d.ts +3 -1
- package/dist/layout-engine/section-breaks.js +6 -2
- package/dist/layout-engine/types.d.ts +18 -1
- package/dist/layout-engine/types.js +1 -1
- package/dist/layout-painter/imageLayout.d.ts +1 -1
- package/dist/layout-painter/renderPage.js +6 -1
- package/dist/layout-painter/renderParagraph.js +169 -82
- package/dist/layout-painter/renderTable.d.ts +1 -1
- package/dist/layout-painter/renderTable.js +18 -7
- package/dist/layout-painter/renderTextBox.d.ts +1 -1
- package/dist/layout-painter/renderTextBox.js +6 -1
- package/dist/model.d.ts +3 -3
- package/dist/model.js +2 -2
- package/dist/paged-layout/sectionBlockWidths.d.ts +14 -0
- package/dist/paged-layout/sectionBlockWidths.js +103 -14
- package/dist/prosemirror/attrs/index.js +12 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +6 -2
- package/dist/prosemirror/conversion/toProseDoc.js +10 -3
- package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +9 -5
- package/dist/prosemirror/extensions/nodes/TableExtension.js +2 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +6 -2
- package/dist/prosemirror/schema/nodes.d.ts +4 -0
- package/dist/prosemirror/utils/tabCalculator.d.ts +2 -123
- package/dist/prosemirror/utils/tabCalculator.js +1 -140
- package/dist/render-dom/RemoteSelectionOverlay.d.ts +4 -4
- package/dist/server.d.ts +2 -2
- package/dist/server.js +2 -2
- package/dist/types/documentEnumValues.d.ts +4 -1
- package/dist/types/documentEnumValues.js +12 -1
- package/dist/types/editor-story.d.ts +8 -0
- package/dist/types/editor-story.js +0 -0
- package/dist/types/remote-selection.d.ts +11 -0
- package/dist/types/remote-selection.js +0 -0
- package/dist/types/wrap.d.ts +36 -0
- package/dist/types/wrap.js +40 -0
- package/dist/utils/fontResolver.d.ts +1 -1
- package/dist/utils/fontResolver.js +42 -2
- package/dist/utils/formatToStyle.js +4 -2
- package/dist/utils/horizontalScale.d.ts +28 -0
- package/dist/utils/horizontalScale.js +42 -0
- package/package.json +2 -2
|
@@ -29,6 +29,8 @@ type RunFormatting = {
|
|
|
29
29
|
*/
|
|
30
30
|
shading?: string;
|
|
31
31
|
fontFamily?: string;
|
|
32
|
+
/** OOXML `w:altName` fallback for `fontFamily`, used only when the primary face is absent. */
|
|
33
|
+
alternateFontFamily?: string;
|
|
32
34
|
/**
|
|
33
35
|
* Resolved East-Asian font (`w:eastAsia` / `eastAsiaTheme`). CJK code points
|
|
34
36
|
* in this run measure and paint with this font; non-CJK keeps `fontFamily`
|
|
@@ -37,6 +39,8 @@ type RunFormatting = {
|
|
|
37
39
|
* to `fontFamily`.
|
|
38
40
|
*/
|
|
39
41
|
eastAsiaFontFamily?: string;
|
|
42
|
+
/** OOXML alternate-name fallback for `eastAsiaFontFamily`. */
|
|
43
|
+
eastAsiaAlternateFontFamily?: string;
|
|
40
44
|
/**
|
|
41
45
|
* Resolved complex-script font (`w:cs` / `cstheme`). Arabic, Hebrew, Indic
|
|
42
46
|
* and South-East Asian code points in this run measure and paint with this
|
|
@@ -46,6 +50,8 @@ type RunFormatting = {
|
|
|
46
50
|
* does NOT do and is why this slot has to reach layout at all.
|
|
47
51
|
*/
|
|
48
52
|
complexScriptFontFamily?: string;
|
|
53
|
+
/** OOXML alternate-name fallback for `complexScriptFontFamily`. */
|
|
54
|
+
complexScriptAlternateFontFamily?: string;
|
|
49
55
|
/** Independent complex-script size (`w:szCs`), in points. */
|
|
50
56
|
complexScriptFontSize?: number;
|
|
51
57
|
/** Independent complex-script weight (`w:bCs`). */
|
|
@@ -127,7 +133,7 @@ type RunFormatting = {
|
|
|
127
133
|
/** Groups a suggestion's runs for accept/reject and scroll-to. */
|
|
128
134
|
suggestionId?: string;
|
|
129
135
|
};
|
|
130
|
-
type ListMarkerFormatting = Pick<RunFormatting, "fontFamily" | "eastAsiaFontFamily" | "complexScriptFontFamily" | "fontSize" | "complexScriptFontSize" | "bold" | "complexScriptBold" | "italic" | "complexScriptItalic" | "rtl" | "forceComplexScript">;
|
|
136
|
+
type ListMarkerFormatting = Pick<RunFormatting, "fontFamily" | "alternateFontFamily" | "eastAsiaFontFamily" | "eastAsiaAlternateFontFamily" | "complexScriptFontFamily" | "complexScriptAlternateFontFamily" | "fontSize" | "complexScriptFontSize" | "bold" | "complexScriptBold" | "italic" | "complexScriptItalic" | "rtl" | "forceComplexScript">;
|
|
131
137
|
/**
|
|
132
138
|
* Hyperlink information for a run.
|
|
133
139
|
*/
|
|
@@ -500,6 +506,8 @@ type ParagraphAttrs = {
|
|
|
500
506
|
listMarkerSecondSlotOffsetTwips?: number;
|
|
501
507
|
defaultFontSize?: number;
|
|
502
508
|
defaultFontFamily?: string;
|
|
509
|
+
/** OOXML alternate-name fallback for `defaultFontFamily`. */
|
|
510
|
+
defaultAlternateFontFamily?: string;
|
|
503
511
|
/**
|
|
504
512
|
* Document-wide `w:defaultTabStop` (§17.6.13) in twips. Read by the list
|
|
505
513
|
* marker tab-stop math so long markers align body text at the document's
|
|
@@ -591,6 +599,8 @@ type TableRow = {
|
|
|
591
599
|
gridAfter?: number;
|
|
592
600
|
height?: number;
|
|
593
601
|
heightRule?: "auto" | "atLeast" | "exact";
|
|
602
|
+
/** Effective row-level table justification after OOXML precedence. */
|
|
603
|
+
justification?: "left" | "center" | "right";
|
|
594
604
|
isHeader?: boolean;
|
|
595
605
|
/** `w:cantSplit`: keep this row in one flow region. */
|
|
596
606
|
cantSplit?: boolean;
|
|
@@ -765,6 +775,8 @@ type TextBoxBlock = {
|
|
|
765
775
|
autoFit?: ShapeTextBody["autoFit"];
|
|
766
776
|
/** Horizontal text wrapping inside the box */
|
|
767
777
|
textWrap?: ShapeTextBody["textWrap"];
|
|
778
|
+
/** Vertical text alignment inside the box */
|
|
779
|
+
verticalAlign?: ShapeTextBody["anchor"];
|
|
768
780
|
/** Fill/background color */
|
|
769
781
|
fillColor?: string;
|
|
770
782
|
/** Border width in pixels */
|
|
@@ -868,6 +880,11 @@ type MeasuredLine = {
|
|
|
868
880
|
descent: number;
|
|
869
881
|
/** Total line height in pixels. */
|
|
870
882
|
lineHeight: number;
|
|
883
|
+
/** Paint adjustment admitted by measurement for this line. */
|
|
884
|
+
justificationPaint?: {
|
|
885
|
+
type: "space-contraction";
|
|
886
|
+
contractionPx: number;
|
|
887
|
+
};
|
|
871
888
|
/** Left offset from floating images (pixels from content left edge). */
|
|
872
889
|
leftOffset?: number;
|
|
873
890
|
/** Right offset from floating images (pixels from content right edge). */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { isFloatingWrapType, isWrapNone } from "../
|
|
2
|
+
import { isFloatingWrapType, isWrapNone } from "../types/wrap.js";
|
|
3
3
|
//#region src/layout-engine/types.ts
|
|
4
4
|
var types_exports = /* @__PURE__ */ __exportAll({
|
|
5
5
|
DEFAULT_TEXTBOX_MARGINS: () => DEFAULT_TEXTBOX_MARGINS,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FlowBlock, Measure } from "../layout-engine/types.js";
|
|
2
2
|
import { ImageAttrs } from "../prosemirror/schema/nodes.js";
|
|
3
3
|
import { BlockLookup } from "./index.js";
|
|
4
|
-
import { WrapType } from "../
|
|
4
|
+
import { WrapType } from "../types/wrap.js";
|
|
5
5
|
//#region src/layout-painter/imageLayout.d.ts
|
|
6
6
|
/**
|
|
7
7
|
* Anchored wrap-type targets — the OOXML wrap types except `inline`.
|
|
@@ -4,6 +4,7 @@ import { measureParagraph } from "../layout-engine/measure/measureParagraph.js";
|
|
|
4
4
|
import { floatingTextBoxReservesBand, floatingTextBoxWrapsText, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun } from "../layout-engine/types.js";
|
|
5
5
|
import { resolveFontFamily } from "../utils/fontResolver.js";
|
|
6
6
|
import { borderToStyle } from "../utils/formatToStyle.js";
|
|
7
|
+
import { normalizeHorizontalScalePercent } from "../utils/horizontalScale.js";
|
|
7
8
|
import { applySanitizedImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
8
9
|
import { eighthsToPixels, pointsToPixels } from "../utils/units.js";
|
|
9
10
|
import { resolveAnchoredImagePosition as resolveAnchoredImagePosition$1 } from "./anchoredImagePosition.js";
|
|
@@ -1335,12 +1336,15 @@ function runContentKey(run) {
|
|
|
1335
1336
|
if (run.color) parts.push(`c:${run.color}`);
|
|
1336
1337
|
if (run.highlight) parts.push(`hi:${run.highlight}`);
|
|
1337
1338
|
if (run.fontFamily) parts.push(`ff:${run.fontFamily}`);
|
|
1339
|
+
if (run.alternateFontFamily) parts.push(`ff-alt:${run.alternateFontFamily}`);
|
|
1338
1340
|
if (run.complexScriptFontFamily) parts.push(`cs:${run.complexScriptFontFamily}`);
|
|
1341
|
+
if (run.complexScriptAlternateFontFamily) parts.push(`cs-alt:${run.complexScriptAlternateFontFamily}`);
|
|
1339
1342
|
if (run.complexScriptFontSize !== void 0) parts.push(`cs-size:${run.complexScriptFontSize}`);
|
|
1340
1343
|
if (run.complexScriptBold !== void 0) parts.push(`cs-bold:${run.complexScriptBold}`);
|
|
1341
1344
|
if (run.complexScriptItalic !== void 0) parts.push(`cs-italic:${run.complexScriptItalic}`);
|
|
1342
1345
|
if (run.forceComplexScript !== void 0) parts.push(`cs-force:${run.forceComplexScript}`);
|
|
1343
1346
|
if (run.eastAsiaFontFamily) parts.push(`ea:${run.eastAsiaFontFamily}`);
|
|
1347
|
+
if (run.eastAsiaAlternateFontFamily) parts.push(`ea-alt:${run.eastAsiaAlternateFontFamily}`);
|
|
1344
1348
|
if (run.fontSize !== void 0) parts.push(`fs:${run.fontSize}`);
|
|
1345
1349
|
if (run.letterSpacing !== void 0) parts.push(`ls:${run.letterSpacing}`);
|
|
1346
1350
|
if (run.superscript) parts.push("sup");
|
|
@@ -1348,7 +1352,8 @@ function runContentKey(run) {
|
|
|
1348
1352
|
if (run.allCaps) parts.push("ac");
|
|
1349
1353
|
if (run.smallCaps) parts.push("sc");
|
|
1350
1354
|
if (run.positionPx !== void 0) parts.push(`pp:${run.positionPx}`);
|
|
1351
|
-
|
|
1355
|
+
const horizontalScale = normalizeHorizontalScalePercent(run.horizontalScale);
|
|
1356
|
+
if (horizontalScale !== void 0 && horizontalScale !== 100) parts.push(`hs:${horizontalScale}`);
|
|
1352
1357
|
if (run.imprint) parts.push("imp");
|
|
1353
1358
|
if (run.emboss) parts.push("emb");
|
|
1354
1359
|
if (run.textShadow) parts.push("sh");
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { ommlToMathml } from "../docx/mathToMathml.js";
|
|
2
2
|
import { parseXmlDocument } from "../docx/xmlParser.js";
|
|
3
3
|
import { evaluateFieldInstruction } from "../fields/evaluateField.js";
|
|
4
|
-
import { hasComplexScriptFormatting, resolveComplexScriptFormatting } from "../layout-engine/measure/complexScriptFormatting.js";
|
|
4
|
+
import { applyComplexScriptFormatting, hasComplexScriptFormatting, resolveComplexScriptFormatting } from "../layout-engine/measure/complexScriptFormatting.js";
|
|
5
5
|
import { getHyperlinkInstanceIndex } from "../layout-engine/measure/hyperlinkInstance.js";
|
|
6
6
|
import { getListMarkerInlineWidth, getListMarkerVisualOffset, resolveListMarkerFont } from "../layout-engine/measure/listMarkerWidth.js";
|
|
7
7
|
import { DOCX_SCRIPT_FONT_SCALE } from "../layout-engine/measure/measureHelpers.js";
|
|
8
|
+
import { calculateTabWidth } from "../layout-engine/measure/tabCalculator.js";
|
|
8
9
|
import { FONT_KERNING_MODE, countCompressibleSpaces, getFontKerningMode, getRunFontKerningMode, toPaintedText } from "../layout-engine/measure/textMeasurementPolicy.js";
|
|
9
10
|
import { isFloatingImageRun } from "../layout-engine/types.js";
|
|
10
|
-
import { calculateTabWidth } from "../prosemirror/utils/tabCalculator.js";
|
|
11
11
|
import { AUTHOR_COLORS, getAuthorColorIdx } from "../utils/authorColors.js";
|
|
12
12
|
import { resolveFontFamily } from "../utils/fontResolver.js";
|
|
13
13
|
import "../utils/fontWeights.js";
|
|
14
|
+
import { getHorizontalScaleFactor } from "../utils/horizontalScale.js";
|
|
14
15
|
import { resolvePhysicalParagraphInlineLayout } from "../utils/paragraphInlineLayout.js";
|
|
15
16
|
import { inlineImageBoundingBox, parseRotationDegrees, rotatedBoundingBox } from "../utils/rotationBoundingBox.js";
|
|
16
17
|
import { applySanitizedImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
@@ -153,11 +154,18 @@ function getRaisedRunFontSize(run) {
|
|
|
153
154
|
if (run.fontSize) return `${fontSizePtToPx(run.fontSize) * DOCX_SCRIPT_FONT_SCALE}px`;
|
|
154
155
|
return `${DOCX_SCRIPT_FONT_SCALE}em`;
|
|
155
156
|
}
|
|
157
|
+
function applyHorizontalScaleTransform(element, horizontalScale) {
|
|
158
|
+
const horizontalScaleFactor = getHorizontalScaleFactor(horizontalScale);
|
|
159
|
+
if (horizontalScaleFactor === 1) return;
|
|
160
|
+
element.style.display = "inline-block";
|
|
161
|
+
element.style.transform = `scaleX(${horizontalScaleFactor})`;
|
|
162
|
+
element.style.transformOrigin = "left center";
|
|
163
|
+
}
|
|
156
164
|
/**
|
|
157
165
|
* Apply text run styles to an element
|
|
158
166
|
*/
|
|
159
167
|
function applyRunStyles(element, run) {
|
|
160
|
-
if (run.fontFamily) element.style.fontFamily = resolveFontFamily(run.fontFamily).cssFallback;
|
|
168
|
+
if (run.fontFamily) element.style.fontFamily = resolveFontFamily(run.fontFamily, run.alternateFontFamily).cssFallback;
|
|
161
169
|
if (run.fontSize) element.style.fontSize = `${fontSizePtToPx(run.fontSize)}px`;
|
|
162
170
|
if (run.bold) element.style.fontWeight = "700";
|
|
163
171
|
if (run.italic) element.style.fontStyle = "italic";
|
|
@@ -172,11 +180,7 @@ function applyRunStyles(element, run) {
|
|
|
172
180
|
if (run.allCaps) element.style.textTransform = "uppercase";
|
|
173
181
|
if (run.smallCaps) element.style.fontVariant = "small-caps";
|
|
174
182
|
if (run.positionPx) element.style.verticalAlign = `${run.positionPx}px`;
|
|
175
|
-
|
|
176
|
-
element.style.display = "inline-block";
|
|
177
|
-
element.style.transform = `scaleX(${run.horizontalScale / 100})`;
|
|
178
|
-
element.style.transformOrigin = "left center";
|
|
179
|
-
}
|
|
183
|
+
applyHorizontalScaleTransform(element, run.horizontalScale);
|
|
180
184
|
element.style.fontKerning = getRunFontKerningMode(run, 11);
|
|
181
185
|
if (run.emboss) element.style.textShadow = "1px 1px 1px rgba(255,255,255,0.5), -1px -1px 1px rgba(0,0,0,0.3)";
|
|
182
186
|
if (run.imprint) element.style.textShadow = "-1px -1px 1px rgba(255,255,255,0.5), 1px 1px 1px rgba(0,0,0,0.3)";
|
|
@@ -293,9 +297,11 @@ function applyRunStyles(element, run) {
|
|
|
293
297
|
element.style.fontSize = getRaisedRunFontSize(run);
|
|
294
298
|
}
|
|
295
299
|
}
|
|
296
|
-
function reserveScaledAdvance(element, unscaledWidth, horizontalScale) {
|
|
297
|
-
|
|
298
|
-
|
|
300
|
+
function reserveScaledAdvance({ element, unscaledWidth, horizontalScale, visualSpaceContractionPx }) {
|
|
301
|
+
const horizontalScaleFactor = getHorizontalScaleFactor(horizontalScale);
|
|
302
|
+
const visualAdvance = Math.max(0, unscaledWidth * horizontalScaleFactor - (visualSpaceContractionPx ?? 0));
|
|
303
|
+
if (horizontalScaleFactor !== 1) element.style.width = `${visualAdvance}px`;
|
|
304
|
+
return visualAdvance;
|
|
299
305
|
}
|
|
300
306
|
/**
|
|
301
307
|
* Apply PM position data attributes
|
|
@@ -304,10 +310,28 @@ function applyPmPositions(element, pmStart, pmEnd) {
|
|
|
304
310
|
if (pmStart !== void 0) element.dataset["pmStart"] = String(pmStart);
|
|
305
311
|
if (pmEnd !== void 0) element.dataset["pmEnd"] = String(pmEnd);
|
|
306
312
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
313
|
+
const NON_COMPRESSIBLE_WHITESPACE_PATTERN = /([^\S ]+)/gu;
|
|
314
|
+
const HAS_NON_COMPRESSIBLE_WHITESPACE_PATTERN = /[^\S ]/u;
|
|
315
|
+
function appendPaintedText({ host, text, doc, contractedWordSpacing }) {
|
|
316
|
+
if (!contractedWordSpacing) {
|
|
317
|
+
host.textContent = text;
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (!HAS_NON_COMPRESSIBLE_WHITESPACE_PATTERN.test(text)) {
|
|
321
|
+
host.textContent = text;
|
|
322
|
+
host.style.wordSpacing = countCompressibleSpaces(text) > 0 ? contractedWordSpacing : "0";
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
host.style.wordSpacing = "0";
|
|
326
|
+
for (const segment of text.split(NON_COMPRESSIBLE_WHITESPACE_PATTERN)) {
|
|
327
|
+
if (segment.length === 0) continue;
|
|
328
|
+
const segmentEl = doc.createElement("span");
|
|
329
|
+
segmentEl.textContent = segment;
|
|
330
|
+
segmentEl.style.wordSpacing = countCompressibleSpaces(segment) > 0 ? contractedWordSpacing : "0";
|
|
331
|
+
host.append(segmentEl);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function renderTextRun(run, doc, options) {
|
|
311
335
|
const span = doc.createElement("span");
|
|
312
336
|
span.className = `${PARAGRAPH_CLASS_NAMES.run} ${PARAGRAPH_CLASS_NAMES.text}`;
|
|
313
337
|
if (run.footnoteRefId !== void 0) {
|
|
@@ -324,18 +348,26 @@ function renderTextRun(run, doc, hyperlinkDirection) {
|
|
|
324
348
|
applyRunStyles(span, run);
|
|
325
349
|
applyPmPositions(span, run.pmStart, run.pmEnd);
|
|
326
350
|
const paintedText = toPaintedText(run.text);
|
|
351
|
+
const visualSpaceContractionPx = options?.visualSpaceContractionPx;
|
|
352
|
+
const effectiveHorizontalScaleFactor = getHorizontalScaleFactor(run.horizontalScale) * (options?.ancestorHorizontalScaleFactor ?? 1);
|
|
353
|
+
const contractedWordSpacing = visualSpaceContractionPx === void 0 || effectiveHorizontalScaleFactor === 0 ? void 0 : `${-visualSpaceContractionPx / effectiveHorizontalScaleFactor}px`;
|
|
327
354
|
const isBookmarkTarget = run.hyperlink?.href.startsWith("#") === true;
|
|
328
355
|
const hyperlinkHref = resolveHyperlinkHref(run.hyperlink?.href, isBookmarkTarget);
|
|
329
356
|
if (run.hyperlink && hyperlinkHref !== void 0) {
|
|
330
357
|
const anchor = doc.createElement("a");
|
|
331
358
|
anchor.href = hyperlinkHref;
|
|
332
|
-
if (hyperlinkDirection || DISPLAYED_URL_PATTERN.test(paintedText.trim())) anchor.dir = LEFT_TO_RIGHT_DIRECTION;
|
|
359
|
+
if (options?.hyperlinkDirection || DISPLAYED_URL_PATTERN.test(paintedText.trim())) anchor.dir = LEFT_TO_RIGHT_DIRECTION;
|
|
333
360
|
if (!isBookmarkTarget) {
|
|
334
361
|
anchor.target = "_blank";
|
|
335
362
|
anchor.rel = "noopener noreferrer";
|
|
336
363
|
}
|
|
337
364
|
if (run.hyperlink.tooltip) anchor.title = run.hyperlink.tooltip;
|
|
338
|
-
|
|
365
|
+
appendPaintedText({
|
|
366
|
+
host: anchor,
|
|
367
|
+
text: paintedText,
|
|
368
|
+
doc,
|
|
369
|
+
...contractedWordSpacing !== void 0 ? { contractedWordSpacing } : {}
|
|
370
|
+
});
|
|
339
371
|
if (!run.hyperlink.noDefaultStyle) {
|
|
340
372
|
const hyperlinkColor = getHyperlinkTextColor(run, span.style.color);
|
|
341
373
|
anchor.style.color = hyperlinkColor;
|
|
@@ -349,7 +381,12 @@ function renderTextRun(run, doc, hyperlinkDirection) {
|
|
|
349
381
|
}
|
|
350
382
|
}
|
|
351
383
|
span.append(anchor);
|
|
352
|
-
} else
|
|
384
|
+
} else appendPaintedText({
|
|
385
|
+
host: span,
|
|
386
|
+
text: paintedText,
|
|
387
|
+
doc,
|
|
388
|
+
...contractedWordSpacing !== void 0 ? { contractedWordSpacing } : {}
|
|
389
|
+
});
|
|
353
390
|
applyWhitespaceUnderline(span, run);
|
|
354
391
|
return span;
|
|
355
392
|
}
|
|
@@ -648,40 +685,36 @@ function resolveFieldText(run, context) {
|
|
|
648
685
|
...run.fldLock ? { locked: true } : {}
|
|
649
686
|
});
|
|
650
687
|
}
|
|
651
|
-
function renderFieldRun(run, doc, context) {
|
|
688
|
+
function renderFieldRun(run, doc, { context, visualSpaceContractionPx }) {
|
|
652
689
|
const text = resolveFieldText(run, context);
|
|
653
690
|
const resolvedRun = {
|
|
654
691
|
...run,
|
|
655
692
|
kind: "text",
|
|
656
693
|
text
|
|
657
694
|
};
|
|
658
|
-
if (resolvedRun.forceComplexScript && hasComplexScriptFormatting(resolvedRun)) return renderTextRun({
|
|
659
|
-
...resolvedRun,
|
|
660
|
-
...resolveComplexScriptFormatting(resolvedRun)
|
|
661
|
-
}, doc);
|
|
695
|
+
if (resolvedRun.forceComplexScript && hasComplexScriptFormatting(resolvedRun)) return renderTextRun(applyComplexScriptFormatting(resolvedRun, resolvedRun), doc, { ...visualSpaceContractionPx !== void 0 ? { visualSpaceContractionPx } : {} });
|
|
662
696
|
if (needsPerScriptSpans({
|
|
663
697
|
...resolvedRun,
|
|
664
698
|
text
|
|
665
699
|
})) {
|
|
666
700
|
const wrapper = doc.createElement("span");
|
|
667
701
|
applyPmPositions(wrapper, resolvedRun.pmStart, resolvedRun.pmEnd);
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
wrapper.style.transform = `scaleX(${resolvedRun.horizontalScale / 100})`;
|
|
671
|
-
wrapper.style.transformOrigin = "left center";
|
|
672
|
-
}
|
|
702
|
+
const horizontalScaleFactor = getHorizontalScaleFactor(resolvedRun.horizontalScale);
|
|
703
|
+
applyHorizontalScaleTransform(wrapper, resolvedRun.horizontalScale);
|
|
673
704
|
const { pmStart: _pmStart, pmEnd: _pmEnd, horizontalScale: _horizontalScale, ...segmentBase } = resolvedRun;
|
|
674
705
|
for (const segment of segmentByScript(text)) {
|
|
675
|
-
const segmentRun = {
|
|
706
|
+
const segmentRun = formatTextRunForScript({
|
|
676
707
|
...segmentBase,
|
|
677
|
-
text: segment.text
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
708
|
+
text: segment.text
|
|
709
|
+
}, segment.script);
|
|
710
|
+
wrapper.append(renderTextRun(segmentRun, doc, {
|
|
711
|
+
...visualSpaceContractionPx !== void 0 ? { visualSpaceContractionPx } : {},
|
|
712
|
+
ancestorHorizontalScaleFactor: horizontalScaleFactor
|
|
713
|
+
}));
|
|
681
714
|
}
|
|
682
715
|
return wrapper;
|
|
683
716
|
}
|
|
684
|
-
return renderTextRun(resolvedRun, doc);
|
|
717
|
+
return renderTextRun(resolvedRun, doc, { ...visualSpaceContractionPx !== void 0 ? { visualSpaceContractionPx } : {} });
|
|
685
718
|
}
|
|
686
719
|
/**
|
|
687
720
|
* Render an OMML math run by converting it to MathML and injecting a
|
|
@@ -710,6 +743,7 @@ function renderMathRun(run, doc) {
|
|
|
710
743
|
host.style.verticalAlign = "middle";
|
|
711
744
|
}
|
|
712
745
|
host.style.fontFamily = "\"Cambria Math\", \"Latin Modern Math\", \"STIX Two Math\", serif";
|
|
746
|
+
applyHorizontalScaleTransform(host, run.horizontalScale);
|
|
713
747
|
try {
|
|
714
748
|
host.innerHTML = mathml;
|
|
715
749
|
} catch {
|
|
@@ -731,6 +765,7 @@ function renderMathFallback(run, doc, fallbackText, errorFlag) {
|
|
|
731
765
|
}
|
|
732
766
|
span.style.fontStyle = "italic";
|
|
733
767
|
span.style.fontFamily = "\"Cambria Math\", \"Latin Modern Math\", \"STIX Two Math\", serif";
|
|
768
|
+
applyHorizontalScaleTransform(span, run.horizontalScale);
|
|
734
769
|
span.textContent = fallbackText;
|
|
735
770
|
applyPmPositions(span, run.pmStart, run.pmEnd);
|
|
736
771
|
return span;
|
|
@@ -743,7 +778,7 @@ function renderRun(run, doc, context) {
|
|
|
743
778
|
if (isTabRun(run)) return renderTabRun(run, doc, 48);
|
|
744
779
|
if (isImageRun(run)) return renderImageRun(run, doc);
|
|
745
780
|
if (isLineBreakRun(run)) return renderLineBreakRun(run, doc);
|
|
746
|
-
if (isFieldRun(run) && context) return renderFieldRun(run, doc, context);
|
|
781
|
+
if (isFieldRun(run) && context) return renderFieldRun(run, doc, { context });
|
|
747
782
|
if (isMathRun(run)) return renderMathRun(run, doc);
|
|
748
783
|
if (run.kind === "renderedPageBreak") {
|
|
749
784
|
const span = doc.createElement("span");
|
|
@@ -793,10 +828,18 @@ function sliceRunsForLine(block, line) {
|
|
|
793
828
|
* The font a script segment paints with, mirroring the measurer's
|
|
794
829
|
* `scriptFontFamily`. Returning undefined leaves the run's own `fontFamily`.
|
|
795
830
|
*/
|
|
796
|
-
const
|
|
797
|
-
if (run.forceComplexScript || script === SCRIPT_CLASS.complex) return
|
|
798
|
-
if (script === SCRIPT_CLASS.eastAsia && run.eastAsiaFontFamily !== void 0)
|
|
799
|
-
|
|
831
|
+
const formatTextRunForScript = (run, script) => {
|
|
832
|
+
if (run.forceComplexScript || script === SCRIPT_CLASS.complex) return applyComplexScriptFormatting(run, run);
|
|
833
|
+
if (script === SCRIPT_CLASS.eastAsia && run.eastAsiaFontFamily !== void 0) {
|
|
834
|
+
const result = {
|
|
835
|
+
...run,
|
|
836
|
+
fontFamily: run.eastAsiaFontFamily
|
|
837
|
+
};
|
|
838
|
+
delete result.alternateFontFamily;
|
|
839
|
+
if (run.eastAsiaAlternateFontFamily !== void 0) result.alternateFontFamily = run.eastAsiaAlternateFontFamily;
|
|
840
|
+
return result;
|
|
841
|
+
}
|
|
842
|
+
return run;
|
|
800
843
|
};
|
|
801
844
|
/**
|
|
802
845
|
* Whether a run needs per-script sibling spans: it carries a script-specific
|
|
@@ -822,10 +865,7 @@ function splitTextRunsByEastAsia(runs) {
|
|
|
822
865
|
const result = [];
|
|
823
866
|
for (const run of runs) {
|
|
824
867
|
if (isTextRun(run) && run.forceComplexScript && hasComplexScriptFormatting(run)) {
|
|
825
|
-
result.push(
|
|
826
|
-
...run,
|
|
827
|
-
...resolveComplexScriptFormatting(run)
|
|
828
|
-
});
|
|
868
|
+
result.push(applyComplexScriptFormatting(run, run));
|
|
829
869
|
continue;
|
|
830
870
|
}
|
|
831
871
|
if (!isTextRun(run) || !needsPerScriptSpans(run)) {
|
|
@@ -834,15 +874,14 @@ function splitTextRunsByEastAsia(runs) {
|
|
|
834
874
|
}
|
|
835
875
|
let offset = 0;
|
|
836
876
|
for (const segment of segmentByScript(run.text)) {
|
|
837
|
-
result.push({
|
|
877
|
+
result.push(formatTextRunForScript({
|
|
838
878
|
...run,
|
|
839
879
|
text: segment.text,
|
|
840
|
-
...scriptFormattingOverride(run, segment.script),
|
|
841
880
|
...run.pmStart !== void 0 ? {
|
|
842
881
|
pmStart: run.pmStart + offset,
|
|
843
882
|
pmEnd: run.pmStart + offset + segment.text.length
|
|
844
883
|
} : {}
|
|
845
|
-
});
|
|
884
|
+
}, segment.script));
|
|
846
885
|
offset += segment.text.length;
|
|
847
886
|
}
|
|
848
887
|
}
|
|
@@ -926,10 +965,19 @@ const startsAfterSoftWrap = (block, line) => {
|
|
|
926
965
|
const RIGHT_EDGE_EPSILON_PX = .5;
|
|
927
966
|
function countShrinkableSpaces(runs, context) {
|
|
928
967
|
let count = 0;
|
|
929
|
-
for (const run of runs) if (isTextRun(run))
|
|
930
|
-
|
|
968
|
+
for (const run of runs) if (isTextRun(run)) {
|
|
969
|
+
if (getHorizontalScaleFactor(run.horizontalScale) === 0) continue;
|
|
970
|
+
count += countCompressibleSpaces(run.text ?? "");
|
|
971
|
+
} else if (isFieldRun(run)) {
|
|
972
|
+
if (getHorizontalScaleFactor(run.horizontalScale) === 0) continue;
|
|
973
|
+
count += countCompressibleSpaces(resolveFieldText(run, context));
|
|
974
|
+
}
|
|
931
975
|
return count;
|
|
932
976
|
}
|
|
977
|
+
function runVisualSpaceContraction({ text, horizontalScale, visualSpaceContractionPx }) {
|
|
978
|
+
if (visualSpaceContractionPx === void 0 || getHorizontalScaleFactor(horizontalScale) === 0) return 0;
|
|
979
|
+
return countCompressibleSpaces(text) * visualSpaceContractionPx;
|
|
980
|
+
}
|
|
933
981
|
/**
|
|
934
982
|
* Build the shared measurement style from a paintable text run.
|
|
935
983
|
*/
|
|
@@ -939,8 +987,11 @@ function runMeasureStyle(run) {
|
|
|
939
987
|
...run.italic !== void 0 ? { italic: run.italic } : {},
|
|
940
988
|
...run.letterSpacing !== void 0 ? { letterSpacing: run.letterSpacing } : {},
|
|
941
989
|
...run.smallCaps !== void 0 ? { smallCaps: run.smallCaps } : {},
|
|
990
|
+
...run.alternateFontFamily !== void 0 ? { alternateFontFamily: run.alternateFontFamily } : {},
|
|
942
991
|
...run.eastAsiaFontFamily !== void 0 ? { eastAsiaFontFamily: run.eastAsiaFontFamily } : {},
|
|
992
|
+
...run.eastAsiaAlternateFontFamily !== void 0 ? { eastAsiaAlternateFontFamily: run.eastAsiaAlternateFontFamily } : {},
|
|
943
993
|
...run.complexScriptFontFamily !== void 0 ? { complexScriptFontFamily: run.complexScriptFontFamily } : {},
|
|
994
|
+
...run.complexScriptAlternateFontFamily !== void 0 ? { complexScriptAlternateFontFamily: run.complexScriptAlternateFontFamily } : {},
|
|
944
995
|
...run.complexScriptFontSize !== void 0 ? { complexScriptFontSize: run.complexScriptFontSize } : {},
|
|
945
996
|
...run.complexScriptBold !== void 0 ? { complexScriptBold: run.complexScriptBold } : {},
|
|
946
997
|
...run.complexScriptItalic !== void 0 ? { complexScriptItalic: run.complexScriptItalic } : {},
|
|
@@ -960,15 +1011,14 @@ function measureFollowingContentWidth(runs, tabRunIndex, measureText, context) {
|
|
|
960
1011
|
for (let i = tabRunIndex + 1; i < runs.length; i++) {
|
|
961
1012
|
const run = runs[i];
|
|
962
1013
|
if (isTabRun(run) || isLineBreakRun(run)) break;
|
|
963
|
-
const scale = run.horizontalScale ?? 100;
|
|
964
1014
|
if (isTextRun(run)) {
|
|
965
1015
|
const text = run.allCaps ? run.text.toLocaleUpperCase() : run.text;
|
|
966
|
-
width += measureText(text, run.fontSize ?? 11, run.fontFamily ?? "Calibri", runMeasureStyle(run)) * (
|
|
1016
|
+
width += measureText(text, run.fontSize ?? 11, run.fontFamily ?? "Calibri", runMeasureStyle(run)) * getHorizontalScaleFactor(run.horizontalScale);
|
|
967
1017
|
} else if (isFieldRun(run)) {
|
|
968
1018
|
const fieldText = resolveFieldText(run, context);
|
|
969
|
-
width += measureText(run.allCaps ? fieldText.toLocaleUpperCase() : fieldText, run.fontSize ?? 11, run.fontFamily ?? "Calibri", runMeasureStyle(run)) * (
|
|
1019
|
+
width += measureText(run.allCaps ? fieldText.toLocaleUpperCase() : fieldText, run.fontSize ?? 11, run.fontFamily ?? "Calibri", runMeasureStyle(run)) * getHorizontalScaleFactor(run.horizontalScale);
|
|
970
1020
|
} else if (isImageRun(run) && !isFloatingImageRun(run)) width += inlineImageBoundingBox(run).width || 0;
|
|
971
|
-
else if (isMathRun(run)) width += measureText(run.plainText, run.fontSize ?? 11, run.fontFamily ?? "Cambria Math", runMeasureStyle(run)) * (
|
|
1021
|
+
else if (isMathRun(run)) width += measureText(run.plainText, run.fontSize ?? 11, run.fontFamily ?? "Cambria Math", runMeasureStyle(run)) * getHorizontalScaleFactor(run.horizontalScale);
|
|
972
1022
|
}
|
|
973
1023
|
return width;
|
|
974
1024
|
}
|
|
@@ -995,8 +1045,8 @@ function measureDecimalPrefixWidth(runs, tabRunIndex, decimalIndex, measureText,
|
|
|
995
1045
|
else runText = run.allCaps ? run.text.toLocaleUpperCase() : run.text;
|
|
996
1046
|
const take = Math.min(runText.length, decimalIndex - consumed);
|
|
997
1047
|
if (take > 0) {
|
|
998
|
-
const
|
|
999
|
-
width += measureText(runText.slice(0, take), run.fontSize ?? 11, run.fontFamily ?? "Calibri", runMeasureStyle(run)) *
|
|
1048
|
+
const horizontalScaleFactor = getHorizontalScaleFactor(run.horizontalScale);
|
|
1049
|
+
width += measureText(runText.slice(0, take), run.fontSize ?? 11, run.fontFamily ?? "Calibri", runMeasureStyle(run)) * horizontalScaleFactor;
|
|
1000
1050
|
}
|
|
1001
1051
|
consumed += runText.length;
|
|
1002
1052
|
}
|
|
@@ -1051,17 +1101,17 @@ function createTextMeasurer(doc) {
|
|
|
1051
1101
|
return (text, fontSize = 11, fontFamily = "Calibri", style = {}) => {
|
|
1052
1102
|
if (!ctx) return applyLetterSpacingToMeasuredWidth(text.length * 7, text, style.letterSpacing);
|
|
1053
1103
|
ctx.fontKerning = getFontKerningMode(style);
|
|
1054
|
-
const fontString = (family, size, bold, italic) => {
|
|
1104
|
+
const fontString = (family, size, bold, italic, alternateFamily) => {
|
|
1055
1105
|
const fontPrefixParts = [];
|
|
1056
1106
|
if (italic) fontPrefixParts.push("italic");
|
|
1057
1107
|
if (style.smallCaps) fontPrefixParts.push("small-caps");
|
|
1058
1108
|
if (bold) fontPrefixParts.push("700");
|
|
1059
1109
|
fontPrefixParts.push(`${size * 96 / 72}px`);
|
|
1060
|
-
return `${fontPrefixParts.join(" ")} ${resolveFontFamily(family).cssFallback}`;
|
|
1110
|
+
return `${fontPrefixParts.join(" ")} ${resolveFontFamily(family, alternateFamily).cssFallback}`;
|
|
1061
1111
|
};
|
|
1062
|
-
const baseFont = fontString(fontFamily, fontSize, style.bold, style.italic);
|
|
1112
|
+
const baseFont = fontString(fontFamily, fontSize, style.bold, style.italic, style.alternateFontFamily);
|
|
1063
1113
|
const complex = resolveComplexScriptFormatting(style);
|
|
1064
|
-
const complexFont = fontString(complex.fontFamily ?? fontFamily, complex.fontSize ?? fontSize, complex.bold ?? style.bold, complex.italic ?? style.italic);
|
|
1114
|
+
const complexFont = fontString(complex.fontFamily ?? fontFamily, complex.fontSize ?? fontSize, complex.bold ?? style.bold, complex.italic ?? style.italic, complex.alternateFontFamily ?? style.alternateFontFamily);
|
|
1065
1115
|
if (style.forceComplexScript) {
|
|
1066
1116
|
ctx.font = complexFont;
|
|
1067
1117
|
return applyLetterSpacingToMeasuredWidth(ctx.measureText(text).width, text, style.letterSpacing);
|
|
@@ -1069,7 +1119,7 @@ function createTextMeasurer(doc) {
|
|
|
1069
1119
|
if (!style.letterSpacing && (style.eastAsiaFontFamily && hasCjk(text) || hasComplexScriptFormatting(style) && hasComplexScript(text))) {
|
|
1070
1120
|
let segmentedWidth = 0;
|
|
1071
1121
|
for (const segment of segmentByScript(text)) {
|
|
1072
|
-
if (segment.script === SCRIPT_CLASS.eastAsia && style.eastAsiaFontFamily) ctx.font = fontString(style.eastAsiaFontFamily, fontSize, style.bold, style.italic);
|
|
1122
|
+
if (segment.script === SCRIPT_CLASS.eastAsia && style.eastAsiaFontFamily) ctx.font = fontString(style.eastAsiaFontFamily, fontSize, style.bold, style.italic, style.eastAsiaAlternateFontFamily);
|
|
1073
1123
|
else if (segment.script === SCRIPT_CLASS.complex) ctx.font = complexFont;
|
|
1074
1124
|
else ctx.font = baseFont;
|
|
1075
1125
|
segmentedWidth += ctx.measureText(segment.text).width;
|
|
@@ -1114,12 +1164,17 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1114
1164
|
if (lineEl.style.display === "flex") return [runEl];
|
|
1115
1165
|
return withCursiveJoiners(runEl, run, cursiveJoinerPlan, applyJoinerRunStyles, doc);
|
|
1116
1166
|
};
|
|
1167
|
+
let visualSpaceContractionPx;
|
|
1117
1168
|
const renderLineTextRun = (run) => {
|
|
1118
|
-
const
|
|
1169
|
+
const hyperlinkDirection = run.hyperlink && options?.leftToRightDisplayedUrlHyperlinks?.has(run.hyperlink) ? LEFT_TO_RIGHT_DIRECTION : void 0;
|
|
1170
|
+
const runEl = renderTextRun(run, doc, {
|
|
1171
|
+
...hyperlinkDirection !== void 0 ? { hyperlinkDirection } : {},
|
|
1172
|
+
...visualSpaceContractionPx !== void 0 ? { visualSpaceContractionPx } : {}
|
|
1173
|
+
});
|
|
1119
1174
|
if (collapsedLeadingSpaceRuns.has(run)) runEl.dataset["collapsedLeadingSpaces"] = "true";
|
|
1120
1175
|
if (collapsedTrailingSpaceRuns.has(run)) runEl.dataset["collapsedTrailingSpaces"] = "true";
|
|
1121
1176
|
if (isCollapsedLineEdgeSpaceRun(run)) {
|
|
1122
|
-
const spaceAdvance = (collapsedSpaceMeasureText?.(" ", run.fontSize || 11, run.fontFamily || "Calibri", runMeasureStyle(run)) ?? 0) * (
|
|
1177
|
+
const spaceAdvance = (collapsedSpaceMeasureText?.(" ", run.fontSize || 11, run.fontFamily || "Calibri", runMeasureStyle(run)) ?? 0) * getHorizontalScaleFactor(run.horizontalScale);
|
|
1123
1178
|
runEl.dataset["collapsedSpaceAdvance"] = String(spaceAdvance);
|
|
1124
1179
|
runEl.style.fontSize = "0";
|
|
1125
1180
|
runEl.style.letterSpacing = "0";
|
|
@@ -1155,19 +1210,24 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1155
1210
|
}
|
|
1156
1211
|
const hasTabRuns = runsForLine.some(isTabRun);
|
|
1157
1212
|
if (alignment === "justify" && options) {
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1213
|
+
const firstLineIndentPx = options.isFirstLine ? options.firstLineIndentPx ?? 0 : 0;
|
|
1214
|
+
const firstLinePositiveIndentPx = Math.max(0, firstLineIndentPx);
|
|
1215
|
+
const firstLineHangingPx = Math.max(0, -firstLineIndentPx);
|
|
1216
|
+
const hasVisibleListMarker = options.isFirstLine && block.attrs?.listMarker && !block.attrs.listMarkerHidden;
|
|
1217
|
+
const firstLineHangingExpansionPx = hasVisibleListMarker ? Math.min(firstLineHangingPx, Math.max(0, options.leftIndentPx ?? 0)) : firstLineHangingPx;
|
|
1218
|
+
const justifyCapacityPx = options.availableWidth - firstLinePositiveIndentPx + firstLineHangingExpansionPx;
|
|
1219
|
+
const overfullPx = line.width - justifyCapacityPx;
|
|
1220
|
+
const shrinkableSpaces = countShrinkableSpaces(runsForLine.filter((run) => !isTextRun(run) || !isCollapsedLineEdgeSpaceRun(run)), options.context);
|
|
1221
|
+
const shouldJustify = !options.isLastLine || options.paragraphEndsWithLineBreak;
|
|
1222
|
+
const finalContractionPx = line.justificationPaint?.type === "space-contraction" ? line.justificationPaint.contractionPx : void 0;
|
|
1223
|
+
const shouldCompressFinalLine = options.isLastLine && finalContractionPx !== void 0 && finalContractionPx > RIGHT_EDGE_EPSILON_PX && overfullPx > RIGHT_EDGE_EPSILON_PX && shrinkableSpaces > 0;
|
|
1224
|
+
if (shouldJustify || shouldCompressFinalLine) {
|
|
1225
|
+
const contractionPx = shouldCompressFinalLine ? finalContractionPx : overfullPx;
|
|
1226
|
+
if (contractionPx > RIGHT_EDGE_EPSILON_PX && shrinkableSpaces > 0) {
|
|
1168
1227
|
lineEl.style.textAlign = "left";
|
|
1169
1228
|
lineEl.style.textAlignLast = "auto";
|
|
1170
|
-
|
|
1229
|
+
visualSpaceContractionPx = contractionPx / shrinkableSpaces;
|
|
1230
|
+
lineEl.style.wordSpacing = "0";
|
|
1171
1231
|
} else if (hasTabRuns && shrinkableSpaces > 0 && -overfullPx > RIGHT_EDGE_EPSILON_PX) {
|
|
1172
1232
|
lineEl.style.textAlign = "left";
|
|
1173
1233
|
lineEl.style.textAlignLast = "auto";
|
|
@@ -1183,7 +1243,7 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1183
1243
|
lineEl.style.whiteSpace = "pre";
|
|
1184
1244
|
lineEl.style.overflow = "visible";
|
|
1185
1245
|
let tabContext;
|
|
1186
|
-
const hasScaledTextRun = runsForLine.some((run) => (isTextRun(run) || isFieldRun(run) || isMathRun(run)) && run.horizontalScale !==
|
|
1246
|
+
const hasScaledTextRun = runsForLine.some((run) => (isTextRun(run) || isFieldRun(run) || isMathRun(run)) && getHorizontalScaleFactor(run.horizontalScale) !== 1);
|
|
1187
1247
|
const measureText = collapsedSpaceMeasureText ?? (hasTabRuns || hasScaledTextRun ? createTextMeasurer(doc) : void 0);
|
|
1188
1248
|
if (hasTabRuns) {
|
|
1189
1249
|
const explicitStops = options?.tabStops?.map(convertTabStopToCalc);
|
|
@@ -1244,7 +1304,10 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1244
1304
|
const next = runsForLine[j];
|
|
1245
1305
|
if (isTabRun(next) || isLineBreakRun(next)) break;
|
|
1246
1306
|
if (isTextRun(next)) lineEl.append(...withJoiners(renderLineTextRun(next), next));
|
|
1247
|
-
else if (isFieldRun(next) && options?.context) lineEl.append(renderFieldRun(next, doc,
|
|
1307
|
+
else if (isFieldRun(next) && options?.context) lineEl.append(renderFieldRun(next, doc, {
|
|
1308
|
+
context: options.context,
|
|
1309
|
+
...visualSpaceContractionPx !== void 0 ? { visualSpaceContractionPx } : {}
|
|
1310
|
+
}));
|
|
1248
1311
|
else if (isImageRun(next)) {
|
|
1249
1312
|
if (isFloatingImageRun(next)) continue;
|
|
1250
1313
|
const imageKey = getInlineImageRunKey(next);
|
|
@@ -1272,8 +1335,17 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1272
1335
|
const fontSize = run.fontSize || 11;
|
|
1273
1336
|
const fontFamily = run.fontFamily || "Calibri";
|
|
1274
1337
|
const measuredWidth = measureText(run.allCaps ? run.text.toLocaleUpperCase() : run.text, fontSize, fontFamily, runMeasureStyle(run));
|
|
1275
|
-
|
|
1276
|
-
|
|
1338
|
+
const runContractionPx = runVisualSpaceContraction({
|
|
1339
|
+
text: run.text,
|
|
1340
|
+
...run.horizontalScale !== void 0 ? { horizontalScale: run.horizontalScale } : {},
|
|
1341
|
+
...visualSpaceContractionPx !== void 0 ? { visualSpaceContractionPx } : {}
|
|
1342
|
+
});
|
|
1343
|
+
currentX += reserveScaledAdvance({
|
|
1344
|
+
element: runEl,
|
|
1345
|
+
unscaledWidth: measuredWidth,
|
|
1346
|
+
...run.horizontalScale !== void 0 ? { horizontalScale: run.horizontalScale } : {},
|
|
1347
|
+
...runContractionPx > 0 ? { visualSpaceContractionPx: runContractionPx } : {}
|
|
1348
|
+
});
|
|
1277
1349
|
} else if (isImageRun(run)) {
|
|
1278
1350
|
if (isFloatingImageRun(run)) continue;
|
|
1279
1351
|
const imageKey = getInlineImageRunKey(run);
|
|
@@ -1286,22 +1358,37 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1286
1358
|
const runEl = renderLineBreakRun(run, doc);
|
|
1287
1359
|
lineEl.append(runEl);
|
|
1288
1360
|
} else if (isFieldRun(run) && options?.context) {
|
|
1289
|
-
const runEl = renderFieldRun(run, doc,
|
|
1361
|
+
const runEl = renderFieldRun(run, doc, {
|
|
1362
|
+
context: options.context,
|
|
1363
|
+
...visualSpaceContractionPx !== void 0 ? { visualSpaceContractionPx } : {}
|
|
1364
|
+
});
|
|
1290
1365
|
lineEl.append(runEl);
|
|
1291
1366
|
if (!measureText) continue;
|
|
1292
1367
|
const fieldText = resolveFieldText(run, options.context);
|
|
1293
1368
|
const fontSize = run.fontSize || 11;
|
|
1294
1369
|
const fontFamily = run.fontFamily || "Calibri";
|
|
1295
1370
|
const measuredWidth = measureText(run.allCaps ? fieldText.toLocaleUpperCase() : fieldText, fontSize, fontFamily, runMeasureStyle(run));
|
|
1296
|
-
|
|
1297
|
-
|
|
1371
|
+
const runContractionPx = runVisualSpaceContraction({
|
|
1372
|
+
text: fieldText,
|
|
1373
|
+
...run.horizontalScale !== void 0 ? { horizontalScale: run.horizontalScale } : {},
|
|
1374
|
+
...visualSpaceContractionPx !== void 0 ? { visualSpaceContractionPx } : {}
|
|
1375
|
+
});
|
|
1376
|
+
currentX += reserveScaledAdvance({
|
|
1377
|
+
element: runEl,
|
|
1378
|
+
unscaledWidth: measuredWidth,
|
|
1379
|
+
...run.horizontalScale !== void 0 ? { horizontalScale: run.horizontalScale } : {},
|
|
1380
|
+
...runContractionPx > 0 ? { visualSpaceContractionPx: runContractionPx } : {}
|
|
1381
|
+
});
|
|
1298
1382
|
} else if (isMathRun(run)) {
|
|
1299
1383
|
const runEl = renderMathRun(run, doc);
|
|
1300
1384
|
lineEl.append(runEl);
|
|
1301
1385
|
if (!measureText) continue;
|
|
1302
1386
|
const measuredWidth = measureText(run.plainText, run.fontSize ?? 11, run.fontFamily ?? "Cambria Math", runMeasureStyle(run));
|
|
1303
|
-
reserveScaledAdvance(
|
|
1304
|
-
|
|
1387
|
+
currentX += reserveScaledAdvance({
|
|
1388
|
+
element: runEl,
|
|
1389
|
+
unscaledWidth: measuredWidth,
|
|
1390
|
+
...run.horizontalScale !== void 0 ? { horizontalScale: run.horizontalScale } : {}
|
|
1391
|
+
});
|
|
1305
1392
|
} else {
|
|
1306
1393
|
const runEl = renderRun(run, doc, options?.context);
|
|
1307
1394
|
lineEl.append(runEl);
|
|
@@ -1534,7 +1621,7 @@ function renderListMarker({ marker, inlineWidth, visualOffset, doc, formatting,
|
|
|
1534
1621
|
const span = doc.createElement("span");
|
|
1535
1622
|
span.className = "layout-list-marker";
|
|
1536
1623
|
span.style.display = "inline-block";
|
|
1537
|
-
span.style.fontFamily = resolveFontFamily(formatting.fontFamily).cssFallback;
|
|
1624
|
+
span.style.fontFamily = resolveFontFamily(formatting.fontFamily, formatting.alternateFontFamily).cssFallback;
|
|
1538
1625
|
if (formatting.fontSize) span.style.fontSize = `${formatting.fontSize * 96 / 72}px`;
|
|
1539
1626
|
if (formatting.bold !== void 0) span.style.fontWeight = formatting.bold ? "700" : "normal";
|
|
1540
1627
|
if (formatting.italic !== void 0) span.style.fontStyle = formatting.italic ? "italic" : "normal";
|
|
@@ -25,7 +25,7 @@ type RenderTableFragmentOptions = {
|
|
|
25
25
|
/**
|
|
26
26
|
* Render a nested table (within a cell)
|
|
27
27
|
*/
|
|
28
|
-
declare function renderNestedTable(block: TableBlock, measure: TableMeasure, context: RenderContext, doc: Document): HTMLElement;
|
|
28
|
+
declare function renderNestedTable(block: TableBlock, measure: TableMeasure, context: RenderContext, doc: Document, frameWidth?: number): HTMLElement;
|
|
29
29
|
/**
|
|
30
30
|
* Render a table fragment to DOM
|
|
31
31
|
*
|