@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
|
@@ -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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ColumnLayout, FOOTNOTE_SEPARATOR_HEIGHT, Fragment, Page, PageHeaderFooterRefs, PageMargins } from "./types.js";
|
|
1
|
+
import { ColumnLayout, FOOTNOTE_SEPARATOR_HEIGHT, Fragment, Page, PageHeaderFooterRefs, PageMargins, SectionPageNumbering } from "./types.js";
|
|
2
2
|
//#region src/layout-engine/paginator.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Current state of a page being laid out.
|
|
@@ -45,8 +45,10 @@ type PaginatorOptions = {
|
|
|
45
45
|
* first-page header) vs. its body pages. Pages 2+ use `margins`.
|
|
46
46
|
*/
|
|
47
47
|
firstPageMargins?: PageMargins;
|
|
48
|
-
/** Per-section body margins used on even
|
|
48
|
+
/** Per-section body margins used on even authored page numbers. */
|
|
49
49
|
sectionEvenPageMargins?: (PageMargins | undefined)[];
|
|
50
|
+
/** Page-number policy for the initial section. */
|
|
51
|
+
pageNumbering?: SectionPageNumbering;
|
|
50
52
|
/** Column configuration (optional). */
|
|
51
53
|
columns?: ColumnLayout;
|
|
52
54
|
/** Per-page footnote reserved heights (pageNumber → height in pixels). */
|
|
@@ -114,7 +116,7 @@ declare function createPaginator(options: PaginatorOptions): {
|
|
|
114
116
|
h: number;
|
|
115
117
|
}, newMargins?: PageMargins, applyImmediately?: boolean) => void;
|
|
116
118
|
/** Mark the next created page as the first page of a new section. */
|
|
117
|
-
startSection: (sectionIndex: number) => void;
|
|
119
|
+
startSection: (sectionIndex: number, pageNumbering?: SectionPageNumbering) => void;
|
|
118
120
|
};
|
|
119
121
|
type Paginator = ReturnType<typeof createPaginator>;
|
|
120
122
|
//#endregion
|
|
@@ -35,6 +35,9 @@ function createPaginator(options) {
|
|
|
35
35
|
let pendingMargins;
|
|
36
36
|
let currentSectionIndex = 0;
|
|
37
37
|
let currentSectionPageNumber = 0;
|
|
38
|
+
let currentPageNumbering = options.pageNumbering ?? { type: "continue" };
|
|
39
|
+
let nextLogicalPageNumber = currentPageNumbering.type === "restart" ? currentPageNumbering.start : 1;
|
|
40
|
+
let sectionStartPending = true;
|
|
38
41
|
const pages = [];
|
|
39
42
|
const states = [];
|
|
40
43
|
function getContentBottom() {
|
|
@@ -48,7 +51,7 @@ function createPaginator(options) {
|
|
|
48
51
|
}
|
|
49
52
|
function currentPageUsesActiveLayout(state) {
|
|
50
53
|
if (pendingPageSize || pendingMargins) return false;
|
|
51
|
-
return arePageSizesEqual(state.page.size, pageSize) && areMarginsEqual(state.page.margins, getPageMargins(state.page.number, state.page.
|
|
54
|
+
return arePageSizesEqual(state.page.size, pageSize) && areMarginsEqual(state.page.margins, getPageMargins(state.page.number, state.page.logicalNumber));
|
|
52
55
|
}
|
|
53
56
|
if (getContentHeight() <= 0) panic("Paginator: page size and margins yield no content area");
|
|
54
57
|
let columnWidths = calculateColumnWidths(pageSize.w, margins.left, margins.right, columns);
|
|
@@ -63,8 +66,8 @@ function createPaginator(options) {
|
|
|
63
66
|
if (getContentHeight() <= 0) panic("Paginator: section page size and margins yield no content area");
|
|
64
67
|
recalculateColumnWidths();
|
|
65
68
|
}
|
|
66
|
-
function getPageMargins(pageNumber,
|
|
67
|
-
const evenMargins =
|
|
69
|
+
function getPageMargins(pageNumber, logicalPageNumber) {
|
|
70
|
+
const evenMargins = logicalPageNumber % 2 === 0 ? options.sectionEvenPageMargins?.[currentSectionIndex] : void 0;
|
|
68
71
|
const pageMargins = pageNumber === 1 && options.firstPageMargins ? { ...options.firstPageMargins } : { ...evenMargins ?? margins };
|
|
69
72
|
if (options.mirrorMargins === true && pageNumber % 2 === 0) return {
|
|
70
73
|
...pageMargins,
|
|
@@ -79,7 +82,7 @@ function createPaginator(options) {
|
|
|
79
82
|
* Get X position for a given column index.
|
|
80
83
|
*/
|
|
81
84
|
function getColumnX(columnIndex) {
|
|
82
|
-
let x = states.at(-1)?.page.margins.left ?? getPageMargins(1,
|
|
85
|
+
let x = states.at(-1)?.page.margins.left ?? getPageMargins(1, nextLogicalPageNumber).left;
|
|
83
86
|
for (let index = 0; index < columnIndex; index++) x += (columnWidths[index] ?? columnWidths[0] ?? 0) + gapAfterColumn(columns, index);
|
|
84
87
|
return x;
|
|
85
88
|
}
|
|
@@ -89,14 +92,19 @@ function createPaginator(options) {
|
|
|
89
92
|
function createNewPage() {
|
|
90
93
|
if (pendingPageSize || pendingMargins) applyPendingLayout();
|
|
91
94
|
const pageNumber = pages.length + 1;
|
|
95
|
+
const logicalNumber = nextLogicalPageNumber;
|
|
96
|
+
nextLogicalPageNumber += 1;
|
|
97
|
+
sectionStartPending = false;
|
|
92
98
|
currentSectionPageNumber += 1;
|
|
93
|
-
const pageMargins = getPageMargins(pageNumber,
|
|
99
|
+
const pageMargins = getPageMargins(pageNumber, logicalNumber);
|
|
94
100
|
const topMargin = pageMargins.top;
|
|
95
101
|
const contentBottom = pageSize.h - pageMargins.bottom;
|
|
96
102
|
const footnoteHeight = options.footnoteReservedHeights?.get(pageNumber) ?? 0;
|
|
97
103
|
const pageContentBottom = contentBottom - footnoteHeight;
|
|
98
104
|
const page = {
|
|
99
105
|
number: pageNumber,
|
|
106
|
+
logicalNumber,
|
|
107
|
+
...currentPageNumbering.format === void 0 ? {} : { logicalNumberFormat: currentPageNumbering.format },
|
|
100
108
|
fragments: [],
|
|
101
109
|
margins: pageMargins,
|
|
102
110
|
size: { ...pageSize },
|
|
@@ -236,12 +244,12 @@ function createPaginator(options) {
|
|
|
236
244
|
*/
|
|
237
245
|
function forcePageBreak(breakOptions = {}) {
|
|
238
246
|
const current = states.at(-1);
|
|
239
|
-
if (breakOptions.coalesceBlankPage && current && current.page.fragments.length === 0 && current.cursorY === current.topMargin
|
|
247
|
+
if (breakOptions.coalesceBlankPage && current && current.page.fragments.length === 0 && current.cursorY === current.topMargin) {
|
|
240
248
|
if (current.page.sectionIndex !== currentSectionIndex) {
|
|
241
|
-
|
|
242
|
-
|
|
249
|
+
retargetCurrentBlankPage();
|
|
250
|
+
return current;
|
|
243
251
|
}
|
|
244
|
-
return current;
|
|
252
|
+
if (currentPageUsesActiveLayout(current)) return current;
|
|
245
253
|
}
|
|
246
254
|
return createNewPage();
|
|
247
255
|
}
|
|
@@ -249,7 +257,8 @@ function createPaginator(options) {
|
|
|
249
257
|
const current = states.at(-1);
|
|
250
258
|
if (!current || current.page.fragments.length > 0 || current.cursorY !== current.topMargin) return false;
|
|
251
259
|
if (pendingPageSize || pendingMargins) applyPendingLayout();
|
|
252
|
-
|
|
260
|
+
retargetSectionMetadata(current.page);
|
|
261
|
+
const pageMargins = getPageMargins(current.page.number, current.page.logicalNumber);
|
|
253
262
|
const topMargin = pageMargins.top;
|
|
254
263
|
const rawContentBottom = pageSize.h - pageMargins.bottom;
|
|
255
264
|
const footnoteHeight = options.footnoteReservedHeights?.get(current.page.number) ?? 0;
|
|
@@ -267,8 +276,6 @@ function createPaginator(options) {
|
|
|
267
276
|
current.contentBottom = rawContentBottom - footnoteHeight;
|
|
268
277
|
current.trailingSpacing = 0;
|
|
269
278
|
columnRegionTop = topMargin;
|
|
270
|
-
currentSectionPageNumber = 1;
|
|
271
|
-
applySectionMetadata(current.page);
|
|
272
279
|
return true;
|
|
273
280
|
}
|
|
274
281
|
/**
|
|
@@ -310,9 +317,23 @@ function createPaginator(options) {
|
|
|
310
317
|
pendingPageSize = void 0;
|
|
311
318
|
pendingMargins = void 0;
|
|
312
319
|
}
|
|
313
|
-
function startSection(sectionIndex) {
|
|
320
|
+
function startSection(sectionIndex, pageNumbering = { type: "continue" }) {
|
|
314
321
|
currentSectionIndex = sectionIndex;
|
|
315
322
|
currentSectionPageNumber = 0;
|
|
323
|
+
currentPageNumbering = pageNumbering;
|
|
324
|
+
sectionStartPending = true;
|
|
325
|
+
if (pageNumbering.type === "restart") nextLogicalPageNumber = pageNumbering.start;
|
|
326
|
+
}
|
|
327
|
+
function retargetSectionMetadata(page) {
|
|
328
|
+
currentSectionPageNumber = 1;
|
|
329
|
+
if (sectionStartPending && currentPageNumbering.type === "restart") {
|
|
330
|
+
page.logicalNumber = currentPageNumbering.start;
|
|
331
|
+
nextLogicalPageNumber = currentPageNumbering.start + 1;
|
|
332
|
+
}
|
|
333
|
+
sectionStartPending = false;
|
|
334
|
+
if (currentPageNumbering.format === void 0) delete page.logicalNumberFormat;
|
|
335
|
+
else page.logicalNumberFormat = currentPageNumbering.format;
|
|
336
|
+
applySectionMetadata(page);
|
|
316
337
|
}
|
|
317
338
|
function applySectionMetadata(page) {
|
|
318
339
|
page.sectionIndex = currentSectionIndex;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OutlineStyleAttr } from "../types/documentEnumValues.js";
|
|
2
2
|
import { ImagePosition, ImageWrap, SdtProperties, SdtType, ShapeTextBody, TableCellFormatting, TableWidthType } from "@stll/docx-core/model";
|
|
3
3
|
declare namespace types_d_exports {
|
|
4
|
-
export { 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 };
|
|
4
|
+
export { 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 };
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Unique identifier for a block in the document.
|
|
@@ -46,6 +46,14 @@ type RunFormatting = {
|
|
|
46
46
|
* does NOT do and is why this slot has to reach layout at all.
|
|
47
47
|
*/
|
|
48
48
|
complexScriptFontFamily?: string;
|
|
49
|
+
/** Independent complex-script size (`w:szCs`), in points. */
|
|
50
|
+
complexScriptFontSize?: number;
|
|
51
|
+
/** Independent complex-script weight (`w:bCs`). */
|
|
52
|
+
complexScriptBold?: boolean;
|
|
53
|
+
/** Independent complex-script slant (`w:iCs`). */
|
|
54
|
+
complexScriptItalic?: boolean;
|
|
55
|
+
/** Force the complex-script formatting slot for every character (`w:cs`). */
|
|
56
|
+
forceComplexScript?: boolean;
|
|
49
57
|
/** Run language metadata resolved from `w:lang`. */
|
|
50
58
|
language?: {
|
|
51
59
|
val?: string;
|
|
@@ -119,6 +127,7 @@ type RunFormatting = {
|
|
|
119
127
|
/** Groups a suggestion's runs for accept/reject and scroll-to. */
|
|
120
128
|
suggestionId?: string;
|
|
121
129
|
};
|
|
130
|
+
type ListMarkerFormatting = Pick<RunFormatting, "fontFamily" | "eastAsiaFontFamily" | "complexScriptFontFamily" | "fontSize" | "complexScriptFontSize" | "bold" | "complexScriptBold" | "italic" | "complexScriptItalic" | "rtl" | "forceComplexScript">;
|
|
122
131
|
/**
|
|
123
132
|
* Hyperlink information for a run.
|
|
124
133
|
*/
|
|
@@ -453,15 +462,14 @@ type ParagraphAttrs = {
|
|
|
453
462
|
listMarker?: string;
|
|
454
463
|
listIsBullet?: boolean;
|
|
455
464
|
listMarkerHidden?: boolean;
|
|
456
|
-
|
|
457
|
-
|
|
465
|
+
/** Canonical numbering-level marker typography, resolved for layout. */
|
|
466
|
+
listMarkerFormatting?: ListMarkerFormatting;
|
|
458
467
|
/**
|
|
459
468
|
* Effective paragraph-mark size used only to measure a visible list
|
|
460
469
|
* paragraph's final line. Word lets the inherited complex-script size raise
|
|
461
470
|
* that line box without enlarging the marker or Western text glyphs.
|
|
462
471
|
*/
|
|
463
472
|
listParagraphMarkFontSize?: number;
|
|
464
|
-
listMarkerBold?: boolean;
|
|
465
473
|
/** Horizontal alignment of the marker around the paragraph's list anchor. */
|
|
466
474
|
listMarkerAlignment?: "left" | "center" | "right";
|
|
467
475
|
/**
|
|
@@ -689,9 +697,20 @@ type SectionBreakBlock = {
|
|
|
689
697
|
orientation?: "portrait" | "landscape";
|
|
690
698
|
margins?: PageMargins;
|
|
691
699
|
columns?: ColumnLayout;
|
|
700
|
+
/** Authored page-number continuation or restart policy for the section ending here. */
|
|
701
|
+
pageNumbering?: SectionPageNumbering;
|
|
692
702
|
/** Line pitch authored by the section properties that end at this boundary, in twips. */
|
|
693
703
|
documentGridLinePitchTwips?: number;
|
|
694
704
|
};
|
|
705
|
+
/** Normalized section page-number policy. An omitted OOXML start continues numbering. */
|
|
706
|
+
type SectionPageNumbering = {
|
|
707
|
+
type: "continue";
|
|
708
|
+
format?: string;
|
|
709
|
+
} | {
|
|
710
|
+
type: "restart";
|
|
711
|
+
start: number;
|
|
712
|
+
format?: string;
|
|
713
|
+
};
|
|
695
714
|
type PageHeaderFooterRefs = {
|
|
696
715
|
titlePg?: boolean;
|
|
697
716
|
evenAndOddHeaders?: boolean;
|
|
@@ -1057,8 +1076,12 @@ type PageMargins = {
|
|
|
1057
1076
|
* A rendered page containing positioned fragments.
|
|
1058
1077
|
*/
|
|
1059
1078
|
type Page = {
|
|
1060
|
-
/**
|
|
1079
|
+
/** Physical page number (1-indexed), used for navigation and page counts. */
|
|
1061
1080
|
number: number;
|
|
1081
|
+
/** Authored page number shown by PAGE fields. */
|
|
1082
|
+
logicalNumber: number;
|
|
1083
|
+
/** OOXML number format for this page's section. */
|
|
1084
|
+
logicalNumberFormat?: string;
|
|
1062
1085
|
/** Fragments positioned on this page. */
|
|
1063
1086
|
fragments: Fragment[];
|
|
1064
1087
|
/** Page margins. */
|
|
@@ -1167,8 +1190,10 @@ type LayoutOptions = {
|
|
|
1167
1190
|
* same extension.
|
|
1168
1191
|
*/
|
|
1169
1192
|
firstPageMargins?: PageMargins;
|
|
1170
|
-
/** Per-section body margins used on even
|
|
1193
|
+
/** Per-section body margins used on even authored page numbers. */
|
|
1171
1194
|
sectionEvenPageMargins?: (PageMargins | undefined)[];
|
|
1195
|
+
/** Page-number policy for the initial section. */
|
|
1196
|
+
pageNumbering?: SectionPageNumbering;
|
|
1172
1197
|
/** Body-level final section page size. */
|
|
1173
1198
|
finalPageSize?: {
|
|
1174
1199
|
w: number;
|
|
@@ -1178,6 +1203,8 @@ type LayoutOptions = {
|
|
|
1178
1203
|
finalMargins?: PageMargins;
|
|
1179
1204
|
/** Body-level final section column configuration. */
|
|
1180
1205
|
finalColumns?: ColumnLayout;
|
|
1206
|
+
/** Body-level final section page-number policy. */
|
|
1207
|
+
finalPageNumbering?: SectionPageNumbering;
|
|
1181
1208
|
/** Column configuration. */
|
|
1182
1209
|
columns?: ColumnLayout;
|
|
1183
1210
|
/** Gap between rendered pages (for UI). */
|
|
@@ -1353,4 +1380,4 @@ declare function tableColumnsArePinned(table: TableBlock): boolean;
|
|
|
1353
1380
|
/** Return the leading visual offset for a row with omitted grid columns. */
|
|
1354
1381
|
declare const getTableRowLeadingWidth: (row: TableRow, columnWidths: readonly number[]) => number;
|
|
1355
1382
|
//#endregion
|
|
1356
|
-
export { 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, types_d_exports };
|
|
1383
|
+
export { 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, types_d_exports };
|
|
@@ -81,7 +81,8 @@ var LayoutPainter = class {
|
|
|
81
81
|
for (const i_item of pages) {
|
|
82
82
|
const page = i_item;
|
|
83
83
|
const context = {
|
|
84
|
-
pageNumber: page.
|
|
84
|
+
pageNumber: page.logicalNumber,
|
|
85
|
+
...page.logicalNumberFormat === void 0 ? {} : { pageNumberFormat: page.logicalNumberFormat },
|
|
85
86
|
totalPages: this.totalPages,
|
|
86
87
|
section: "body"
|
|
87
88
|
};
|
|
@@ -601,6 +601,7 @@ function renderFootnoteContent(footnote, contentWidth, doc, context) {
|
|
|
601
601
|
wrapper.style.height = `${content.height}px`;
|
|
602
602
|
const renderContext = {
|
|
603
603
|
pageNumber: context?.pageNumber ?? 0,
|
|
604
|
+
...context?.pageNumberFormat === void 0 ? {} : { pageNumberFormat: context.pageNumberFormat },
|
|
604
605
|
totalPages: context?.totalPages ?? 0,
|
|
605
606
|
section: context?.section ?? "body",
|
|
606
607
|
contentWidth
|
|
@@ -1133,8 +1134,7 @@ function applySectionHeaderFooterOptions(page, pageOptions, options) {
|
|
|
1133
1134
|
if (!refs) return false;
|
|
1134
1135
|
const isFirstSectionPage = page.sectionPageNumber === 1;
|
|
1135
1136
|
const useFirst = refs.titlePg === true && isFirstSectionPage;
|
|
1136
|
-
const
|
|
1137
|
-
const useEven = refs.evenAndOddHeaders === true && sectionPageNumber % 2 === 0;
|
|
1137
|
+
const useEven = refs.evenAndOddHeaders === true && page.logicalNumber % 2 === 0;
|
|
1138
1138
|
const headerRId = (() => {
|
|
1139
1139
|
if (useFirst) return refs.headerFirst;
|
|
1140
1140
|
if (useEven) return refs.headerEven;
|
|
@@ -1176,7 +1176,8 @@ function sectionPagesContext(page, counts) {
|
|
|
1176
1176
|
*/
|
|
1177
1177
|
function buildPageRenderArgs(page, totalPages, options) {
|
|
1178
1178
|
const context = {
|
|
1179
|
-
pageNumber: page.
|
|
1179
|
+
pageNumber: page.logicalNumber,
|
|
1180
|
+
...page.logicalNumberFormat === void 0 ? {} : { pageNumberFormat: page.logicalNumberFormat },
|
|
1180
1181
|
totalPages,
|
|
1181
1182
|
section: "body",
|
|
1182
1183
|
...options.bookmarkPages ? { bookmarkPages: options.bookmarkPages } : {},
|
|
@@ -1224,6 +1225,7 @@ function computePageFingerprintInternal(page, blockLookup, options) {
|
|
|
1224
1225
|
parts.push(`m:${pageMarginsFingerprint(page.margins)}`);
|
|
1225
1226
|
if (page.authoredMargins) parts.push(`am:${pageMarginsFingerprint(page.authoredMargins)}`);
|
|
1226
1227
|
parts.push(`n:${page.number}`);
|
|
1228
|
+
parts.push(`ln:${page.logicalNumber},${page.logicalNumberFormat ?? ""}`);
|
|
1227
1229
|
if (page.sectionIndex !== void 0) parts.push(`si:${page.sectionIndex}`);
|
|
1228
1230
|
if (page.sectionPageNumber !== void 0) parts.push(`sp:${page.sectionPageNumber}`);
|
|
1229
1231
|
if (page.headerFooterRefs) parts.push(`hf:${JSON.stringify(page.headerFooterRefs)}`);
|
|
@@ -1334,6 +1336,10 @@ function runContentKey(run) {
|
|
|
1334
1336
|
if (run.highlight) parts.push(`hi:${run.highlight}`);
|
|
1335
1337
|
if (run.fontFamily) parts.push(`ff:${run.fontFamily}`);
|
|
1336
1338
|
if (run.complexScriptFontFamily) parts.push(`cs:${run.complexScriptFontFamily}`);
|
|
1339
|
+
if (run.complexScriptFontSize !== void 0) parts.push(`cs-size:${run.complexScriptFontSize}`);
|
|
1340
|
+
if (run.complexScriptBold !== void 0) parts.push(`cs-bold:${run.complexScriptBold}`);
|
|
1341
|
+
if (run.complexScriptItalic !== void 0) parts.push(`cs-italic:${run.complexScriptItalic}`);
|
|
1342
|
+
if (run.forceComplexScript !== void 0) parts.push(`cs-force:${run.forceComplexScript}`);
|
|
1337
1343
|
if (run.eastAsiaFontFamily) parts.push(`ea:${run.eastAsiaFontFamily}`);
|
|
1338
1344
|
if (run.fontSize !== void 0) parts.push(`fs:${run.fontSize}`);
|
|
1339
1345
|
if (run.letterSpacing !== void 0) parts.push(`ls:${run.letterSpacing}`);
|