@stll/folio-core 0.22.3 → 0.23.1
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/ai-edits/apply.d.ts +1 -1
- package/dist/controller/layoutPipeline.js +7 -3
- package/dist/document-operations.d.ts +4 -4
- package/dist/document-operations.js +17 -1
- 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 +2 -11
- package/dist/docx/numberingParser.js +3 -79
- package/dist/docx/ooxmlCounterFormatter.d.ts +8 -0
- package/dist/docx/ooxmlCounterFormatter.js +134 -0
- package/dist/docx/rezip.d.ts +1 -1
- package/dist/docx/rezip.js +12 -31
- 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 +6 -0
- package/dist/layout-bridge/convert/toFlowBlocks.js +51 -109
- package/dist/layout-engine/index.d.ts +3 -2
- package/dist/layout-engine/index.js +40 -16
- package/dist/layout-engine/measure/cache.js +1 -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/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 +31 -4
- package/dist/layout-painter/imageLayout.d.ts +1 -1
- package/dist/layout-painter/index.js +2 -1
- package/dist/layout-painter/renderPage.js +9 -3
- package/dist/layout-painter/renderParagraph.js +42 -25
- package/dist/layout-painter/renderUtils.d.ts +2 -0
- package/dist/managers/AutoSaveManager.js +8 -40
- package/dist/managers/TableSelectionManager.d.ts +1 -1
- package/dist/managers/autoSaveCodec.d.ts +17 -0
- package/dist/managers/autoSaveCodec.js +109 -0
- package/dist/paged-layout/sectionGeometry.d.ts +3 -2
- package/dist/paged-layout/sectionGeometry.js +17 -1
- package/dist/prosemirror/attrs/index.js +278 -25
- package/dist/prosemirror/commands/comments.js +3 -3
- package/dist/prosemirror/commands/formatting.js +19 -19
- package/dist/prosemirror/commands/index.d.ts +2 -2
- package/dist/prosemirror/commands/paragraph.js +32 -32
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +4 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +8 -8
- package/dist/prosemirror/commands/table.d.ts +10 -52
- package/dist/prosemirror/commands/table.js +34 -34
- package/dist/prosemirror/conversion/fromProseDoc.js +24 -33
- package/dist/prosemirror/conversion/sdtAttrs.d.ts +2 -1
- package/dist/prosemirror/conversion/sdtAttrs.js +9 -4
- package/dist/prosemirror/conversion/toProseDoc.js +4 -1
- package/dist/prosemirror/extensions/ExtensionManager.d.ts +6 -3
- package/dist/prosemirror/extensions/ExtensionManager.js +5 -3
- package/dist/prosemirror/extensions/core/ParagraphExtension.d.ts +1 -1
- package/dist/prosemirror/extensions/features/ListExtension.js +4 -4
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.d.ts +3 -2
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +31 -17
- package/dist/prosemirror/extensions/nodes/ShapeExtension.d.ts +1 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.js +1 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +1 -1
- package/dist/prosemirror/extensions/types.d.ts +134 -1
- package/dist/prosemirror/index.d.ts +2 -2
- package/dist/prosemirror/plugins/selectionTracker.js +25 -99
- package/dist/prosemirror/revisionCarriers.js +3 -1
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/index.js +87 -0
- package/dist/prosemirror/schema/marks.d.ts +8 -0
- package/dist/prosemirror/schema/nodes.d.ts +15 -2
- package/dist/prosemirror/selectionState.d.ts +11 -5
- package/dist/prosemirror/selectionState.js +94 -57
- package/dist/utils/tableOperations.d.ts +7 -6
- package/package.json +3 -3
|
@@ -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,15 +1,15 @@
|
|
|
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
|
-
import { NUMBER_FORMAT_VALUES } from "../../types/documentEnumValues.js";
|
|
13
13
|
import { resolveColor, resolveHighlightToCss } from "../../utils/colorResolver.js";
|
|
14
14
|
import { resolveThemeFont } from "../../utils/fontResolver.js";
|
|
15
15
|
import { resolveShadingFill } from "../../utils/formatToStyle.js";
|
|
@@ -75,51 +75,8 @@ function formatNumberedMarker(counters, level) {
|
|
|
75
75
|
if (parts.length === 0) return "1.";
|
|
76
76
|
return `${parts.join(".")}.`;
|
|
77
77
|
}
|
|
78
|
-
const ROMAN_PAIRS = [
|
|
79
|
-
[1e3, "M"],
|
|
80
|
-
[900, "CM"],
|
|
81
|
-
[500, "D"],
|
|
82
|
-
[400, "CD"],
|
|
83
|
-
[100, "C"],
|
|
84
|
-
[90, "XC"],
|
|
85
|
-
[50, "L"],
|
|
86
|
-
[40, "XL"],
|
|
87
|
-
[10, "X"],
|
|
88
|
-
[9, "IX"],
|
|
89
|
-
[5, "V"],
|
|
90
|
-
[4, "IV"],
|
|
91
|
-
[1, "I"]
|
|
92
|
-
];
|
|
93
|
-
function toRoman(value, upper) {
|
|
94
|
-
if (value <= 0) return "";
|
|
95
|
-
let remaining = value;
|
|
96
|
-
let output = "";
|
|
97
|
-
for (const [number, symbol] of ROMAN_PAIRS) while (remaining >= number) {
|
|
98
|
-
output += symbol;
|
|
99
|
-
remaining -= number;
|
|
100
|
-
}
|
|
101
|
-
return upper ? output : output.toLowerCase();
|
|
102
|
-
}
|
|
103
|
-
function toLetter(value, upper) {
|
|
104
|
-
if (value <= 0) return "";
|
|
105
|
-
const zeroBased = value - 1;
|
|
106
|
-
const baseCodePoint = upper ? 65 : 97;
|
|
107
|
-
return String.fromCodePoint(baseCodePoint + zeroBased % 26).repeat(Math.floor(zeroBased / 26) + 1);
|
|
108
|
-
}
|
|
109
78
|
function formatCounter(value, format) {
|
|
110
|
-
|
|
111
|
-
switch (format) {
|
|
112
|
-
case "upperRoman": return toRoman(value, true);
|
|
113
|
-
case "lowerRoman": return toRoman(value, false);
|
|
114
|
-
case "upperLetter": return toLetter(value, true);
|
|
115
|
-
case "lowerLetter": return toLetter(value, false);
|
|
116
|
-
case "decimalZero": return padDecimal(value, 2);
|
|
117
|
-
case "decimalZero3": return padDecimal(value, 3);
|
|
118
|
-
case "decimalZero4": return padDecimal(value, 4);
|
|
119
|
-
case "decimalZero5": return padDecimal(value, 5);
|
|
120
|
-
case "none": return "";
|
|
121
|
-
default: return String(value);
|
|
122
|
-
}
|
|
79
|
+
return formatOoxmlCounter(value, format);
|
|
123
80
|
}
|
|
124
81
|
function resolveListTemplate(template, counters, levelFormats, forceDecimal = false) {
|
|
125
82
|
return template.replace(/%(?<digit>\d)(?<punct>[.):\]])?/gu, (...args) => {
|
|
@@ -364,7 +321,7 @@ const resolveWesternThemeFont = (fontFamily, theme) => {
|
|
|
364
321
|
return (themeRef ? resolveThemeFont(themeRef, theme?.fontScheme) : null) ?? fontFamily.ascii ?? fontFamily.hAnsi ?? void 0;
|
|
365
322
|
};
|
|
366
323
|
const resolveComplexScriptThemeFont = (fontFamily, theme) => {
|
|
367
|
-
return (fontFamily.
|
|
324
|
+
return (fontFamily.csTheme ? resolveThemeFont(fontFamily.csTheme, theme?.fontScheme) : null) ?? fontFamily.cs ?? void 0;
|
|
368
325
|
};
|
|
369
326
|
const resolveEastAsiaThemeFont = (fontFamily, theme) => {
|
|
370
327
|
return (fontFamily.eastAsiaTheme ? resolveThemeFont(fontFamily.eastAsiaTheme, theme?.fontScheme) : null) ?? fontFamily.eastAsia ?? void 0;
|
|
@@ -400,6 +357,10 @@ function applyRunFormattingOverrides(formatting, attrs) {
|
|
|
400
357
|
if (attrs.shadow === false) formatting.textShadow = false;
|
|
401
358
|
if (attrs.outline === false) formatting.textOutline = false;
|
|
402
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;
|
|
403
364
|
}
|
|
404
365
|
function paragraphRunDefaults(pmAttrs, theme) {
|
|
405
366
|
const defaultTextFormatting = pmAttrs.defaultTextFormatting;
|
|
@@ -413,8 +374,12 @@ function paragraphRunDefaults(pmAttrs, theme) {
|
|
|
413
374
|
if (complexScriptFontFamily) result.complexScriptFontFamily = complexScriptFontFamily;
|
|
414
375
|
if (defaultTextFormatting.language) result.language = { ...defaultTextFormatting.language };
|
|
415
376
|
if (defaultTextFormatting.fontSize !== void 0) result.fontSize = defaultTextFormatting.fontSize / 2;
|
|
377
|
+
if (defaultTextFormatting.fontSizeCs !== void 0) result.complexScriptFontSize = defaultTextFormatting.fontSizeCs / 2;
|
|
416
378
|
if (defaultTextFormatting.bold !== void 0) result.bold = defaultTextFormatting.bold;
|
|
379
|
+
if (defaultTextFormatting.boldCs !== void 0) result.complexScriptBold = defaultTextFormatting.boldCs;
|
|
417
380
|
if (defaultTextFormatting.italic !== void 0) result.italic = defaultTextFormatting.italic;
|
|
381
|
+
if (defaultTextFormatting.italicCs !== void 0) result.complexScriptItalic = defaultTextFormatting.italicCs;
|
|
382
|
+
if (defaultTextFormatting.cs !== void 0) result.forceComplexScript = defaultTextFormatting.cs;
|
|
418
383
|
if (defaultTextFormatting.underline && defaultTextFormatting.underline.style !== "none") {
|
|
419
384
|
result.underline = { style: defaultTextFormatting.underline.style };
|
|
420
385
|
if (defaultTextFormatting.underline.color) result.underline.color = resolveColor(defaultTextFormatting.underline.color, theme);
|
|
@@ -650,78 +615,54 @@ function toListMarkerRevision(kind, info) {
|
|
|
650
615
|
}
|
|
651
616
|
function isAddedNumberingChange(change) {
|
|
652
617
|
const previousFormatting = change.previousFormatting;
|
|
653
|
-
return previousFormatting != null && Object.hasOwn(previousFormatting, "numPr") && previousFormatting
|
|
618
|
+
return previousFormatting != null && Object.hasOwn(previousFormatting, "numPr") && previousFormatting.numPr == null;
|
|
654
619
|
}
|
|
655
620
|
function isRemovedNumberingChange(change) {
|
|
656
621
|
const previousFormatting = change.previousFormatting;
|
|
657
|
-
return previousFormatting != null && Object.hasOwn(previousFormatting, "numPr") && isListNumPr(previousFormatting
|
|
622
|
+
return previousFormatting != null && Object.hasOwn(previousFormatting, "numPr") && isListNumPr(previousFormatting.numPr);
|
|
658
623
|
}
|
|
659
624
|
function isChangedNumberingChange(currentNumPr, change) {
|
|
660
625
|
const previousFormatting = change.previousFormatting;
|
|
661
|
-
return previousFormatting != null && Object.hasOwn(previousFormatting, "numPr") && isListNumPr(previousFormatting
|
|
626
|
+
return previousFormatting != null && Object.hasOwn(previousFormatting, "numPr") && isListNumPr(previousFormatting.numPr) && !areListNumPrEqual(previousFormatting.numPr, currentNumPr);
|
|
662
627
|
}
|
|
663
628
|
function areListNumPrEqual(left, right) {
|
|
664
629
|
return left.numId === right.numId && left.ilvl === right.ilvl;
|
|
665
630
|
}
|
|
666
|
-
function isRecord(value) {
|
|
667
|
-
return typeof value === "object" && value !== null;
|
|
668
|
-
}
|
|
669
631
|
function isListNumPr(value) {
|
|
670
|
-
|
|
671
|
-
const numId = value["numId"];
|
|
672
|
-
const ilvl = value["ilvl"];
|
|
673
|
-
return (numId === void 0 || typeof numId === "number") && (ilvl === void 0 || typeof ilvl === "number");
|
|
674
|
-
}
|
|
675
|
-
function isNumberFormat(value) {
|
|
676
|
-
return NUMBER_FORMAT_VALUES.some((format) => format === value);
|
|
677
|
-
}
|
|
678
|
-
function readNumberFormats(value) {
|
|
679
|
-
if (!Array.isArray(value)) return;
|
|
680
|
-
const formats = [];
|
|
681
|
-
for (const item of value) {
|
|
682
|
-
if (!isNumberFormat(item)) return;
|
|
683
|
-
formats.push(item);
|
|
684
|
-
}
|
|
685
|
-
return formats;
|
|
686
|
-
}
|
|
687
|
-
function readListMarkerSuffix(value) {
|
|
688
|
-
if (value === "tab" || value === "space" || value === "nothing") return value;
|
|
689
|
-
}
|
|
690
|
-
function readListMarkerAlignment(value) {
|
|
691
|
-
if (value === "left" || value === "center" || value === "right") return value;
|
|
632
|
+
return value !== void 0 && value !== null;
|
|
692
633
|
}
|
|
693
634
|
function toPreviousListAttrs(previousFormatting) {
|
|
694
635
|
const attrs = {};
|
|
695
|
-
const numPr = previousFormatting
|
|
636
|
+
const numPr = previousFormatting.numPr;
|
|
696
637
|
if (isListNumPr(numPr)) attrs.numPr = numPr;
|
|
697
|
-
const listIsBullet = previousFormatting
|
|
698
|
-
if (
|
|
699
|
-
const listIsLegal = previousFormatting
|
|
700
|
-
if (
|
|
701
|
-
const listMarker = previousFormatting
|
|
702
|
-
if (
|
|
703
|
-
const listNumFmt = previousFormatting
|
|
704
|
-
if (
|
|
705
|
-
const listLevelNumFmts =
|
|
706
|
-
if (listLevelNumFmts) attrs.listLevelNumFmts = listLevelNumFmts;
|
|
707
|
-
const listLevelStarts = previousFormatting
|
|
708
|
-
if (
|
|
709
|
-
const listAbstractNumId = previousFormatting
|
|
710
|
-
if (
|
|
711
|
-
const listStartOverride = previousFormatting
|
|
712
|
-
if (
|
|
713
|
-
const listMarkerHidden = previousFormatting
|
|
714
|
-
if (
|
|
715
|
-
const listMarkerFontFamily = previousFormatting
|
|
716
|
-
if (
|
|
717
|
-
const listMarkerFontSize = previousFormatting
|
|
718
|
-
if (
|
|
719
|
-
const listMarkerBold = previousFormatting
|
|
720
|
-
if (
|
|
721
|
-
const listMarkerAlignment =
|
|
722
|
-
if (listMarkerAlignment) attrs.listMarkerAlignment = listMarkerAlignment;
|
|
723
|
-
const listMarkerSuffix =
|
|
724
|
-
if (listMarkerSuffix) attrs.listMarkerSuffix = listMarkerSuffix;
|
|
638
|
+
const listIsBullet = previousFormatting.listIsBullet;
|
|
639
|
+
if (listIsBullet !== void 0) attrs.listIsBullet = listIsBullet;
|
|
640
|
+
const listIsLegal = previousFormatting.listIsLegal;
|
|
641
|
+
if (listIsLegal !== void 0) attrs.listIsLegal = listIsLegal;
|
|
642
|
+
const listMarker = previousFormatting.listMarker;
|
|
643
|
+
if (listMarker !== void 0) attrs.listMarker = listMarker;
|
|
644
|
+
const listNumFmt = previousFormatting.listNumFmt;
|
|
645
|
+
if (listNumFmt !== void 0) attrs.listNumFmt = listNumFmt;
|
|
646
|
+
const listLevelNumFmts = previousFormatting.listLevelNumFmts;
|
|
647
|
+
if (listLevelNumFmts !== void 0) attrs.listLevelNumFmts = listLevelNumFmts;
|
|
648
|
+
const listLevelStarts = previousFormatting.listLevelStarts;
|
|
649
|
+
if (listLevelStarts !== void 0) attrs.listLevelStarts = listLevelStarts;
|
|
650
|
+
const listAbstractNumId = previousFormatting.listAbstractNumId;
|
|
651
|
+
if (listAbstractNumId !== void 0) attrs.listAbstractNumId = listAbstractNumId;
|
|
652
|
+
const listStartOverride = previousFormatting.listStartOverride;
|
|
653
|
+
if (listStartOverride !== void 0) attrs.listStartOverride = listStartOverride;
|
|
654
|
+
const listMarkerHidden = previousFormatting.listMarkerHidden;
|
|
655
|
+
if (listMarkerHidden !== void 0) attrs.listMarkerHidden = listMarkerHidden;
|
|
656
|
+
const listMarkerFontFamily = previousFormatting.listMarkerFontFamily;
|
|
657
|
+
if (listMarkerFontFamily !== void 0) attrs.listMarkerFontFamily = listMarkerFontFamily;
|
|
658
|
+
const listMarkerFontSize = previousFormatting.listMarkerFontSize;
|
|
659
|
+
if (listMarkerFontSize !== void 0) attrs.listMarkerFontSize = listMarkerFontSize;
|
|
660
|
+
const listMarkerBold = previousFormatting.listMarkerBold;
|
|
661
|
+
if (listMarkerBold !== void 0) attrs.listMarkerBold = listMarkerBold;
|
|
662
|
+
const listMarkerAlignment = previousFormatting.listMarkerAlignment;
|
|
663
|
+
if (listMarkerAlignment !== void 0) attrs.listMarkerAlignment = listMarkerAlignment;
|
|
664
|
+
const listMarkerSuffix = previousFormatting.listMarkerSuffix;
|
|
665
|
+
if (listMarkerSuffix !== void 0) attrs.listMarkerSuffix = listMarkerSuffix;
|
|
725
666
|
return attrs;
|
|
726
667
|
}
|
|
727
668
|
function resolveDeletedListMarker(previousListAttrs, listCounters, listAbstractCounters, listSeenNumIds) {
|
|
@@ -846,10 +787,10 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
|
|
|
846
787
|
if (pmAttrs.widowControl === false) attrs.widowControl = false;
|
|
847
788
|
if (pmAttrs.contextualSpacing) attrs.contextualSpacing = true;
|
|
848
789
|
if (pmAttrs.runInWithNext) attrs.runInWithNext = true;
|
|
849
|
-
|
|
790
|
+
const bidi = directionToBidi(pmAttrs.direction);
|
|
791
|
+
if (bidi !== void 0) attrs.bidi = bidi;
|
|
850
792
|
if (pmAttrs.styleId) attrs.styleId = pmAttrs.styleId;
|
|
851
|
-
const
|
|
852
|
-
const propertyChanges = Array.isArray(pPrChange) ? pPrChange : [];
|
|
793
|
+
const propertyChanges = pmAttrs._propertyChanges ?? [];
|
|
853
794
|
let changedNumberingChange;
|
|
854
795
|
if (pmAttrs.numPr) {
|
|
855
796
|
const numPr = {};
|
|
@@ -1213,7 +1154,7 @@ function convertTable(node, startPos, options) {
|
|
|
1213
1154
|
if (justification) tableBlock.justification = justification;
|
|
1214
1155
|
if (indentPx !== void 0) tableBlock.indent = indentPx;
|
|
1215
1156
|
if (floatingPx) tableBlock.floating = floatingPx;
|
|
1216
|
-
if (originalFormatting?.bidi) tableBlock.bidi = true;
|
|
1157
|
+
if (attrs._resolvedBidi ?? originalFormatting?.bidi) tableBlock.bidi = true;
|
|
1217
1158
|
return tableBlock;
|
|
1218
1159
|
}
|
|
1219
1160
|
/**
|
|
@@ -1488,6 +1429,7 @@ function toFlowBlocks(doc, options = {}) {
|
|
|
1488
1429
|
const breakType = secProps?.sectionStart ?? pmAttrs.sectionBreakType;
|
|
1489
1430
|
if (breakType) sectionBreak.type = breakType;
|
|
1490
1431
|
if (secProps) {
|
|
1432
|
+
sectionBreak.pageNumbering = getPageNumbering(secProps);
|
|
1491
1433
|
const documentGridLinePitchTwips = resolveDocumentGridLinePitch(secProps.docGrid);
|
|
1492
1434
|
if (documentGridLinePitchTwips !== void 0) sectionBreak.documentGridLinePitchTwips = documentGridLinePitchTwips;
|
|
1493
1435
|
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, 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, 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");
|
|
@@ -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 };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SCRIPT_CLASS, hasCjk, hasComplexScript, scriptClassOf, segmentByScript } from "../../utils/scriptSegments.js";
|
|
2
2
|
import { getCachedFontMetrics, getCachedTextWidth, getTextWidthCacheGeneration, setCachedFontMetrics, setCachedTextWidth } from "./cache.js";
|
|
3
|
+
import { hasComplexScriptFormatting, resolveComplexScriptFormatting } from "./complexScriptFormatting.js";
|
|
3
4
|
import { buildFontString, getResolvedData, ptToPx } from "./measureHelpers.js";
|
|
4
5
|
import { setMeasureProvider } from "./measureProvider.js";
|
|
5
6
|
import { canPrefetchMeasurement, prefetchMeasurement } from "./measureWorker.js";
|
|
@@ -115,10 +116,14 @@ function canvasGetFontMetrics(style) {
|
|
|
115
116
|
* @param style - Font styling properties
|
|
116
117
|
* @returns Width in pixels
|
|
117
118
|
*/
|
|
118
|
-
function canvasMeasureTextWidth(text,
|
|
119
|
+
function canvasMeasureTextWidth(text, sourceStyle) {
|
|
119
120
|
if (!text) return 0;
|
|
121
|
+
const style = sourceStyle.forceComplexScript ? {
|
|
122
|
+
...sourceStyle,
|
|
123
|
+
...resolveComplexScriptFormatting(sourceStyle)
|
|
124
|
+
} : sourceStyle;
|
|
120
125
|
const measuredText = applyTextTransform(text, style);
|
|
121
|
-
if (!style.letterSpacing && needsPerScriptFonts(style, measuredText)) return measureMixedScriptWidth(measuredText, style);
|
|
126
|
+
if (!sourceStyle.forceComplexScript && !style.letterSpacing && needsPerScriptFonts(style, measuredText)) return measureMixedScriptWidth(measuredText, style);
|
|
122
127
|
const ctx = getCanvasContext();
|
|
123
128
|
const font = buildFontString(style);
|
|
124
129
|
const letterSpacing = style.letterSpacing ?? 0;
|
|
@@ -156,9 +161,9 @@ function canvasMeasureTextWidth(text, style) {
|
|
|
156
161
|
* letter spacing, horizontal scale, transform, and the EA font so the segment
|
|
157
162
|
* takes the single-font path (no double-counting, no recursion).
|
|
158
163
|
*/
|
|
159
|
-
function glyphAdvanceStyle(style
|
|
164
|
+
function glyphAdvanceStyle(style) {
|
|
160
165
|
const result = {};
|
|
161
|
-
if (fontFamily !== void 0) result.fontFamily = fontFamily;
|
|
166
|
+
if (style.fontFamily !== void 0) result.fontFamily = style.fontFamily;
|
|
162
167
|
if (style.fontSize !== void 0) result.fontSize = style.fontSize;
|
|
163
168
|
if (style.bold !== void 0) result.bold = style.bold;
|
|
164
169
|
if (style.italic !== void 0) result.italic = style.italic;
|
|
@@ -179,19 +184,28 @@ function glyphAdvanceStyle(style, fontFamily) {
|
|
|
179
184
|
*/
|
|
180
185
|
function needsPerScriptFonts(style, measuredText) {
|
|
181
186
|
if (style.eastAsiaFontFamily && hasCjk(measuredText)) return true;
|
|
182
|
-
return
|
|
187
|
+
return hasComplexScriptFormatting(style) && hasComplexScript(measuredText);
|
|
183
188
|
}
|
|
184
|
-
/**
|
|
185
|
-
function
|
|
186
|
-
if (script === SCRIPT_CLASS.eastAsia)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
+
/** Resolve the independent font/style slot selected by a script segment. */
|
|
190
|
+
function scriptStyle(style, script) {
|
|
191
|
+
if (script === SCRIPT_CLASS.eastAsia) {
|
|
192
|
+
if (style.eastAsiaFontFamily === void 0) return style;
|
|
193
|
+
return {
|
|
194
|
+
...style,
|
|
195
|
+
fontFamily: style.eastAsiaFontFamily
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (script === SCRIPT_CLASS.complex) return {
|
|
199
|
+
...style,
|
|
200
|
+
...resolveComplexScriptFormatting(style)
|
|
201
|
+
};
|
|
202
|
+
return style;
|
|
189
203
|
}
|
|
190
204
|
function measureMixedScriptWidth(measuredText, style) {
|
|
191
205
|
const letterSpacing = style.letterSpacing ?? 0;
|
|
192
206
|
const horizontalScale = getHorizontalScaleFactor(style);
|
|
193
207
|
let glyphWidth = 0;
|
|
194
|
-
for (const segment of segmentByScript(measuredText)) glyphWidth += canvasMeasureTextWidth(segment.text, glyphAdvanceStyle(
|
|
208
|
+
for (const segment of segmentByScript(measuredText)) glyphWidth += canvasMeasureTextWidth(segment.text, glyphAdvanceStyle(scriptStyle(style, segment.script)));
|
|
195
209
|
let width = glyphWidth;
|
|
196
210
|
if (letterSpacing) {
|
|
197
211
|
const codePoints = countCodePoints(measuredText);
|
|
@@ -247,7 +261,11 @@ function canvasMeasureText(text, style) {
|
|
|
247
261
|
* @param style - Font styling properties
|
|
248
262
|
* @returns Run measurement with width and per-character widths
|
|
249
263
|
*/
|
|
250
|
-
function canvasMeasureRun(text,
|
|
264
|
+
function canvasMeasureRun(text, sourceStyle) {
|
|
265
|
+
const style = sourceStyle.forceComplexScript ? {
|
|
266
|
+
...sourceStyle,
|
|
267
|
+
...resolveComplexScriptFormatting(sourceStyle)
|
|
268
|
+
} : sourceStyle;
|
|
251
269
|
const metrics = canvasGetFontMetrics(style);
|
|
252
270
|
if (!text) return {
|
|
253
271
|
width: 0,
|
|
@@ -262,10 +280,7 @@ function canvasMeasureRun(text, style) {
|
|
|
262
280
|
...style,
|
|
263
281
|
fontFamily: style.eastAsiaFontFamily
|
|
264
282
|
}) : void 0;
|
|
265
|
-
const complexScriptFont = style
|
|
266
|
-
...style,
|
|
267
|
-
fontFamily: style.complexScriptFontFamily
|
|
268
|
-
}) : void 0;
|
|
283
|
+
const complexScriptFont = hasComplexScriptFormatting(style) && !style.letterSpacing ? buildFontString(scriptStyle(style, SCRIPT_CLASS.complex)) : void 0;
|
|
269
284
|
const letterSpacing = style.letterSpacing ?? 0;
|
|
270
285
|
const scale = getHorizontalScaleFactor(style);
|
|
271
286
|
const charWidths = [];
|
|
@@ -32,6 +32,10 @@ function buildRunFontStyle(run, fallbackFontFamily, fallbackFontSize) {
|
|
|
32
32
|
fontFamily: run.fontFamily ?? fallbackFontFamily,
|
|
33
33
|
...run.eastAsiaFontFamily !== void 0 ? { eastAsiaFontFamily: run.eastAsiaFontFamily } : {},
|
|
34
34
|
...run.complexScriptFontFamily !== void 0 ? { complexScriptFontFamily: run.complexScriptFontFamily } : {},
|
|
35
|
+
...run.complexScriptFontSize !== void 0 ? { complexScriptFontSize: run.complexScriptFontSize } : {},
|
|
36
|
+
...run.complexScriptBold !== void 0 ? { complexScriptBold: run.complexScriptBold } : {},
|
|
37
|
+
...run.complexScriptItalic !== void 0 ? { complexScriptItalic: run.complexScriptItalic } : {},
|
|
38
|
+
...run.forceComplexScript !== void 0 ? { forceComplexScript: run.forceComplexScript } : {},
|
|
35
39
|
fontSize,
|
|
36
40
|
...run.bold !== void 0 ? { bold: run.bold } : {},
|
|
37
41
|
...run.italic !== void 0 ? { italic: run.italic } : {},
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { calculateTabWidth, pixelsToTwips } from "../../prosemirror/utils/tabCalculator.js";
|
|
2
2
|
import { CJK_FALLBACK_FONT_FAMILY, isCjkFont } from "../../utils/fontResolver.js";
|
|
3
3
|
import { inlineImageBoundingBox } from "../../utils/rotationBoundingBox.js";
|
|
4
|
-
import { hasCjk } from "../../utils/scriptSegments.js";
|
|
4
|
+
import { hasCjk, hasComplexScript } from "../../utils/scriptSegments.js";
|
|
5
5
|
import { measuredLineAdvance } from "../lineFlow.js";
|
|
6
6
|
import { isFloatingImageRun } from "../types.js";
|
|
7
7
|
import { clampFloatingWrapMargins } from "./clampFloatingWrapMargins.js";
|
|
8
|
+
import { hasComplexScriptFormatting, resolveComplexScriptFormatting } from "./complexScriptFormatting.js";
|
|
8
9
|
import { resolveEffectiveLineBreakPolicy } from "./effectiveLineBreakPolicy.js";
|
|
9
10
|
import { getFloatingAvailableWidth, getFloatingMargins } from "./floatingZones.js";
|
|
10
11
|
import { defaultLineBreakProvider, getLineBreakProvider } from "./lineBreakProvider.js";
|
|
@@ -97,6 +98,15 @@ function cjkLineHeightStyle(run, baseStyle) {
|
|
|
97
98
|
fontFamily: CJK_FALLBACK_FONT_FAMILY
|
|
98
99
|
};
|
|
99
100
|
}
|
|
101
|
+
/** Pick the dominant typography metrics for a run containing complex script. */
|
|
102
|
+
function complexScriptLineHeightStyle(run, baseStyle) {
|
|
103
|
+
if (!hasComplexScriptFormatting(run) || !run.forceComplexScript && !hasComplexScript(run.text)) return baseStyle;
|
|
104
|
+
const complexStyle = {
|
|
105
|
+
...baseStyle,
|
|
106
|
+
...resolveComplexScriptFormatting(run)
|
|
107
|
+
};
|
|
108
|
+
return (complexStyle.fontSize ?? DEFAULT_FONT_SIZE) >= (baseStyle.fontSize ?? DEFAULT_FONT_SIZE) ? complexStyle : baseStyle;
|
|
109
|
+
}
|
|
100
110
|
/**
|
|
101
111
|
* Calculate typography metrics from font size and spacing settings
|
|
102
112
|
*
|
|
@@ -1018,7 +1028,7 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
1018
1028
|
run: textRun
|
|
1019
1029
|
});
|
|
1020
1030
|
const breakPolicy = effectiveLineBreakPolicy.provider;
|
|
1021
|
-
const lineHeightStyle = cjkLineHeightStyle(textRun, style);
|
|
1031
|
+
const lineHeightStyle = cjkLineHeightStyle(textRun, complexScriptLineHeightStyle(textRun, style));
|
|
1022
1032
|
updateMaxFont(lineHeightStyle);
|
|
1023
1033
|
if (!text || text.length === 0) {
|
|
1024
1034
|
currentLine.toRun = runIndex;
|
|
@@ -1095,7 +1105,7 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
1095
1105
|
}
|
|
1096
1106
|
}
|
|
1097
1107
|
if (fittingPrefix) {
|
|
1098
|
-
for (const segment of fittingPrefix.segments) updateMaxFont(cjkLineHeightStyle(segment.run, segment.style));
|
|
1108
|
+
for (const segment of fittingPrefix.segments) updateMaxFont(cjkLineHeightStyle(segment.run, complexScriptLineHeightStyle(segment.run, segment.style)));
|
|
1099
1109
|
currentLine.width += fittingPrefix.width + measureTextWidth("-", fittingPrefix.hyphenStyle);
|
|
1100
1110
|
currentLine.trailingWhitespaceWidth = 0;
|
|
1101
1111
|
currentLine.toRun = fittingPrefix.endRunIndex;
|
|
@@ -26,6 +26,10 @@ type FontStyle = {
|
|
|
26
26
|
* points. Same contract as `eastAsiaFontFamily`, over a different slot.
|
|
27
27
|
*/
|
|
28
28
|
complexScriptFontFamily?: string;
|
|
29
|
+
complexScriptFontSize?: number;
|
|
30
|
+
complexScriptBold?: boolean;
|
|
31
|
+
complexScriptItalic?: boolean;
|
|
32
|
+
forceComplexScript?: boolean;
|
|
29
33
|
fontSize?: number;
|
|
30
34
|
bold?: boolean;
|
|
31
35
|
italic?: boolean;
|