@stll/folio-core 0.23.0 → 0.24.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/fontReadiness.js +12 -7
- package/dist/controller/layoutPipeline.js +7 -3
- package/dist/docx/blockContentParser.js +2 -47
- package/dist/docx/fieldParser.d.ts +1 -1
- package/dist/docx/fieldParser.js +12 -4
- package/dist/docx/numberingParser.d.ts +3 -11
- package/dist/docx/numberingParser.js +26 -158
- package/dist/docx/ooxmlCounterFormatter.d.ts +8 -0
- package/dist/docx/ooxmlCounterFormatter.js +134 -0
- package/dist/docx/paragraphParser.js +3 -4
- package/dist/docx/serializer/tableSerializer.js +1 -1
- package/dist/docx/tableParser.js +2 -1
- package/dist/fields/bookmarkPages.js +1 -1
- package/dist/fields/evaluateField.js +1 -1
- package/dist/fields/fieldContext.d.ts +2 -0
- package/dist/fields/resolveFieldValues.js +5 -2
- package/dist/layout-bridge/convert/headerFooterLayout.js +7 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +27 -64
- package/dist/layout-engine/index.d.ts +3 -2
- package/dist/layout-engine/index.js +40 -16
- package/dist/layout-engine/measure/cache.js +5 -1
- package/dist/layout-engine/measure/complexScriptFormatting.d.ts +18 -0
- package/dist/layout-engine/measure/complexScriptFormatting.js +11 -0
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +3 -1
- package/dist/layout-engine/measure/listMarkerWidth.js +25 -21
- package/dist/layout-engine/measure/measureContainer.js +31 -16
- package/dist/layout-engine/measure/measureHelpers.js +4 -0
- package/dist/layout-engine/measure/measureParagraph.js +13 -3
- package/dist/layout-engine/measure/measureTypes.d.ts +4 -0
- package/dist/layout-engine/paginator.d.ts +5 -3
- package/dist/layout-engine/paginator.js +34 -13
- package/dist/layout-engine/types.d.ts +34 -7
- package/dist/layout-painter/index.js +2 -1
- package/dist/layout-painter/renderPage.js +9 -3
- package/dist/layout-painter/renderParagraph.js +50 -42
- package/dist/layout-painter/renderUtils.d.ts +2 -0
- package/dist/paged-layout/sectionGeometry.d.ts +3 -2
- package/dist/paged-layout/sectionGeometry.js +17 -1
- package/dist/prosemirror/attrs/index.js +7 -6
- package/dist/prosemirror/conversion/fromProseDoc.js +5 -19
- package/dist/prosemirror/conversion/toProseDoc.js +5 -4
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -3
- package/dist/prosemirror/extensions/features/ListExtension.js +1 -3
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.d.ts +3 -2
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +31 -17
- package/dist/prosemirror/extensions/nodes/TableExtension.js +1 -0
- package/dist/prosemirror/schema/marks.d.ts +8 -0
- package/dist/prosemirror/schema/nodes.d.ts +5 -7
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -3
- package/package.json +2 -2
|
@@ -13,7 +13,7 @@ function buildBookmarkPageMap(pages, blocks) {
|
|
|
13
13
|
if (anchors.length === 0) return pageByBookmark;
|
|
14
14
|
for (const page of pages) for (const fragment of page.fragments) for (const anchor of anchors) {
|
|
15
15
|
if (!fragmentContainsAnchor(fragment, anchor)) continue;
|
|
16
|
-
assignBookmarkPage(pageByBookmark, anchor.names, page.
|
|
16
|
+
assignBookmarkPage(pageByBookmark, anchor.names, page.logicalNumber);
|
|
17
17
|
}
|
|
18
18
|
return pageByBookmark;
|
|
19
19
|
}
|
|
@@ -38,7 +38,7 @@ function evaluateField(parsed, ctx, options = {}) {
|
|
|
38
38
|
const fallback = options.fallback ?? "";
|
|
39
39
|
if (options.locked) return fallback;
|
|
40
40
|
switch (parsed.type) {
|
|
41
|
-
case "PAGE": return computePageNumber(ctx.pageNumber, parsed);
|
|
41
|
+
case "PAGE": return computePageNumber(ctx.pageNumber, parsed, ctx.pageNumberFormat);
|
|
42
42
|
case "NUMPAGES": return computePageNumber(ctx.totalPages, parsed);
|
|
43
43
|
case "SECTIONPAGES": return ctx.sectionPages === void 0 ? fallback : computePageNumber(ctx.sectionPages, parsed);
|
|
44
44
|
case "TIME": {
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
type FieldContext = {
|
|
10
10
|
/** 1-indexed page the field is on (PAGE). */
|
|
11
11
|
pageNumber: number;
|
|
12
|
+
/** OOXML section-level format used when PAGE has no explicit format switch. */
|
|
13
|
+
pageNumberFormat?: string;
|
|
12
14
|
/** Total pages in the document (NUMPAGES). */
|
|
13
15
|
totalPages: number;
|
|
14
16
|
/** Pages in the field's current section (SECTIONPAGES); omit until the
|
|
@@ -22,6 +22,7 @@ function resolveFieldValues(blocks, pages, shared) {
|
|
|
22
22
|
const sectionPages = location ? shared.sectionPageCounts.get(location.sectionIndex) : void 0;
|
|
23
23
|
const context = {
|
|
24
24
|
pageNumber: location?.page ?? 1,
|
|
25
|
+
...location?.pageFormat === void 0 ? {} : { pageNumberFormat: location.pageFormat },
|
|
25
26
|
totalPages: shared.totalPages,
|
|
26
27
|
bookmarkPages: shared.bookmarkPages,
|
|
27
28
|
bookmarkText: shared.bookmarkText,
|
|
@@ -131,7 +132,8 @@ function fieldValuesEqual(a, b) {
|
|
|
131
132
|
function buildBlockPageMap(pages) {
|
|
132
133
|
const map = /* @__PURE__ */ new Map();
|
|
133
134
|
for (const page of pages) for (const fragment of page.fragments) if (!map.has(fragment.blockId)) map.set(fragment.blockId, {
|
|
134
|
-
page: page.
|
|
135
|
+
page: page.logicalNumber,
|
|
136
|
+
...page.logicalNumberFormat === void 0 ? {} : { pageFormat: page.logicalNumberFormat },
|
|
135
137
|
sectionIndex: page.sectionIndex ?? 0
|
|
136
138
|
});
|
|
137
139
|
return map;
|
|
@@ -143,7 +145,8 @@ function buildTableRowPageMap(pages) {
|
|
|
143
145
|
for (let rowIndex = fragment.fromRow; rowIndex < fragment.toRow; rowIndex++) {
|
|
144
146
|
const key = tableRowKey(fragment.blockId, rowIndex);
|
|
145
147
|
if (!map.has(key)) map.set(key, {
|
|
146
|
-
page: page.
|
|
148
|
+
page: page.logicalNumber,
|
|
149
|
+
...page.logicalNumberFormat === void 0 ? {} : { pageFormat: page.logicalNumberFormat },
|
|
147
150
|
sectionIndex: page.sectionIndex ?? 0
|
|
148
151
|
});
|
|
149
152
|
}
|
|
@@ -442,7 +442,7 @@ function serializeParagraphAttrs(attrs) {
|
|
|
442
442
|
"listMarker",
|
|
443
443
|
"listIsBullet",
|
|
444
444
|
"listMarkerHidden",
|
|
445
|
-
"
|
|
445
|
+
"listMarkerFormatting",
|
|
446
446
|
"listMarkerAlignment",
|
|
447
447
|
"listMarkerSuffix",
|
|
448
448
|
"tabs"
|
|
@@ -470,6 +470,12 @@ function serializeRunFmt(run) {
|
|
|
470
470
|
"highlightColor",
|
|
471
471
|
"fontSize",
|
|
472
472
|
"fontFamily",
|
|
473
|
+
"eastAsiaFontFamily",
|
|
474
|
+
"complexScriptFontFamily",
|
|
475
|
+
"complexScriptFontSize",
|
|
476
|
+
"complexScriptBold",
|
|
477
|
+
"complexScriptItalic",
|
|
478
|
+
"forceComplexScript",
|
|
473
479
|
"verticalAlign",
|
|
474
480
|
"letterSpacing",
|
|
475
481
|
"smallCaps",
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { convertBulletToUnicode } from "../../docx/bulletMarkers.js";
|
|
2
2
|
import { resolveDocumentGridLinePitch } from "../../docx/documentGrid.js";
|
|
3
|
-
import {
|
|
3
|
+
import { formatOoxmlCounter } from "../../docx/ooxmlCounterFormatter.js";
|
|
4
4
|
import { setParagraphFrame } from "../../layout-engine/paragraphFrame.js";
|
|
5
5
|
import { setTextBoxGroupId } from "../../layout-engine/textBoxGroup.js";
|
|
6
6
|
import { DEFAULT_TEXTBOX_MARGINS } from "../../layout-engine/types.js";
|
|
7
|
+
import { getPageNumbering } from "../../paged-layout/sectionGeometry.js";
|
|
7
8
|
import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs, expectRunShadingMarkAttrs, expectSymbolAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../../prosemirror/attrs/index.js";
|
|
8
9
|
import { autospacingMatchesBase } from "../../prosemirror/autospacingBase.js";
|
|
9
10
|
import { runShadingAttrsToShading } from "../../prosemirror/conversion/runShadingMark.js";
|
|
10
|
-
import {
|
|
11
|
+
import { directionToBidi } from "../../prosemirror/paragraphDirection.js";
|
|
11
12
|
import { assertValidProseMirrorDocument } from "../../prosemirror/validation.js";
|
|
12
13
|
import { resolveColor, resolveHighlightToCss } from "../../utils/colorResolver.js";
|
|
13
14
|
import { resolveThemeFont } from "../../utils/fontResolver.js";
|
|
@@ -74,51 +75,8 @@ function formatNumberedMarker(counters, level) {
|
|
|
74
75
|
if (parts.length === 0) return "1.";
|
|
75
76
|
return `${parts.join(".")}.`;
|
|
76
77
|
}
|
|
77
|
-
const ROMAN_PAIRS = [
|
|
78
|
-
[1e3, "M"],
|
|
79
|
-
[900, "CM"],
|
|
80
|
-
[500, "D"],
|
|
81
|
-
[400, "CD"],
|
|
82
|
-
[100, "C"],
|
|
83
|
-
[90, "XC"],
|
|
84
|
-
[50, "L"],
|
|
85
|
-
[40, "XL"],
|
|
86
|
-
[10, "X"],
|
|
87
|
-
[9, "IX"],
|
|
88
|
-
[5, "V"],
|
|
89
|
-
[4, "IV"],
|
|
90
|
-
[1, "I"]
|
|
91
|
-
];
|
|
92
|
-
function toRoman(value, upper) {
|
|
93
|
-
if (value <= 0) return "";
|
|
94
|
-
let remaining = value;
|
|
95
|
-
let output = "";
|
|
96
|
-
for (const [number, symbol] of ROMAN_PAIRS) while (remaining >= number) {
|
|
97
|
-
output += symbol;
|
|
98
|
-
remaining -= number;
|
|
99
|
-
}
|
|
100
|
-
return upper ? output : output.toLowerCase();
|
|
101
|
-
}
|
|
102
|
-
function toLetter(value, upper) {
|
|
103
|
-
if (value <= 0) return "";
|
|
104
|
-
const zeroBased = value - 1;
|
|
105
|
-
const baseCodePoint = upper ? 65 : 97;
|
|
106
|
-
return String.fromCodePoint(baseCodePoint + zeroBased % 26).repeat(Math.floor(zeroBased / 26) + 1);
|
|
107
|
-
}
|
|
108
78
|
function formatCounter(value, format) {
|
|
109
|
-
|
|
110
|
-
switch (format) {
|
|
111
|
-
case "upperRoman": return toRoman(value, true);
|
|
112
|
-
case "lowerRoman": return toRoman(value, false);
|
|
113
|
-
case "upperLetter": return toLetter(value, true);
|
|
114
|
-
case "lowerLetter": return toLetter(value, false);
|
|
115
|
-
case "decimalZero": return padDecimal(value, 2);
|
|
116
|
-
case "decimalZero3": return padDecimal(value, 3);
|
|
117
|
-
case "decimalZero4": return padDecimal(value, 4);
|
|
118
|
-
case "decimalZero5": return padDecimal(value, 5);
|
|
119
|
-
case "none": return "";
|
|
120
|
-
default: return String(value);
|
|
121
|
-
}
|
|
79
|
+
return formatOoxmlCounter(value, format);
|
|
122
80
|
}
|
|
123
81
|
function resolveListTemplate(template, counters, levelFormats, forceDecimal = false) {
|
|
124
82
|
return template.replace(/%(?<digit>\d)(?<punct>[.):\]])?/gu, (...args) => {
|
|
@@ -399,9 +357,12 @@ function applyRunFormattingOverrides(formatting, attrs) {
|
|
|
399
357
|
if (attrs.shadow === false) formatting.textShadow = false;
|
|
400
358
|
if (attrs.outline === false) formatting.textOutline = false;
|
|
401
359
|
if (attrs.rtl === false) formatting.rtl = false;
|
|
360
|
+
if (attrs.boldCs !== void 0) formatting.complexScriptBold = attrs.boldCs;
|
|
361
|
+
if (attrs.italicCs !== void 0) formatting.complexScriptItalic = attrs.italicCs;
|
|
362
|
+
if (attrs.fontSizeCs !== void 0) formatting.complexScriptFontSize = attrs.fontSizeCs / 2;
|
|
363
|
+
if (attrs.cs !== void 0) formatting.forceComplexScript = attrs.cs;
|
|
402
364
|
}
|
|
403
|
-
function
|
|
404
|
-
const defaultTextFormatting = pmAttrs.defaultTextFormatting;
|
|
365
|
+
function textFormattingToRunFormatting(defaultTextFormatting, theme) {
|
|
405
366
|
if (!defaultTextFormatting) return {};
|
|
406
367
|
const result = {};
|
|
407
368
|
const fontFamily = defaultTextFormatting.fontFamily ? resolveWesternThemeFont(defaultTextFormatting.fontFamily, theme) : void 0;
|
|
@@ -412,8 +373,13 @@ function paragraphRunDefaults(pmAttrs, theme) {
|
|
|
412
373
|
if (complexScriptFontFamily) result.complexScriptFontFamily = complexScriptFontFamily;
|
|
413
374
|
if (defaultTextFormatting.language) result.language = { ...defaultTextFormatting.language };
|
|
414
375
|
if (defaultTextFormatting.fontSize !== void 0) result.fontSize = defaultTextFormatting.fontSize / 2;
|
|
376
|
+
if (defaultTextFormatting.fontSizeCs !== void 0) result.complexScriptFontSize = defaultTextFormatting.fontSizeCs / 2;
|
|
415
377
|
if (defaultTextFormatting.bold !== void 0) result.bold = defaultTextFormatting.bold;
|
|
378
|
+
if (defaultTextFormatting.boldCs !== void 0) result.complexScriptBold = defaultTextFormatting.boldCs;
|
|
416
379
|
if (defaultTextFormatting.italic !== void 0) result.italic = defaultTextFormatting.italic;
|
|
380
|
+
if (defaultTextFormatting.italicCs !== void 0) result.complexScriptItalic = defaultTextFormatting.italicCs;
|
|
381
|
+
if (defaultTextFormatting.rtl !== void 0) result.rtl = defaultTextFormatting.rtl;
|
|
382
|
+
if (defaultTextFormatting.cs !== void 0) result.forceComplexScript = defaultTextFormatting.cs;
|
|
417
383
|
if (defaultTextFormatting.underline && defaultTextFormatting.underline.style !== "none") {
|
|
418
384
|
result.underline = { style: defaultTextFormatting.underline.style };
|
|
419
385
|
if (defaultTextFormatting.underline.color) result.underline.color = resolveColor(defaultTextFormatting.underline.color, theme);
|
|
@@ -442,6 +408,9 @@ function paragraphRunDefaults(pmAttrs, theme) {
|
|
|
442
408
|
if (defaultTextFormatting.emphasisMark && defaultTextFormatting.emphasisMark !== "none") result.emphasisMark = defaultTextFormatting.emphasisMark;
|
|
443
409
|
return result;
|
|
444
410
|
}
|
|
411
|
+
function paragraphRunDefaults(pmAttrs, theme) {
|
|
412
|
+
return textFormattingToRunFormatting(pmAttrs.defaultTextFormatting, theme);
|
|
413
|
+
}
|
|
445
414
|
/**
|
|
446
415
|
* Build an ImageRun from ProseMirror node attrs, applying conditional property assignment
|
|
447
416
|
* to satisfy exactOptionalPropertyTypes.
|
|
@@ -687,12 +656,8 @@ function toPreviousListAttrs(previousFormatting) {
|
|
|
687
656
|
if (listStartOverride !== void 0) attrs.listStartOverride = listStartOverride;
|
|
688
657
|
const listMarkerHidden = previousFormatting.listMarkerHidden;
|
|
689
658
|
if (listMarkerHidden !== void 0) attrs.listMarkerHidden = listMarkerHidden;
|
|
690
|
-
const
|
|
691
|
-
if (
|
|
692
|
-
const listMarkerFontSize = previousFormatting.listMarkerFontSize;
|
|
693
|
-
if (listMarkerFontSize !== void 0) attrs.listMarkerFontSize = listMarkerFontSize;
|
|
694
|
-
const listMarkerBold = previousFormatting.listMarkerBold;
|
|
695
|
-
if (listMarkerBold !== void 0) attrs.listMarkerBold = listMarkerBold;
|
|
659
|
+
const listMarkerFormatting = previousFormatting.listMarkerFormatting;
|
|
660
|
+
if (listMarkerFormatting !== void 0) attrs.listMarkerFormatting = listMarkerFormatting;
|
|
696
661
|
const listMarkerAlignment = previousFormatting.listMarkerAlignment;
|
|
697
662
|
if (listMarkerAlignment !== void 0) attrs.listMarkerAlignment = listMarkerAlignment;
|
|
698
663
|
const listMarkerSuffix = previousFormatting.listMarkerSuffix;
|
|
@@ -708,7 +673,7 @@ function resolveDeletedListMarker(previousListAttrs, listCounters, listAbstractC
|
|
|
708
673
|
if (previousListAttrs.listIsBullet) return "•";
|
|
709
674
|
return null;
|
|
710
675
|
}
|
|
711
|
-
function applyDeletedListMarkerAttrs(attrs, change, listCounters, listAbstractCounters, listSeenNumIds) {
|
|
676
|
+
function applyDeletedListMarkerAttrs(attrs, change, listCounters, listAbstractCounters, listSeenNumIds, theme) {
|
|
712
677
|
const previousListAttrs = toPreviousListAttrs(change.previousFormatting);
|
|
713
678
|
const marker = resolveDeletedListMarker(previousListAttrs, listCounters, listAbstractCounters, listSeenNumIds);
|
|
714
679
|
if (!marker) return;
|
|
@@ -716,9 +681,7 @@ function applyDeletedListMarkerAttrs(attrs, change, listCounters, listAbstractCo
|
|
|
716
681
|
attrs.listMarkerRevision = toListMarkerRevision("del", change.info);
|
|
717
682
|
if (previousListAttrs.listIsBullet !== void 0) attrs.listIsBullet = previousListAttrs.listIsBullet;
|
|
718
683
|
if (previousListAttrs.listMarkerHidden !== void 0) attrs.listMarkerHidden = previousListAttrs.listMarkerHidden;
|
|
719
|
-
if (previousListAttrs.
|
|
720
|
-
if (previousListAttrs.listMarkerFontSize) attrs.listMarkerFontSize = previousListAttrs.listMarkerFontSize;
|
|
721
|
-
if (previousListAttrs.listMarkerBold !== void 0) attrs.listMarkerBold = previousListAttrs.listMarkerBold;
|
|
684
|
+
if (previousListAttrs.listMarkerFormatting) attrs.listMarkerFormatting = textFormattingToRunFormatting(previousListAttrs.listMarkerFormatting, theme);
|
|
722
685
|
if (previousListAttrs.listMarkerAlignment) attrs.listMarkerAlignment = previousListAttrs.listMarkerAlignment;
|
|
723
686
|
if (previousListAttrs.listMarkerSuffix) attrs.listMarkerSuffix = previousListAttrs.listMarkerSuffix;
|
|
724
687
|
}
|
|
@@ -821,7 +784,8 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
|
|
|
821
784
|
if (pmAttrs.widowControl === false) attrs.widowControl = false;
|
|
822
785
|
if (pmAttrs.contextualSpacing) attrs.contextualSpacing = true;
|
|
823
786
|
if (pmAttrs.runInWithNext) attrs.runInWithNext = true;
|
|
824
|
-
|
|
787
|
+
const bidi = directionToBidi(pmAttrs.direction);
|
|
788
|
+
if (bidi !== void 0) attrs.bidi = bidi;
|
|
825
789
|
if (pmAttrs.styleId) attrs.styleId = pmAttrs.styleId;
|
|
826
790
|
const propertyChanges = pmAttrs._propertyChanges ?? [];
|
|
827
791
|
let changedNumberingChange;
|
|
@@ -853,15 +817,13 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
|
|
|
853
817
|
else if (pmAttrs.listMarker) attrs.listMarker = pmAttrs.listIsBullet ? convertBulletToUnicode(pmAttrs.listMarker) : pmAttrs.listMarker;
|
|
854
818
|
if (pmAttrs.listIsBullet !== void 0) attrs.listIsBullet = pmAttrs.listIsBullet;
|
|
855
819
|
if (pmAttrs.listMarkerHidden) attrs.listMarkerHidden = true;
|
|
856
|
-
if (pmAttrs.
|
|
857
|
-
if (pmAttrs.listMarkerFontSize) attrs.listMarkerFontSize = pmAttrs.listMarkerFontSize;
|
|
858
|
-
if (pmAttrs.listMarkerBold !== null && pmAttrs.listMarkerBold !== void 0) attrs.listMarkerBold = pmAttrs.listMarkerBold;
|
|
820
|
+
if (pmAttrs.listMarkerFormatting) attrs.listMarkerFormatting = textFormattingToRunFormatting(pmAttrs.listMarkerFormatting, theme);
|
|
859
821
|
if (pmAttrs.listMarkerAlignment) attrs.listMarkerAlignment = pmAttrs.listMarkerAlignment;
|
|
860
822
|
if (pmAttrs.listMarkerSuffix) attrs.listMarkerSuffix = pmAttrs.listMarkerSuffix;
|
|
861
823
|
if (pmAttrs.listMarkerSecondSlotOffsetTwips !== void 0) attrs.listMarkerSecondSlotOffsetTwips = pmAttrs.listMarkerSecondSlotOffsetTwips;
|
|
862
824
|
if (!pmAttrs.numPr) {
|
|
863
825
|
const numberingRemovedChange = propertyChanges.find(isRemovedNumberingChange);
|
|
864
|
-
if (numberingRemovedChange) applyDeletedListMarkerAttrs(attrs, numberingRemovedChange, originalListCounters, originalListAbstractCounters, originalListSeenNumIds);
|
|
826
|
+
if (numberingRemovedChange) applyDeletedListMarkerAttrs(attrs, numberingRemovedChange, originalListCounters, originalListAbstractCounters, originalListSeenNumIds, theme);
|
|
865
827
|
}
|
|
866
828
|
if (defaultTabStopTwips !== void 0) attrs.defaultTabStopTwips = defaultTabStopTwips;
|
|
867
829
|
const dtf = pmAttrs.defaultTextFormatting;
|
|
@@ -1187,7 +1149,7 @@ function convertTable(node, startPos, options) {
|
|
|
1187
1149
|
if (justification) tableBlock.justification = justification;
|
|
1188
1150
|
if (indentPx !== void 0) tableBlock.indent = indentPx;
|
|
1189
1151
|
if (floatingPx) tableBlock.floating = floatingPx;
|
|
1190
|
-
if (originalFormatting?.bidi) tableBlock.bidi = true;
|
|
1152
|
+
if (attrs._resolvedBidi ?? originalFormatting?.bidi) tableBlock.bidi = true;
|
|
1191
1153
|
return tableBlock;
|
|
1192
1154
|
}
|
|
1193
1155
|
/**
|
|
@@ -1462,6 +1424,7 @@ function toFlowBlocks(doc, options = {}) {
|
|
|
1462
1424
|
const breakType = secProps?.sectionStart ?? pmAttrs.sectionBreakType;
|
|
1463
1425
|
if (breakType) sectionBreak.type = breakType;
|
|
1464
1426
|
if (secProps) {
|
|
1427
|
+
sectionBreak.pageNumbering = getPageNumbering(secProps);
|
|
1465
1428
|
const documentGridLinePitchTwips = resolveDocumentGridLinePitch(secProps.docGrid);
|
|
1466
1429
|
if (documentGridLinePitchTwips !== void 0) sectionBreak.documentGridLinePitchTwips = documentGridLinePitchTwips;
|
|
1467
1430
|
if (secProps.pageWidth || secProps.pageHeight) sectionBreak.pageSize = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, tableColumnsArePinned } from "./types.js";
|
|
1
|
+
import { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionPageNumbering, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, tableColumnsArePinned } from "./types.js";
|
|
2
2
|
import { PageState, Paginator, PaginatorOptions, createPaginator } from "./paginator.js";
|
|
3
3
|
import { KeepNextChain, calculateChainHeight, computeKeepNextChains, getMidChainIndices, hasKeepLines, hasPageBreakBefore } from "./keep-together.js";
|
|
4
4
|
import { resolveSectionHeaderFooterRefs } from "./headerFooterRefs.js";
|
|
@@ -11,6 +11,7 @@ type SectionLayoutConfig = {
|
|
|
11
11
|
h: number;
|
|
12
12
|
};
|
|
13
13
|
margins: PageMargins;
|
|
14
|
+
pageNumbering: SectionPageNumbering;
|
|
14
15
|
columns?: ColumnLayout;
|
|
15
16
|
};
|
|
16
17
|
declare function collectSectionConfigs(blocks: FlowBlock[], initialConfig: SectionLayoutConfig, finalConfig: SectionLayoutConfig): {
|
|
@@ -43,4 +44,4 @@ declare function layoutDocument(blocks: FlowBlock[], measures: Measure[], option
|
|
|
43
44
|
*/
|
|
44
45
|
declare function getHeaderRowsHeight(measure: TableMeasure, headerRowCount: number): number;
|
|
45
46
|
//#endregion
|
|
46
|
-
export { BlockId, BorderStyle, type BreakDecision, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, type KeepNextChain, Layout, LayoutOptions, LineBreakRun, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, type PageState, type Paginator, type PaginatorOptions, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionLayoutConfig, type SectionState, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, getTableRowLeadingWidth, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, scheduleSectionBreak, tableColumnsArePinned };
|
|
47
|
+
export { BlockId, BorderStyle, type BreakDecision, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, type KeepNextChain, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, type PageState, type Paginator, type PaginatorOptions, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionLayoutConfig, SectionPageNumbering, type SectionState, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, getTableRowLeadingWidth, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, scheduleSectionBreak, tableColumnsArePinned };
|
|
@@ -5,7 +5,7 @@ import { measuredLineAdvance } from "./lineFlow.js";
|
|
|
5
5
|
import { resolveFloatingTableX } from "./measure/floatingTablePosition.js";
|
|
6
6
|
import { createPaginator } from "./paginator.js";
|
|
7
7
|
import { getParagraphFragmentPmRange } from "./paragraphFragmentRange.js";
|
|
8
|
-
import { collapseParagraphSpacing, getParagraphSpacingAfter, getParagraphSpacingBefore, paragraphsShareStyle, resolveEffectiveParagraphSpacingTree } from "./paragraphSpacing.js";
|
|
8
|
+
import { collapseParagraphSpacing, getParagraphSpacingAfter, getParagraphSpacingBefore, isEmptyParagraph, paragraphsShareStyle, resolveEffectiveParagraphSpacingTree } from "./paragraphSpacing.js";
|
|
9
9
|
import { assertExhaustiveFlowBlock, findPageIndexContainingPmPos } from "./pmPageIndex.js";
|
|
10
10
|
import { INITIAL_RENDERED_BREAK_STATE, reconcileAfterBlock, reconcileBreakBeforeBlock, recordReflowBoundary } from "./renderedBreakReconciliation.js";
|
|
11
11
|
import { applyPendingToActive, createInitialSectionState, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, scheduleSectionBreak } from "./section-breaks.js";
|
|
@@ -25,6 +25,7 @@ const DEFAULT_COLUMNS = {
|
|
|
25
25
|
gap: 0
|
|
26
26
|
};
|
|
27
27
|
const DEFAULT_SECTION_BREAK_TYPE = "nextPage";
|
|
28
|
+
const CONTINUE_PAGE_NUMBERING = { type: "continue" };
|
|
28
29
|
function collectSectionConfigs(blocks, initialConfig, finalConfig) {
|
|
29
30
|
const configs = [];
|
|
30
31
|
const breakIndices = [];
|
|
@@ -35,7 +36,8 @@ function collectSectionConfigs(blocks, initialConfig, finalConfig) {
|
|
|
35
36
|
const sectionBreak = block;
|
|
36
37
|
const config = {
|
|
37
38
|
pageSize: sectionBreak.pageSize ?? previousConfig.pageSize,
|
|
38
|
-
margins: sectionBreak.margins ?? previousConfig.margins
|
|
39
|
+
margins: sectionBreak.margins ?? previousConfig.margins,
|
|
40
|
+
pageNumbering: sectionBreak.pageNumbering ?? CONTINUE_PAGE_NUMBERING
|
|
39
41
|
};
|
|
40
42
|
if (sectionBreak.columns !== void 0) config.columns = sectionBreak.columns;
|
|
41
43
|
configs.push(config);
|
|
@@ -160,12 +162,14 @@ function layoutDocument(blocks, measures, options) {
|
|
|
160
162
|
if (pageSize.w - margins.left - margins.right <= 0) panic("layoutDocument: page size and margins yield no content area");
|
|
161
163
|
const bodyConfig = {
|
|
162
164
|
pageSize,
|
|
163
|
-
margins
|
|
165
|
+
margins,
|
|
166
|
+
pageNumbering: options.pageNumbering ?? CONTINUE_PAGE_NUMBERING
|
|
164
167
|
};
|
|
165
168
|
if (options.columns !== void 0) bodyConfig.columns = options.columns;
|
|
166
169
|
const finalConfig = {
|
|
167
170
|
pageSize: finalPageSize,
|
|
168
|
-
margins: finalMargins
|
|
171
|
+
margins: finalMargins,
|
|
172
|
+
pageNumbering: options.finalPageNumbering ?? bodyConfig.pageNumbering
|
|
169
173
|
};
|
|
170
174
|
const finalColumns = options.finalColumns ?? options.columns;
|
|
171
175
|
if (finalColumns !== void 0) finalConfig.columns = finalColumns;
|
|
@@ -179,6 +183,7 @@ function layoutDocument(blocks, measures, options) {
|
|
|
179
183
|
...options.firstPageMargins !== void 0 ? { firstPageMargins: options.firstPageMargins } : {},
|
|
180
184
|
...options.sectionEvenPageMargins !== void 0 ? { sectionEvenPageMargins: options.sectionEvenPageMargins } : {},
|
|
181
185
|
columns: initialConfig.columns ?? DEFAULT_COLUMNS,
|
|
186
|
+
pageNumbering: initialConfig.pageNumbering,
|
|
182
187
|
...options.footnoteReservedHeights !== void 0 ? { footnoteReservedHeights: options.footnoteReservedHeights } : {},
|
|
183
188
|
...options.sectionHeaderFooterRefs !== void 0 ? { sectionHeaderFooterRefs: options.sectionHeaderFooterRefs } : {}
|
|
184
189
|
});
|
|
@@ -474,10 +479,27 @@ function getHeaderRowsHeight(measure, headerRowCount) {
|
|
|
474
479
|
for (let i = 0; i < headerRowCount && i < measure.rows.length; i++) height += measure.rows[i].height;
|
|
475
480
|
return height;
|
|
476
481
|
}
|
|
477
|
-
const tableRowStartsWithRenderedPageBreak = (block, rowIndex) =>
|
|
478
|
-
const
|
|
479
|
-
|
|
480
|
-
|
|
482
|
+
const tableRowStartsWithRenderedPageBreak = (block, rowIndex) => {
|
|
483
|
+
const visibleCells = block.rows[rowIndex]?.cells.filter((cell) => cell.blocks.some((cellBlock) => cellBlock.kind !== "paragraph" || !isEmptyParagraph(cellBlock)));
|
|
484
|
+
if (!visibleCells || visibleCells.length === 0) return false;
|
|
485
|
+
return visibleCells.every((cell) => {
|
|
486
|
+
const firstVisibleBlock = cell.blocks.find((cellBlock) => cellBlock.kind !== "paragraph" || !isEmptyParagraph(cellBlock));
|
|
487
|
+
return firstVisibleBlock?.kind === "paragraph" && firstVisibleBlock.attrs?.renderedPageBreakBefore === true;
|
|
488
|
+
});
|
|
489
|
+
};
|
|
490
|
+
const getVerticallyMergedRows = (block) => {
|
|
491
|
+
const mergedRows = /* @__PURE__ */ new Set();
|
|
492
|
+
for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex += 1) {
|
|
493
|
+
const row = block.rows[rowIndex];
|
|
494
|
+
if (!row) continue;
|
|
495
|
+
for (const cell of row.cells) {
|
|
496
|
+
const rowSpan = cell.rowSpan ?? 1;
|
|
497
|
+
if (rowSpan <= 1) continue;
|
|
498
|
+
for (let mergedRowIndex = rowIndex; mergedRowIndex < Math.min(block.rows.length, rowIndex + rowSpan); mergedRowIndex += 1) mergedRows.add(mergedRowIndex);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return mergedRows;
|
|
502
|
+
};
|
|
481
503
|
const flowBlockHasTrackedChanges = (block) => {
|
|
482
504
|
if (block.kind === "paragraph") return block.runs.some((run) => {
|
|
483
505
|
if (run.kind === "lineBreak") return false;
|
|
@@ -499,7 +521,7 @@ function layoutTable(block, measure, paginator, footnoteHeightById) {
|
|
|
499
521
|
const headerRowsHeight = getHeaderRowsHeight(measure, headerRowCount);
|
|
500
522
|
let currentRowIndex = 0;
|
|
501
523
|
const breakInfo = buildTableRowBreakInfo(block, measure);
|
|
502
|
-
const
|
|
524
|
+
const verticallyMergedRows = getVerticallyMergedRows(block);
|
|
503
525
|
const computeTableX = (columnIndex) => {
|
|
504
526
|
let x = paginator.getColumnX(columnIndex);
|
|
505
527
|
if (block.justification === "center") x += (paginator.columnWidth - measure.totalWidth) / 2;
|
|
@@ -520,7 +542,7 @@ function layoutTable(block, measure, paginator, footnoteHeightById) {
|
|
|
520
542
|
const canSplitRow = (rowIndex, state = paginator.getCurrentState()) => {
|
|
521
543
|
const row = rows[rowIndex];
|
|
522
544
|
const sourceRow = block.rows[rowIndex];
|
|
523
|
-
if (!row || !sourceRow || sourceRow.cantSplit || sourceRow.isHeader ||
|
|
545
|
+
if (!row || !sourceRow || sourceRow.cantSplit || sourceRow.isHeader || verticallyMergedRows.has(rowIndex)) return false;
|
|
524
546
|
if ((breakInfo.breakOffsets[rowIndex]?.length ?? 0) <= 1) return false;
|
|
525
547
|
const freshHeaderOverhead = headerRowCount > 0 && rowIndex >= headerRowCount ? headerRowsHeight : 0;
|
|
526
548
|
const oversized = row.height + freshHeaderOverhead > getCurrentRowCapacity(state);
|
|
@@ -881,24 +903,26 @@ function handleSectionBreak(_block, paginator, nextSectionConfig, nextSectionTyp
|
|
|
881
903
|
switch (nextSectionType) {
|
|
882
904
|
case "nextPage":
|
|
883
905
|
paginator.updatePageLayout(nextSectionConfig.pageSize, nextSectionConfig.margins);
|
|
884
|
-
if (nextSectionIndex !== void 0) paginator.startSection(nextSectionIndex);
|
|
906
|
+
if (nextSectionIndex !== void 0) paginator.startSection(nextSectionIndex, nextSectionConfig.pageNumbering);
|
|
885
907
|
paginator.forcePageBreak({ coalesceBlankPage: true });
|
|
886
908
|
break;
|
|
887
909
|
case "evenPage":
|
|
888
|
-
paginator.updatePageLayout(nextSectionConfig.pageSize, nextSectionConfig.margins);
|
|
889
|
-
if (nextSectionIndex !== void 0) paginator.startSection(nextSectionIndex);
|
|
890
910
|
if (paginator.forcePageBreak({ coalesceBlankPage: true }).page.number % 2 !== 0) paginator.forcePageBreak();
|
|
911
|
+
paginator.updatePageLayout(nextSectionConfig.pageSize, nextSectionConfig.margins);
|
|
912
|
+
if (nextSectionIndex !== void 0) paginator.startSection(nextSectionIndex, nextSectionConfig.pageNumbering);
|
|
913
|
+
if (!paginator.retargetCurrentBlankPage()) panic("Even-page section target must be blank");
|
|
891
914
|
break;
|
|
892
915
|
case "oddPage":
|
|
893
|
-
paginator.updatePageLayout(nextSectionConfig.pageSize, nextSectionConfig.margins);
|
|
894
|
-
if (nextSectionIndex !== void 0) paginator.startSection(nextSectionIndex);
|
|
895
916
|
if (paginator.forcePageBreak({ coalesceBlankPage: true }).page.number % 2 === 0) paginator.forcePageBreak();
|
|
917
|
+
paginator.updatePageLayout(nextSectionConfig.pageSize, nextSectionConfig.margins);
|
|
918
|
+
if (nextSectionIndex !== void 0) paginator.startSection(nextSectionIndex, nextSectionConfig.pageNumbering);
|
|
919
|
+
if (!paginator.retargetCurrentBlankPage()) panic("Odd-page section target must be blank");
|
|
896
920
|
break;
|
|
897
921
|
case "continuous": {
|
|
898
922
|
const currentPage = paginator.pages.at(-1);
|
|
899
923
|
const nextSize = nextSectionConfig.pageSize;
|
|
900
924
|
const pageSizeChanges = currentPage != null && (Math.round(nextSize.w) !== Math.round(currentPage.size.w) || Math.round(nextSize.h) !== Math.round(currentPage.size.h));
|
|
901
|
-
if (nextSectionIndex !== void 0) paginator.startSection(nextSectionIndex);
|
|
925
|
+
if (nextSectionIndex !== void 0) paginator.startSection(nextSectionIndex, nextSectionConfig.pageNumbering);
|
|
902
926
|
if (pageSizeChanges) {
|
|
903
927
|
paginator.updatePageLayout(nextSize, nextSectionConfig.margins);
|
|
904
928
|
if (!paginator.retargetCurrentBlankPage()) paginator.forcePageBreak({ coalesceBlankPage: true });
|
|
@@ -170,7 +170,7 @@ const paragraphMeasureCache = /* @__PURE__ */ new Map();
|
|
|
170
170
|
*/
|
|
171
171
|
function hashParagraphBlock(block) {
|
|
172
172
|
const parts = [`lbp:${getLineBreakProviderGeneration()}`];
|
|
173
|
-
for (const run of block.runs) if (run.kind === "text") parts.push(`t:${run.text}|${run.fontFamily}|${run.eastAsiaFontFamily}|${run.complexScriptFontFamily}|${run.fontSize}|${run.bold}|${run.italic}|${run.allCaps}|${run.smallCaps}|${run.horizontalScale}|${run.letterSpacing}|${run.language?.val}|${run.language?.eastAsia}|${run.language?.bidi}`);
|
|
173
|
+
for (const run of block.runs) if (run.kind === "text") parts.push(`t:${run.text}|${run.fontFamily}|${run.eastAsiaFontFamily}|${run.complexScriptFontFamily}|${run.fontSize}|${run.complexScriptFontSize}|${run.bold}|${run.complexScriptBold}|${run.italic}|${run.complexScriptItalic}|${run.forceComplexScript}|${run.allCaps}|${run.smallCaps}|${run.horizontalScale}|${run.letterSpacing}|${run.language?.val}|${run.language?.eastAsia}|${run.language?.bidi}`);
|
|
174
174
|
else if (run.kind === "tab") parts.push(`tab:${run.width}`);
|
|
175
175
|
else if (run.kind === "image") parts.push(`img:${run.width}x${run.height}:${run.exactLineHeight === true ? "exact" : "text"}`);
|
|
176
176
|
else if (run.kind === "lineBreak") parts.push("br");
|
|
@@ -186,6 +186,10 @@ function hashParagraphBlock(block) {
|
|
|
186
186
|
if (attrs.reserveEmptyOutlineHeight) parts.push("outline-empty-reserve");
|
|
187
187
|
if (attrs.documentGridLinePitch !== void 0) parts.push(`documentGrid:${attrs.documentGridLinePitch}|${attrs.snapToGrid !== false}`);
|
|
188
188
|
if (attrs.justificationCompatibility) parts.push(`justify-compat:${attrs.justificationCompatibility.type}`);
|
|
189
|
+
if (attrs.listMarker !== void 0) {
|
|
190
|
+
const marker = attrs.listMarkerFormatting;
|
|
191
|
+
parts.push(`marker:${attrs.listMarker}|${attrs.listMarkerHidden}|${attrs.listMarkerAlignment}|${attrs.listMarkerSuffix}|${marker?.fontFamily}|${marker?.eastAsiaFontFamily}|${marker?.complexScriptFontFamily}|${marker?.fontSize}|${marker?.complexScriptFontSize}|${marker?.bold}|${marker?.complexScriptBold}|${marker?.italic}|${marker?.complexScriptItalic}|${marker?.rtl}|${marker?.forceComplexScript}`);
|
|
192
|
+
}
|
|
189
193
|
parts.push(...lineBreakPolicyCacheParts(attrs));
|
|
190
194
|
const borders = attrs.borders;
|
|
191
195
|
if (borders) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/layout-engine/measure/complexScriptFormatting.d.ts
|
|
2
|
+
type ComplexScriptFormattingSource = {
|
|
3
|
+
complexScriptFontFamily?: string;
|
|
4
|
+
complexScriptFontSize?: number;
|
|
5
|
+
complexScriptBold?: boolean;
|
|
6
|
+
complexScriptItalic?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type ResolvedComplexScriptFormatting = {
|
|
9
|
+
fontFamily?: string;
|
|
10
|
+
fontSize?: number;
|
|
11
|
+
bold?: boolean;
|
|
12
|
+
italic?: boolean;
|
|
13
|
+
};
|
|
14
|
+
/** Resolve Word's independent complex-script slot into ordinary paint fields. */
|
|
15
|
+
declare const resolveComplexScriptFormatting: (source: ComplexScriptFormattingSource) => ResolvedComplexScriptFormatting;
|
|
16
|
+
declare const hasComplexScriptFormatting: (source: ComplexScriptFormattingSource) => boolean;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { ResolvedComplexScriptFormatting, hasComplexScriptFormatting, resolveComplexScriptFormatting };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/layout-engine/measure/complexScriptFormatting.ts
|
|
2
|
+
/** Resolve Word's independent complex-script slot into ordinary paint fields. */
|
|
3
|
+
const resolveComplexScriptFormatting = (source) => ({
|
|
4
|
+
...source.complexScriptFontFamily !== void 0 ? { fontFamily: source.complexScriptFontFamily } : {},
|
|
5
|
+
...source.complexScriptFontSize !== void 0 ? { fontSize: source.complexScriptFontSize } : {},
|
|
6
|
+
...source.complexScriptBold !== void 0 ? { bold: source.complexScriptBold } : {},
|
|
7
|
+
...source.complexScriptItalic !== void 0 ? { italic: source.complexScriptItalic } : {}
|
|
8
|
+
});
|
|
9
|
+
const hasComplexScriptFormatting = (source) => source.complexScriptFontFamily !== void 0 || source.complexScriptFontSize !== void 0 || source.complexScriptBold !== void 0 || source.complexScriptItalic !== void 0;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { hasComplexScriptFormatting, resolveComplexScriptFormatting };
|
|
@@ -8,7 +8,7 @@ import { ParagraphBlock } from "../types.js";
|
|
|
8
8
|
declare const DEFAULT_TAB_STOP_TWIPS = 720;
|
|
9
9
|
/**
|
|
10
10
|
* Marker font resolution per ECMA-376 §17.9.6:
|
|
11
|
-
* 1. explicit numbering-level rPr (`attrs.
|
|
11
|
+
* 1. explicit numbering-level rPr (`attrs.listMarkerFormatting`),
|
|
12
12
|
* 2. first body text run's font,
|
|
13
13
|
* 3. paragraph defaults, then document defaults.
|
|
14
14
|
*/
|
|
@@ -16,6 +16,8 @@ declare function resolveListMarkerFont(block: ParagraphBlock): {
|
|
|
16
16
|
fontFamily: string;
|
|
17
17
|
fontSize: number;
|
|
18
18
|
bold?: boolean;
|
|
19
|
+
italic?: boolean;
|
|
20
|
+
rtl?: boolean;
|
|
19
21
|
};
|
|
20
22
|
/**
|
|
21
23
|
* Compute the marker's inline-block width in pixels, or 0 if the paragraph
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { hasCjk, hasComplexScript } from "../../utils/scriptSegments.js";
|
|
2
|
+
import { hasComplexScriptFormatting, resolveComplexScriptFormatting } from "./complexScriptFormatting.js";
|
|
1
3
|
import { ptToPx } from "./measureHelpers.js";
|
|
2
4
|
import { measureTextWidth } from "./measureProvider.js";
|
|
3
5
|
//#region src/layout-engine/measure/listMarkerWidth.ts
|
|
@@ -12,21 +14,33 @@ const DEFAULT_TAB_STOP_TWIPS = 720;
|
|
|
12
14
|
const TWIPS_TO_PX = 96 / 1440;
|
|
13
15
|
/**
|
|
14
16
|
* Marker font resolution per ECMA-376 §17.9.6:
|
|
15
|
-
* 1. explicit numbering-level rPr (`attrs.
|
|
17
|
+
* 1. explicit numbering-level rPr (`attrs.listMarkerFormatting`),
|
|
16
18
|
* 2. first body text run's font,
|
|
17
19
|
* 3. paragraph defaults, then document defaults.
|
|
18
20
|
*/
|
|
19
21
|
function resolveListMarkerFont(block) {
|
|
20
22
|
const attrs = block.attrs;
|
|
21
23
|
const firstTextRun = block.runs.find((r) => r.kind === "text");
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
fontFamily,
|
|
27
|
-
fontSize,
|
|
28
|
-
...bold !== void 0 ? { bold } : {}
|
|
24
|
+
const markerFormatting = attrs?.listMarkerFormatting;
|
|
25
|
+
const bold = markerFormatting?.bold ?? firstTextRun?.bold;
|
|
26
|
+
const italic = markerFormatting?.italic ?? firstTextRun?.italic;
|
|
27
|
+
const base = {
|
|
28
|
+
fontFamily: markerFormatting?.fontFamily ?? firstTextRun?.fontFamily ?? attrs?.defaultFontFamily ?? DEFAULT_FONT_FAMILY,
|
|
29
|
+
fontSize: markerFormatting?.fontSize ?? firstTextRun?.fontSize ?? attrs?.defaultFontSize ?? DEFAULT_FONT_SIZE,
|
|
30
|
+
...bold !== void 0 ? { bold } : {},
|
|
31
|
+
...italic !== void 0 ? { italic } : {},
|
|
32
|
+
...markerFormatting?.rtl !== void 0 ? { rtl: markerFormatting.rtl } : {}
|
|
29
33
|
};
|
|
34
|
+
const marker = attrs?.listMarker ?? "";
|
|
35
|
+
if (markerFormatting && hasComplexScriptFormatting(markerFormatting) && (markerFormatting.forceComplexScript || hasComplexScript(marker))) return {
|
|
36
|
+
...base,
|
|
37
|
+
...resolveComplexScriptFormatting(markerFormatting)
|
|
38
|
+
};
|
|
39
|
+
if (markerFormatting?.eastAsiaFontFamily && hasCjk(marker)) return {
|
|
40
|
+
...base,
|
|
41
|
+
fontFamily: markerFormatting.eastAsiaFontFamily
|
|
42
|
+
};
|
|
43
|
+
return base;
|
|
30
44
|
}
|
|
31
45
|
/**
|
|
32
46
|
* Compute the marker's inline-block width in pixels, or 0 if the paragraph
|
|
@@ -49,12 +63,7 @@ function resolveListMarkerFont(block) {
|
|
|
49
63
|
function getListMarkerInlineWidth(block) {
|
|
50
64
|
const attrs = block.attrs;
|
|
51
65
|
if (!attrs?.listMarker || attrs.listMarkerHidden) return 0;
|
|
52
|
-
const
|
|
53
|
-
const style = {
|
|
54
|
-
fontFamily,
|
|
55
|
-
fontSize,
|
|
56
|
-
...bold !== void 0 ? { bold } : {}
|
|
57
|
-
};
|
|
66
|
+
const style = resolveListMarkerFont(block);
|
|
58
67
|
const naturalWidth = measureTextWidth(attrs.listMarker, style);
|
|
59
68
|
const markerEndOffset = getMarkerEndOffset(naturalWidth, attrs.listMarkerAlignment);
|
|
60
69
|
const suffix = attrs.listMarkerSuffix ?? "tab";
|
|
@@ -75,19 +84,14 @@ function getListMarkerInlineWidth(block) {
|
|
|
75
84
|
let bodyStart;
|
|
76
85
|
if (firstCustomPast !== void 0 && firstGridPast !== void 0) bodyStart = Math.min(firstCustomPast, firstGridPast);
|
|
77
86
|
else bodyStart = firstCustomPast ?? firstGridPast;
|
|
78
|
-
if (bodyStart === void 0) return naturalWidth + ptToPx(fontSize) * .5;
|
|
87
|
+
if (bodyStart === void 0) return naturalWidth + ptToPx(style.fontSize ?? DEFAULT_FONT_SIZE) * .5;
|
|
79
88
|
return bodyStart - markerStartPx;
|
|
80
89
|
}
|
|
81
90
|
/** Paint-only offset that places the marker around its authored list anchor. */
|
|
82
91
|
function getListMarkerVisualOffset(block) {
|
|
83
92
|
const attrs = block.attrs;
|
|
84
93
|
if (!attrs?.listMarker || attrs.listMarkerHidden) return 0;
|
|
85
|
-
const
|
|
86
|
-
const naturalWidth = measureTextWidth(attrs.listMarker, {
|
|
87
|
-
fontFamily,
|
|
88
|
-
fontSize,
|
|
89
|
-
...bold !== void 0 ? { bold } : {}
|
|
90
|
-
});
|
|
94
|
+
const naturalWidth = measureTextWidth(attrs.listMarker, resolveListMarkerFont(block));
|
|
91
95
|
if (attrs.listMarkerAlignment === "right") return -naturalWidth;
|
|
92
96
|
if (attrs.listMarkerAlignment === "center") return -naturalWidth / 2;
|
|
93
97
|
return 0;
|