@stll/folio-core 0.48.0 → 0.50.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/ai-edits/apply.js +565 -121
- package/dist/ai-edits/headless.d.ts +37 -1
- package/dist/ai-edits/headless.js +47 -16
- package/dist/ai-edits/minimal-replacement.d.ts +64 -0
- package/dist/ai-edits/minimal-replacement.js +282 -0
- package/dist/controller/layoutPipeline.js +11 -1
- package/dist/display-list/build/paragraphPrimitives.js +63 -7
- package/dist/display-list/build/textBoxPrimitives.js +1 -1
- package/dist/display-list/build/unsupported.d.ts +2 -2
- package/dist/display-list/build/unsupported.js +0 -0
- package/dist/display-list/dom/renderDisplayListToDom.d.ts +10 -1
- package/dist/display-list/dom/renderDisplayListToDom.js +8 -8
- package/dist/display-list/html/renderDisplayListToHtml.d.ts +21 -0
- package/dist/display-list/html/renderDisplayListToHtml.js +126 -0
- package/dist/display-list/selectDisplayPages.d.ts +6 -0
- package/dist/display-list/selectDisplayPages.js +44 -0
- package/dist/docx/blockContentParser.js +2 -2
- package/dist/docx/bulletMarkers.d.ts +18 -2
- package/dist/docx/bulletMarkers.js +27 -2
- package/dist/docx/drawingGroupChildren.d.ts +60 -0
- package/dist/docx/drawingGroupChildren.js +176 -0
- package/dist/docx/drawingUtils.js +3 -0
- package/dist/docx/groupDrawingParser.d.ts +7 -1
- package/dist/docx/groupDrawingParser.js +123 -32
- package/dist/docx/packageParts.d.ts +45 -1
- package/dist/docx/packageParts.js +93 -2
- package/dist/docx/paraIdAttribute.d.ts +3 -2
- package/dist/docx/paragraphParser.js +91 -7
- package/dist/docx/paragraphTextBoxEnrichment.js +126 -4
- package/dist/docx/runParser.js +10 -0
- package/dist/docx/selectiveSaveFlags.d.ts +10 -3
- package/dist/docx/selectiveSaveFlags.js +1 -1
- package/dist/docx/selectiveXmlPatch.d.ts +56 -34
- package/dist/docx/selectiveXmlPatch.js +222 -115
- package/dist/docx/serializer/groupTextBoxWriteBack.d.ts +12 -0
- package/dist/docx/serializer/groupTextBoxWriteBack.js +101 -0
- package/dist/docx/serializer/paragraphSerializer.js +5 -4
- package/dist/docx/serializer/runSerializer.d.ts +5 -1
- package/dist/docx/serializer/runSerializer.js +4 -3
- package/dist/docx/shapeAlternateContent.d.ts +25 -0
- package/dist/docx/shapeAlternateContent.js +52 -0
- package/dist/docx/textBoxParser.d.ts +10 -2
- package/dist/docx/textBoxParser.js +9 -3
- package/dist/export-pdf.d.ts +35 -2
- package/dist/export-pdf.js +51 -20
- package/dist/fonts/fontsourceFaces.d.ts +47 -0
- package/dist/fonts/fontsourceFaces.js +230 -0
- package/dist/internal/headlessRevisionResolution.js +50 -13
- package/dist/layout-bridge/convert/flowBlockPostprocessing.d.ts +8 -0
- package/dist/layout-bridge/convert/flowBlockPostprocessing.js +106 -0
- package/dist/layout-bridge/convert/flowBorders.d.ts +17 -0
- package/dist/layout-bridge/convert/flowBorders.js +31 -0
- package/dist/layout-bridge/convert/flowConversionShared.d.ts +111 -0
- package/dist/layout-bridge/convert/flowConversionShared.js +23 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +2 -1
- package/dist/layout-bridge/convert/footnoteLayout.js +2 -1
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +2 -1
- package/dist/layout-bridge/convert/imageConversion.d.ts +33 -0
- package/dist/layout-bridge/convert/imageConversion.js +118 -0
- package/dist/layout-bridge/convert/listMarkers.d.ts +28 -0
- package/dist/layout-bridge/convert/listMarkers.js +98 -0
- package/dist/layout-bridge/convert/noteReferences.d.ts +14 -0
- package/dist/layout-bridge/convert/noteReferences.js +29 -0
- package/dist/layout-bridge/convert/pageBreakSplitting.d.ts +16 -0
- package/dist/layout-bridge/convert/pageBreakSplitting.js +140 -0
- package/dist/layout-bridge/convert/paragraphAttrs.d.ts +20 -0
- package/dist/layout-bridge/convert/paragraphAttrs.js +234 -0
- package/dist/layout-bridge/convert/paragraphConversion.d.ts +12 -0
- package/dist/layout-bridge/convert/paragraphConversion.js +112 -0
- package/dist/layout-bridge/convert/paragraphRuns.d.ts +15 -0
- package/dist/layout-bridge/convert/paragraphRuns.js +281 -0
- package/dist/layout-bridge/convert/runFormattingMerge.d.ts +19 -0
- package/dist/layout-bridge/convert/runFormattingMerge.js +167 -0
- package/dist/layout-bridge/convert/runMarkFormatting.d.ts +11 -0
- package/dist/layout-bridge/convert/runMarkFormatting.js +291 -0
- package/dist/layout-bridge/convert/sectionBoundaries.d.ts +35 -0
- package/dist/layout-bridge/convert/sectionBoundaries.js +114 -0
- package/dist/layout-bridge/convert/tableConversion.d.ts +12 -0
- package/dist/layout-bridge/convert/tableConversion.js +303 -0
- package/dist/layout-bridge/convert/textBoxFill.d.ts +20 -0
- package/dist/layout-bridge/convert/textBoxFill.js +42 -0
- package/dist/layout-bridge/convert/textFormattingConversion.d.ts +22 -0
- package/dist/layout-bridge/convert/textFormattingConversion.js +120 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +5 -113
- package/dist/layout-bridge/convert/toFlowBlocks.js +11 -2060
- package/dist/layout-bridge/engine/hitTest.js +1 -1
- package/dist/layout-bridge/engine/measuring/index.d.ts +2 -1
- package/dist/layout-bridge/engine/measuring/index.js +2 -1
- package/dist/layout-bridge/engine/selectionRects.js +1 -1
- package/dist/layout-engine/imageLayout.d.ts +9 -0
- package/dist/layout-engine/imageLayout.js +48 -0
- package/dist/layout-engine/index.d.ts +4 -19
- package/dist/layout-engine/index.js +14 -910
- package/dist/layout-engine/keep-together.d.ts +5 -2
- package/dist/layout-engine/keep-together.js +5 -1
- package/dist/layout-engine/layoutFlowShared.d.ts +6 -0
- package/dist/layout-engine/layoutFlowShared.js +8 -0
- package/dist/layout-engine/measure/advanceComposition.js +49 -3
- package/dist/layout-engine/measure/crossRunWords.d.ts +45 -0
- package/dist/layout-engine/measure/crossRunWords.js +172 -0
- package/dist/layout-engine/measure/floatingLineClearance.d.ts +24 -0
- package/dist/layout-engine/measure/floatingLineClearance.js +44 -0
- package/dist/layout-engine/measure/inlineObjectMetrics.d.ts +6 -0
- package/dist/layout-engine/measure/inlineObjectMetrics.js +52 -0
- package/dist/layout-engine/measure/justification.d.ts +32 -0
- package/dist/layout-engine/measure/justification.js +83 -0
- package/dist/layout-engine/measure/lineFitting.d.ts +48 -0
- package/dist/layout-engine/measure/lineFitting.js +145 -0
- package/dist/layout-engine/measure/lineTypography.d.ts +44 -0
- package/dist/layout-engine/measure/lineTypography.js +124 -0
- package/dist/layout-engine/measure/measureBlocks.js +7 -4
- package/dist/layout-engine/measure/measureContainer.js +46 -3
- package/dist/layout-engine/measure/measureHelpers.js +13 -3
- package/dist/layout-engine/measure/measureParagraph.d.ts +1 -20
- package/dist/layout-engine/measure/measureParagraph.js +41 -780
- package/dist/layout-engine/measure/paragraphMeasureShared.d.ts +109 -0
- package/dist/layout-engine/measure/paragraphMeasureShared.js +82 -0
- package/dist/layout-engine/measure/paragraphTabs.d.ts +18 -0
- package/dist/layout-engine/measure/paragraphTabs.js +78 -0
- package/dist/layout-engine/measure/smallCapsCasing.d.ts +56 -0
- package/dist/layout-engine/measure/smallCapsCasing.js +88 -0
- package/dist/layout-engine/paginator.d.ts +2 -0
- package/dist/layout-engine/paginator.js +5 -1
- package/dist/layout-engine/paragraphLayout.d.ts +23 -0
- package/dist/layout-engine/paragraphLayout.js +204 -0
- package/dist/layout-engine/paragraphSpacing.d.ts +4 -2
- package/dist/layout-engine/paragraphSpacing.js +2 -1
- package/dist/layout-engine/sectionLayout.d.ts +45 -0
- package/dist/layout-engine/sectionLayout.js +216 -0
- package/dist/layout-engine/tableLayout.d.ts +17 -0
- package/dist/layout-engine/tableLayout.js +369 -0
- package/dist/layout-engine/tableRowBreak.d.ts +8 -1
- package/dist/layout-engine/tableRowBreak.js +22 -1
- package/dist/layout-engine/textBoxLayout.d.ts +15 -0
- package/dist/layout-engine/textBoxLayout.js +137 -0
- package/dist/layout-engine/types.d.ts +21 -2
- package/dist/layout-painter/renderPage.js +1 -0
- package/dist/layout-painter/renderParagraph.js +41 -4
- package/dist/layout-painter/renderTextBox.d.ts +12 -2
- package/dist/layout-painter/renderTextBox.js +26 -2
- package/dist/paged-layout/sectionBlockWidths.d.ts +2 -1
- package/dist/paged-layout/sectionBlockWidths.js +1 -1
- package/dist/prosemirror/alternateContentAttrs.d.ts +9 -0
- package/dist/prosemirror/alternateContentAttrs.js +35 -0
- package/dist/prosemirror/attrs/index.js +90 -0
- package/dist/prosemirror/commands/comments.js +51 -41
- package/dist/prosemirror/contentControlRevisions.d.ts +43 -0
- package/dist/prosemirror/contentControlRevisions.js +84 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +46 -22
- package/dist/prosemirror/conversion/toProseDoc.js +42 -19
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +7 -7
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +7 -7
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +6 -3
- package/dist/prosemirror/extensions/nodes/SdtExtension.js +9 -2
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +1 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +3 -0
- package/dist/prosemirror/listMarker.js +2 -2
- package/dist/prosemirror/paragraphDirection.d.ts +29 -2
- package/dist/prosemirror/paragraphDirection.js +21 -2
- package/dist/prosemirror/plugins/suggestionMode.js +37 -8
- package/dist/prosemirror/rejoinRunCarriers.d.ts +27 -0
- package/dist/prosemirror/rejoinRunCarriers.js +66 -0
- package/dist/prosemirror/runIdentityAcrossRevisions.d.ts +10 -0
- package/dist/prosemirror/runIdentityAcrossRevisions.js +90 -0
- package/dist/prosemirror/schema/nodes.d.ts +37 -5
- package/dist/server.d.ts +3 -2
- package/dist/types/content.d.ts +2 -2
- package/package.json +2 -2
- package/dist/layout-engine/justifiedLineFit.d.ts +0 -7
- package/dist/layout-engine/justifiedLineFit.js +0 -6
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { FieldRun, ImageRun, LineBreakRun, MathRun, MeasuredLine, Run, TabRun, TextRun } from "../types.js";
|
|
2
|
+
import { FontMetrics, FontStyle } from "./measureTypes.js";
|
|
3
|
+
import { FloatingLineSegmentZone } from "./floatingZones.js";
|
|
4
|
+
//#region src/layout-engine/measure/paragraphMeasureShared.d.ts
|
|
5
|
+
declare const DEFAULT_FONT_SIZE = 11;
|
|
6
|
+
declare const DEFAULT_LINE_HEIGHT_MULTIPLIER = 1;
|
|
7
|
+
declare const WIDTH_TOLERANCE = 0.5;
|
|
8
|
+
/**
|
|
9
|
+
* Typography metrics for a line
|
|
10
|
+
*/
|
|
11
|
+
type LineTypography = {
|
|
12
|
+
ascent: number;
|
|
13
|
+
descent: number;
|
|
14
|
+
lineHeight: number;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* State tracking for line accumulation
|
|
18
|
+
*/
|
|
19
|
+
type LineState = {
|
|
20
|
+
fromRun: number;
|
|
21
|
+
fromChar: number;
|
|
22
|
+
toRun: number;
|
|
23
|
+
toChar: number;
|
|
24
|
+
width: number;
|
|
25
|
+
/** Width of collapsible ASCII whitespace at the current line tail. */
|
|
26
|
+
trailingWhitespaceWidth: number;
|
|
27
|
+
/** Spaces the layout may compress while justifying this line. */
|
|
28
|
+
regularSpaceWidth: number;
|
|
29
|
+
/** Paint plan set only when final-text contraction admits a candidate. */
|
|
30
|
+
justificationPaint?: NonNullable<MeasuredLine["justificationPaint"]>;
|
|
31
|
+
maxFontSize: number;
|
|
32
|
+
maxFontMetrics: FontMetrics | null;
|
|
33
|
+
/**
|
|
34
|
+
* Largest tab font on the line. Tabs are whitespace: their font sizes the
|
|
35
|
+
* line only when no other run on it does (a line of nothing but tabs).
|
|
36
|
+
*/
|
|
37
|
+
maxTabFontSize: number;
|
|
38
|
+
maxTabFontMetrics: FontMetrics | null;
|
|
39
|
+
/** Maximum inline image height in pixels (already in px, not points) */
|
|
40
|
+
maxImageHeightPx: number;
|
|
41
|
+
/** Maximum exact-height embedded-object preview on the line. */
|
|
42
|
+
maxExactImageHeightPx: number;
|
|
43
|
+
/** Maximum inline math height in pixels (already in px, not points) */
|
|
44
|
+
maxMathHeightPx: number;
|
|
45
|
+
availableWidth: number;
|
|
46
|
+
/** Left offset from floating images (pixels from content left edge) */
|
|
47
|
+
leftOffset: number;
|
|
48
|
+
/** Right offset from floating images (pixels from content right edge) */
|
|
49
|
+
rightOffset: number;
|
|
50
|
+
/** Optional split segment zones from centered floating exclusions */
|
|
51
|
+
segmentZones?: FloatingLineSegmentZone[];
|
|
52
|
+
discretionaryHyphen?: {
|
|
53
|
+
runIndex: number;
|
|
54
|
+
};
|
|
55
|
+
renderedPageBreakBefore?: boolean;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Extract FontStyle from a run that carries RunFormatting (text, tab, or
|
|
59
|
+
* field). All three share the same formatting shape, so they measure the
|
|
60
|
+
* same way; widening the parameter keeps tab-following measurement
|
|
61
|
+
* (FieldRun page numbers, etc.) consistent with TextRun handling.
|
|
62
|
+
*/
|
|
63
|
+
declare function runToFontStyle(run: TextRun | TabRun | FieldRun | MathRun): FontStyle;
|
|
64
|
+
/**
|
|
65
|
+
* Check if a run is a text run
|
|
66
|
+
*/
|
|
67
|
+
declare function isTextRun(run: Run): run is TextRun;
|
|
68
|
+
/**
|
|
69
|
+
* Check if a run is a tab run
|
|
70
|
+
*/
|
|
71
|
+
declare function isTabRun(run: Run): run is TabRun;
|
|
72
|
+
/**
|
|
73
|
+
* Check if a run is an image run
|
|
74
|
+
*/
|
|
75
|
+
declare function isImageRun(run: Run): run is ImageRun;
|
|
76
|
+
/**
|
|
77
|
+
* Check if a run is a line break run
|
|
78
|
+
*/
|
|
79
|
+
declare function isLineBreakRun(run: Run): run is LineBreakRun;
|
|
80
|
+
/**
|
|
81
|
+
* Check if a run is a field run
|
|
82
|
+
*/
|
|
83
|
+
declare function isFieldRun(run: Run): run is FieldRun;
|
|
84
|
+
/** Text a field run is measured at: its resolved value when known (so the
|
|
85
|
+
* measurer agrees with the painter), else the cached fallback. */
|
|
86
|
+
declare function fieldMeasureText(run: FieldRun, fieldValues: ReadonlyMap<number, string> | undefined): string;
|
|
87
|
+
/**
|
|
88
|
+
* Check if a run is a math equation run
|
|
89
|
+
*/
|
|
90
|
+
declare function isMathRun(run: Run): run is MathRun;
|
|
91
|
+
/**
|
|
92
|
+
* Check if text run is empty (only whitespace or no text)
|
|
93
|
+
*/
|
|
94
|
+
declare function isEmptyTextRun(run: TextRun): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Sum the inline pixel widths of runs after a tab, up to (but not including)
|
|
97
|
+
* the next tab or line break. Measured per-run so widths reserved match what
|
|
98
|
+
* the painter draws even when trailing runs use different fonts/sizes.
|
|
99
|
+
*
|
|
100
|
+
* Floating/anchored images are skipped — the painter lifts them out of the
|
|
101
|
+
* paragraph flow (see `isFloatingImageRun`) and `measureFollowingContentWidth`
|
|
102
|
+
* in the painter already excludes them, so counting their width here would
|
|
103
|
+
* desync measurer and painter on tab advance for paragraphs with a tab
|
|
104
|
+
* preceding a floating image.
|
|
105
|
+
*/
|
|
106
|
+
declare function isBlockLayoutImageRun(run: ImageRun): boolean;
|
|
107
|
+
declare function isSpaceOrTab(char: string | undefined): boolean;
|
|
108
|
+
//#endregion
|
|
109
|
+
export { DEFAULT_FONT_SIZE, DEFAULT_LINE_HEIGHT_MULTIPLIER, LineState, LineTypography, WIDTH_TOLERANCE, fieldMeasureText, isBlockLayoutImageRun, isEmptyTextRun, isFieldRun, isImageRun, isLineBreakRun, isMathRun, isSpaceOrTab, isTabRun, isTextRun, runToFontStyle };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { isFloatingImageRun } from "../types.js";
|
|
2
|
+
import { DEFAULT_FONT_FAMILY, buildRunFontStyle } from "./measureHelpers.js";
|
|
3
|
+
//#region src/layout-engine/measure/paragraphMeasureShared.ts
|
|
4
|
+
const DEFAULT_FONT_SIZE = 11;
|
|
5
|
+
const DEFAULT_LINE_HEIGHT_MULTIPLIER = 1;
|
|
6
|
+
const WIDTH_TOLERANCE = .5;
|
|
7
|
+
/**
|
|
8
|
+
* Extract FontStyle from a run that carries RunFormatting (text, tab, or
|
|
9
|
+
* field). All three share the same formatting shape, so they measure the
|
|
10
|
+
* same way; widening the parameter keeps tab-following measurement
|
|
11
|
+
* (FieldRun page numbers, etc.) consistent with TextRun handling.
|
|
12
|
+
*/
|
|
13
|
+
function runToFontStyle(run) {
|
|
14
|
+
return buildRunFontStyle(run, DEFAULT_FONT_FAMILY, 11);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Check if a run is a text run
|
|
18
|
+
*/
|
|
19
|
+
function isTextRun(run) {
|
|
20
|
+
return run.kind === "text";
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Check if a run is a tab run
|
|
24
|
+
*/
|
|
25
|
+
function isTabRun(run) {
|
|
26
|
+
return run.kind === "tab";
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check if a run is an image run
|
|
30
|
+
*/
|
|
31
|
+
function isImageRun(run) {
|
|
32
|
+
return run.kind === "image";
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Check if a run is a line break run
|
|
36
|
+
*/
|
|
37
|
+
function isLineBreakRun(run) {
|
|
38
|
+
return run.kind === "lineBreak";
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if a run is a field run
|
|
42
|
+
*/
|
|
43
|
+
function isFieldRun(run) {
|
|
44
|
+
return run.kind === "field";
|
|
45
|
+
}
|
|
46
|
+
/** Text a field run is measured at: its resolved value when known (so the
|
|
47
|
+
* measurer agrees with the painter), else the cached fallback. */
|
|
48
|
+
function fieldMeasureText(run, fieldValues) {
|
|
49
|
+
return (run.pmStart === void 0 ? void 0 : fieldValues?.get(run.pmStart)) ?? (run.fallback || "1");
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check if a run is a math equation run
|
|
53
|
+
*/
|
|
54
|
+
function isMathRun(run) {
|
|
55
|
+
return run.kind === "math";
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if text run is empty (only whitespace or no text)
|
|
59
|
+
*/
|
|
60
|
+
function isEmptyTextRun(run) {
|
|
61
|
+
return !run.text || run.text.replace(/\u00a0/gu, " ").trim().length === 0;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Sum the inline pixel widths of runs after a tab, up to (but not including)
|
|
65
|
+
* the next tab or line break. Measured per-run so widths reserved match what
|
|
66
|
+
* the painter draws even when trailing runs use different fonts/sizes.
|
|
67
|
+
*
|
|
68
|
+
* Floating/anchored images are skipped — the painter lifts them out of the
|
|
69
|
+
* paragraph flow (see `isFloatingImageRun`) and `measureFollowingContentWidth`
|
|
70
|
+
* in the painter already excludes them, so counting their width here would
|
|
71
|
+
* desync measurer and painter on tab advance for paragraphs with a tab
|
|
72
|
+
* preceding a floating image.
|
|
73
|
+
*/
|
|
74
|
+
function isBlockLayoutImageRun(run) {
|
|
75
|
+
if (isFloatingImageRun(run)) return false;
|
|
76
|
+
return run.wrapType === "topAndBottom" || run.displayMode === "block";
|
|
77
|
+
}
|
|
78
|
+
function isSpaceOrTab(char) {
|
|
79
|
+
return char === " " || char === " ";
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
export { DEFAULT_FONT_SIZE, DEFAULT_LINE_HEIGHT_MULTIPLIER, WIDTH_TOLERANCE, fieldMeasureText, isBlockLayoutImageRun, isEmptyTextRun, isFieldRun, isImageRun, isLineBreakRun, isMathRun, isSpaceOrTab, isTabRun, isTextRun, runToFontStyle };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Run } from "../types.js";
|
|
2
|
+
//#region src/layout-engine/measure/paragraphTabs.d.ts
|
|
3
|
+
declare function measureInlineWidthAfterTab(runs: Run[], tabIndex: number, fieldValues?: ReadonlyMap<number, string>): number;
|
|
4
|
+
declare function hasFollowingTabOnLine(runs: Run[], tabIndex: number): boolean;
|
|
5
|
+
declare function hasPriorTabOnLine(runs: Run[], tabIndex: number): boolean;
|
|
6
|
+
declare function canClampTabToRightEdge(alignment: string, currentLineWidth: number, hasPriorTab: boolean, followingWidth: number, availableWidth: number): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Width of the inline content preceding the first `.` in the runs that follow
|
|
9
|
+
* a tab, used to anchor `decimal` tab stops. Mirrors `getTextAfterTab` +
|
|
10
|
+
* decimal-prefix measurement in the painter (`renderParagraph.ts`) so the
|
|
11
|
+
* measurer and painter agree on tab advance for decimal stops.
|
|
12
|
+
*
|
|
13
|
+
* Returns 0 when no decimal separator appears before the next tab / line
|
|
14
|
+
* break — `calculateTabWidth` treats that as "no anchor adjustment".
|
|
15
|
+
*/
|
|
16
|
+
declare function measureDecimalPrefixWidthAfterTab(runs: Run[], tabIndex: number, fieldValues?: ReadonlyMap<number, string>): number;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { canClampTabToRightEdge, hasFollowingTabOnLine, hasPriorTabOnLine, measureDecimalPrefixWidthAfterTab, measureInlineWidthAfterTab };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { inlineImageBoundingBox } from "../../utils/rotationBoundingBox.js";
|
|
2
|
+
import { isFloatingImageRun } from "../types.js";
|
|
3
|
+
import { measureTextWidth } from "./measureProvider.js";
|
|
4
|
+
import { fieldMeasureText, isBlockLayoutImageRun, isFieldRun, isImageRun, isLineBreakRun, isMathRun, isTabRun, isTextRun, runToFontStyle } from "./paragraphMeasureShared.js";
|
|
5
|
+
//#region src/layout-engine/measure/paragraphTabs.ts
|
|
6
|
+
/**
|
|
7
|
+
* Tab measurement on a line: the width of content following a tab, decimal
|
|
8
|
+
* tab prefixes, neighbouring tabs, and right-edge clamping.
|
|
9
|
+
*/
|
|
10
|
+
function measureInlineWidthAfterTab(runs, tabIndex, fieldValues) {
|
|
11
|
+
let width = 0;
|
|
12
|
+
for (let i = tabIndex + 1; i < runs.length; i++) {
|
|
13
|
+
const next = runs[i];
|
|
14
|
+
if (!next || isTabRun(next) || isLineBreakRun(next)) break;
|
|
15
|
+
if (isImageRun(next)) {
|
|
16
|
+
if (isBlockLayoutImageRun(next)) break;
|
|
17
|
+
if (!isFloatingImageRun(next)) width += inlineImageBoundingBox(next).width || 0;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (isTextRun(next)) width += measureTextWidth(next.text || "", runToFontStyle(next));
|
|
21
|
+
else if (isFieldRun(next)) width += measureTextWidth(fieldMeasureText(next, fieldValues), runToFontStyle(next));
|
|
22
|
+
else if (isMathRun(next)) width += measureTextWidth(next.plainText || "[equation]", runToFontStyle(next));
|
|
23
|
+
}
|
|
24
|
+
return width;
|
|
25
|
+
}
|
|
26
|
+
function hasFollowingTabOnLine(runs, tabIndex) {
|
|
27
|
+
for (let i = tabIndex + 1; i < runs.length; i++) {
|
|
28
|
+
const next = runs[i];
|
|
29
|
+
if (!next || isLineBreakRun(next)) break;
|
|
30
|
+
if (isImageRun(next) && isBlockLayoutImageRun(next)) break;
|
|
31
|
+
if (isTabRun(next)) return true;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
function hasPriorTabOnLine(runs, tabIndex) {
|
|
36
|
+
for (let i = tabIndex - 1; i >= 0; i--) {
|
|
37
|
+
const prior = runs[i];
|
|
38
|
+
if (!prior || isLineBreakRun(prior) || isImageRun(prior) && isBlockLayoutImageRun(prior)) break;
|
|
39
|
+
if (isTabRun(prior)) return true;
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
function canClampTabToRightEdge(alignment, currentLineWidth, hasPriorTab, followingWidth, availableWidth) {
|
|
44
|
+
if (alignment === "start" || alignment === "default") return currentLineWidth > .5 && (hasPriorTab || followingWidth <= availableWidth);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Width of the inline content preceding the first `.` in the runs that follow
|
|
49
|
+
* a tab, used to anchor `decimal` tab stops. Mirrors `getTextAfterTab` +
|
|
50
|
+
* decimal-prefix measurement in the painter (`renderParagraph.ts`) so the
|
|
51
|
+
* measurer and painter agree on tab advance for decimal stops.
|
|
52
|
+
*
|
|
53
|
+
* Returns 0 when no decimal separator appears before the next tab / line
|
|
54
|
+
* break — `calculateTabWidth` treats that as "no anchor adjustment".
|
|
55
|
+
*/
|
|
56
|
+
function measureDecimalPrefixWidthAfterTab(runs, tabIndex, fieldValues) {
|
|
57
|
+
let text = "";
|
|
58
|
+
let firstRun;
|
|
59
|
+
for (let i = tabIndex + 1; i < runs.length; i++) {
|
|
60
|
+
const next = runs[i];
|
|
61
|
+
if (!next || isTabRun(next) || isLineBreakRun(next)) break;
|
|
62
|
+
if (isTextRun(next)) {
|
|
63
|
+
text += next.text || "";
|
|
64
|
+
firstRun ??= next;
|
|
65
|
+
} else if (isFieldRun(next)) {
|
|
66
|
+
text += fieldMeasureText(next, fieldValues);
|
|
67
|
+
firstRun ??= next;
|
|
68
|
+
} else if (isMathRun(next)) {
|
|
69
|
+
text += next.plainText || "[equation]";
|
|
70
|
+
firstRun ??= next;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const decimalIndex = text.indexOf(".");
|
|
74
|
+
if (decimalIndex === -1 || !firstRun) return 0;
|
|
75
|
+
return measureTextWidth(text.slice(0, decimalIndex), runToFontStyle(firstRun));
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { canClampTabToRightEdge, hasFollowingTabOnLine, hasPriorTabOnLine, measureDecimalPrefixWidthAfterTab, measureInlineWidthAfterTab };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//#region src/layout-engine/measure/smallCapsCasing.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Casing rules for synthesized `w:smallCaps` glyphs.
|
|
4
|
+
*
|
|
5
|
+
* A face that carries no `smcp`/`c2sc` substitution has no true small-capital
|
|
6
|
+
* glyph, so it is faked: a lowercase letter is drawn as its uppercase form at
|
|
7
|
+
* a smaller point size, on the run's own baseline, at a fixed fraction of the
|
|
8
|
+
* run's declared size — 0.8, an exact ratio observed to repeat across mixed
|
|
9
|
+
* two-size runs at every point size and never round to a half-point `w:sz`
|
|
10
|
+
* step. That is not a canvas or DOM backend's own `font-variant: small-caps`,
|
|
11
|
+
* which synthesizes at its own, uncontrollable, narrower ratio (Blink and
|
|
12
|
+
* WebKit use 0.7).
|
|
13
|
+
*
|
|
14
|
+
* Pure: no canvas, no DOM. Shared by every measurement and paint backend so a
|
|
15
|
+
* run's advances and its glyphs agree on which characters shrink.
|
|
16
|
+
*/
|
|
17
|
+
/** Fraction of the run's declared size a synthesized small capital draws at. */
|
|
18
|
+
declare const SMALL_CAPS_SCALE = 0.8;
|
|
19
|
+
/**
|
|
20
|
+
* Whether `char` is a cased letter in its lowercase form — the class
|
|
21
|
+
* `w:smallCaps` draws as a shrunken, uppercased capital. Digits, punctuation,
|
|
22
|
+
* symbols and already-uppercase letters keep the run's full size; combining
|
|
23
|
+
* `char`'s upper and lower forms this way (rather than comparing to a
|
|
24
|
+
* separate "is uppercase" test) is what correctly leaves caseless scripts
|
|
25
|
+
* (CJK, most punctuation) at full size too, since neither form differs from
|
|
26
|
+
* the character itself there.
|
|
27
|
+
*/
|
|
28
|
+
declare function isSmallCapsLetter(char: string): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Per-code-point small-caps classification for `text`, one entry per code
|
|
31
|
+
* point (iterated the same way `[...text]`/`for...of` does, so it lines up
|
|
32
|
+
* with any other code-point walk of the same string).
|
|
33
|
+
*
|
|
34
|
+
* Whitespace carries no case of its own; a run's space draws at the size of
|
|
35
|
+
* the character immediately before it — the trailing space after a
|
|
36
|
+
* synthesized word is itself synthesized — so a whitespace code point here
|
|
37
|
+
* takes the previous code point's class, and only falls back to full size
|
|
38
|
+
* when it opens the string (nothing to inherit from).
|
|
39
|
+
*/
|
|
40
|
+
declare function smallCapsMask(text: string): boolean[];
|
|
41
|
+
/** A maximal run of `text` drawn at one size: `small` selects which. */
|
|
42
|
+
type SmallCapsSegment = {
|
|
43
|
+
readonly text: string;
|
|
44
|
+
readonly small: boolean;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* `text` split into maximal same-size segments for painting, each already
|
|
48
|
+
* uppercased where `small` — the shrunken capital a `smcp`-less face
|
|
49
|
+
* substitutes for the source lowercase letter. A run with no lowercase letter
|
|
50
|
+
* at all (already-uppercase headings, digits, punctuation) comes back as one
|
|
51
|
+
* `small: false` segment, so a caller can skip the extra painting work its
|
|
52
|
+
* mixed-size runs need.
|
|
53
|
+
*/
|
|
54
|
+
declare function smallCapsSegments(text: string): SmallCapsSegment[];
|
|
55
|
+
//#endregion
|
|
56
|
+
export { SMALL_CAPS_SCALE, SmallCapsSegment, isSmallCapsLetter, smallCapsMask, smallCapsSegments };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
//#region src/layout-engine/measure/smallCapsCasing.ts
|
|
2
|
+
/**
|
|
3
|
+
* Casing rules for synthesized `w:smallCaps` glyphs.
|
|
4
|
+
*
|
|
5
|
+
* A face that carries no `smcp`/`c2sc` substitution has no true small-capital
|
|
6
|
+
* glyph, so it is faked: a lowercase letter is drawn as its uppercase form at
|
|
7
|
+
* a smaller point size, on the run's own baseline, at a fixed fraction of the
|
|
8
|
+
* run's declared size — 0.8, an exact ratio observed to repeat across mixed
|
|
9
|
+
* two-size runs at every point size and never round to a half-point `w:sz`
|
|
10
|
+
* step. That is not a canvas or DOM backend's own `font-variant: small-caps`,
|
|
11
|
+
* which synthesizes at its own, uncontrollable, narrower ratio (Blink and
|
|
12
|
+
* WebKit use 0.7).
|
|
13
|
+
*
|
|
14
|
+
* Pure: no canvas, no DOM. Shared by every measurement and paint backend so a
|
|
15
|
+
* run's advances and its glyphs agree on which characters shrink.
|
|
16
|
+
*/
|
|
17
|
+
/** Fraction of the run's declared size a synthesized small capital draws at. */
|
|
18
|
+
const SMALL_CAPS_SCALE = .8;
|
|
19
|
+
/** Whitespace never gets its own small-caps class; see `smallCapsMask`. */
|
|
20
|
+
const WHITESPACE_PATTERN = /\s/u;
|
|
21
|
+
/**
|
|
22
|
+
* Whether `char` is a cased letter in its lowercase form — the class
|
|
23
|
+
* `w:smallCaps` draws as a shrunken, uppercased capital. Digits, punctuation,
|
|
24
|
+
* symbols and already-uppercase letters keep the run's full size; combining
|
|
25
|
+
* `char`'s upper and lower forms this way (rather than comparing to a
|
|
26
|
+
* separate "is uppercase" test) is what correctly leaves caseless scripts
|
|
27
|
+
* (CJK, most punctuation) at full size too, since neither form differs from
|
|
28
|
+
* the character itself there.
|
|
29
|
+
*/
|
|
30
|
+
function isSmallCapsLetter(char) {
|
|
31
|
+
return char.toLocaleUpperCase() !== char;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Per-code-point small-caps classification for `text`, one entry per code
|
|
35
|
+
* point (iterated the same way `[...text]`/`for...of` does, so it lines up
|
|
36
|
+
* with any other code-point walk of the same string).
|
|
37
|
+
*
|
|
38
|
+
* Whitespace carries no case of its own; a run's space draws at the size of
|
|
39
|
+
* the character immediately before it — the trailing space after a
|
|
40
|
+
* synthesized word is itself synthesized — so a whitespace code point here
|
|
41
|
+
* takes the previous code point's class, and only falls back to full size
|
|
42
|
+
* when it opens the string (nothing to inherit from).
|
|
43
|
+
*/
|
|
44
|
+
function smallCapsMask(text) {
|
|
45
|
+
const mask = [];
|
|
46
|
+
let previous = false;
|
|
47
|
+
for (const char of text) {
|
|
48
|
+
const small = WHITESPACE_PATTERN.test(char) ? previous : isSmallCapsLetter(char);
|
|
49
|
+
mask.push(small);
|
|
50
|
+
previous = small;
|
|
51
|
+
}
|
|
52
|
+
return mask;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* `text` split into maximal same-size segments for painting, each already
|
|
56
|
+
* uppercased where `small` — the shrunken capital a `smcp`-less face
|
|
57
|
+
* substitutes for the source lowercase letter. A run with no lowercase letter
|
|
58
|
+
* at all (already-uppercase headings, digits, punctuation) comes back as one
|
|
59
|
+
* `small: false` segment, so a caller can skip the extra painting work its
|
|
60
|
+
* mixed-size runs need.
|
|
61
|
+
*/
|
|
62
|
+
function smallCapsSegments(text) {
|
|
63
|
+
const mask = smallCapsMask(text);
|
|
64
|
+
const segments = [];
|
|
65
|
+
let current = "";
|
|
66
|
+
let currentSmall;
|
|
67
|
+
let index = 0;
|
|
68
|
+
for (const char of text) {
|
|
69
|
+
const small = mask[index] ?? false;
|
|
70
|
+
if (currentSmall !== void 0 && small !== currentSmall) {
|
|
71
|
+
segments.push({
|
|
72
|
+
text: current,
|
|
73
|
+
small: currentSmall
|
|
74
|
+
});
|
|
75
|
+
current = "";
|
|
76
|
+
}
|
|
77
|
+
current += small ? char.toLocaleUpperCase() : char;
|
|
78
|
+
currentSmall = small;
|
|
79
|
+
index += 1;
|
|
80
|
+
}
|
|
81
|
+
if (current) segments.push({
|
|
82
|
+
text: current,
|
|
83
|
+
small: currentSmall ?? false
|
|
84
|
+
});
|
|
85
|
+
return segments;
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { SMALL_CAPS_SCALE, isSmallCapsLetter, smallCapsMask, smallCapsSegments };
|
|
@@ -51,6 +51,8 @@ type PaginatorOptions = {
|
|
|
51
51
|
firstPageMargins?: PageMargins;
|
|
52
52
|
/** Per-section body margins used on even authored page numbers. */
|
|
53
53
|
sectionEvenPageMargins?: (PageMargins | undefined)[];
|
|
54
|
+
/** Per-section body margins used on the first page of a `w:titlePg` section. */
|
|
55
|
+
sectionFirstPageMargins?: (PageMargins | undefined)[];
|
|
54
56
|
/** Page-number policy for the initial section. */
|
|
55
57
|
pageNumbering?: SectionPageNumbering;
|
|
56
58
|
/** Column configuration (optional). */
|
|
@@ -94,7 +94,11 @@ function createPaginator(options) {
|
|
|
94
94
|
}
|
|
95
95
|
function getPageMargins(pageNumber, logicalPageNumber) {
|
|
96
96
|
const evenMargins = logicalPageNumber % 2 === 0 ? options.sectionEvenPageMargins?.[currentSectionIndex] : void 0;
|
|
97
|
-
const
|
|
97
|
+
const titlePageMargins = currentSectionPageNumber === 1 ? options.sectionFirstPageMargins?.[currentSectionIndex] : void 0;
|
|
98
|
+
let pageMargins;
|
|
99
|
+
if (titlePageMargins) pageMargins = { ...titlePageMargins };
|
|
100
|
+
else if (pageNumber === 1 && options.firstPageMargins) pageMargins = { ...options.firstPageMargins };
|
|
101
|
+
else pageMargins = { ...evenMargins ?? margins };
|
|
98
102
|
if (options.mirrorMargins === true && pageNumber % 2 === 0) return {
|
|
99
103
|
...pageMargins,
|
|
100
104
|
left: pageMargins.right,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ParagraphBlock, ParagraphMeasure } from "./types.js";
|
|
2
|
+
import { createPaginator } from "./paginator.js";
|
|
3
|
+
//#region src/layout-engine/paragraphLayout.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Layout a paragraph block onto pages.
|
|
6
|
+
*
|
|
7
|
+
* When `footnoteHeightById` is provided, each line carrying a footnote
|
|
8
|
+
* ref additionally reserves space on its host page for the fn's
|
|
9
|
+
* content. Pagination decisions include only the reservation growth
|
|
10
|
+
* beyond any retry floor, so a line cannot land on a page that lacks
|
|
11
|
+
* room for both body and note content.
|
|
12
|
+
*/
|
|
13
|
+
type LayoutParagraphOptions = {
|
|
14
|
+
block: ParagraphBlock;
|
|
15
|
+
measure: ParagraphMeasure;
|
|
16
|
+
paginator: ReturnType<typeof createPaginator>;
|
|
17
|
+
contentWidth: number;
|
|
18
|
+
footnoteHeightById: Map<number, number> | undefined;
|
|
19
|
+
suppressSpaceBefore: boolean;
|
|
20
|
+
};
|
|
21
|
+
declare function layoutParagraph({ block, measure, paginator, contentWidth, footnoteHeightById, suppressSpaceBefore }: LayoutParagraphOptions): void;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { layoutParagraph };
|