@stll/folio-core 0.47.7 → 0.49.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/minimal-replacement.d.ts +64 -0
- package/dist/ai-edits/minimal-replacement.js +282 -0
- package/dist/controller/fontReadiness.js +3 -3
- package/dist/controller/hyphenationReadiness.d.ts +19 -0
- package/dist/controller/hyphenationReadiness.js +47 -0
- package/dist/controller/layoutPipeline.d.ts +3 -0
- package/dist/controller/layoutPipeline.js +70 -18
- package/dist/display-list/build/buildDisplayList.js +39 -12
- package/dist/display-list/build/pageFurniture.d.ts +7 -1
- package/dist/display-list/build/pageFurniture.js +21 -8
- package/dist/display-list/build/paragraphPrimitives.js +68 -11
- package/dist/display-list/build/tablePrimitives.js +10 -6
- 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.js +0 -1
- package/dist/docx/attributeRemainder.js +10 -2
- package/dist/docx/blockContentParser.d.ts +2 -0
- package/dist/docx/blockContentParser.js +79 -64
- package/dist/docx/bulletMarkers.d.ts +18 -2
- package/dist/docx/bulletMarkers.js +27 -2
- package/dist/docx/commentParser.d.ts +2 -1
- package/dist/docx/commentParser.js +57 -45
- package/dist/docx/containerChildren.d.ts +21 -8
- package/dist/docx/containerChildren.js +39 -9
- package/dist/docx/documentParser.d.ts +5 -1
- package/dist/docx/documentParser.js +8 -5
- package/dist/docx/documentSectionFacts.d.ts +22 -0
- package/dist/docx/documentSectionFacts.js +43 -0
- 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/fieldParser.d.ts +8 -1
- package/dist/docx/fieldParser.js +47 -3
- package/dist/docx/fontTableParser.js +34 -27
- package/dist/docx/footnoteParser.d.ts +3 -2
- package/dist/docx/footnoteParser.js +15 -12
- package/dist/docx/groupDrawingParser.d.ts +9 -2
- package/dist/docx/groupDrawingParser.js +125 -37
- package/dist/docx/headerFooterParser.d.ts +7 -2
- package/dist/docx/headerFooterParser.js +15 -5
- package/dist/docx/hyperlinkParser.d.ts +48 -36
- package/dist/docx/hyperlinkParser.js +97 -82
- package/dist/docx/numberingParser.js +108 -84
- 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.d.ts +5 -1
- package/dist/docx/paragraphParser.js +468 -365
- package/dist/docx/paragraphProperties.js +123 -109
- package/dist/docx/paragraphPropertySource.d.ts +6 -1
- package/dist/docx/paragraphPropertySource.js +9 -1
- package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +143 -10
- package/dist/docx/parser.d.ts +7 -1
- package/dist/docx/parser.js +33 -16
- package/dist/docx/previewBudget.d.ts +55 -33
- package/dist/docx/previewBudget.js +59 -65
- package/dist/docx/rezip.js +41 -58
- package/dist/docx/runParser.d.ts +4 -1
- package/dist/docx/runParser.js +182 -184
- package/dist/docx/sdtProperties.js +87 -84
- package/dist/docx/sectionParser.js +169 -160
- 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 +47 -42
- package/dist/docx/serializer/runSerializer.d.ts +5 -1
- package/dist/docx/serializer/runSerializer.js +4 -3
- package/dist/docx/serializer/settingsSerializer.js +19 -1
- package/dist/docx/settingsParser.js +8 -0
- package/dist/docx/shapeAlternateContent.d.ts +25 -0
- package/dist/docx/shapeAlternateContent.js +52 -0
- package/dist/docx/streamingXmlParser.d.ts +6 -2
- package/dist/docx/streamingXmlParser.js +12 -7
- package/dist/docx/styleParser.js +34 -8
- package/dist/docx/tableParser.d.ts +21 -12
- package/dist/docx/tableParser.js +518 -441
- package/dist/docx/textBoxParser.d.ts +18 -5
- package/dist/docx/textBoxParser.js +12 -6
- package/dist/docx/verbatimCapture.d.ts +10 -8
- package/dist/docx/verbatimCapture.js +45 -2
- package/dist/docx/vmlImageParser.d.ts +15 -13
- package/dist/docx/vmlImageParser.js +75 -60
- package/dist/docx/vmlPreview.d.ts +3 -3
- package/dist/docx/vmlPreview.js +3 -4
- package/dist/docx/xmlNamespaceContext.d.ts +9 -0
- package/dist/docx/xmlNamespaceContext.js +54 -0
- package/dist/docx/xmlParser.d.ts +6 -3
- package/dist/docx/xmlParser.js +11 -41
- package/dist/docx/xmlResourceLimits.d.ts +2 -1
- package/dist/docx/xmlResourceLimits.js +4 -1
- package/dist/fonts/headlessMeasure.js +0 -0
- package/dist/headless-layout.d.ts +11 -2
- package/dist/headless-layout.js +153 -107
- package/dist/internal/headlessRevisionResolution.js +50 -13
- package/dist/internal/paragraphFormattingSerialization.js +3 -3
- package/dist/layout-bridge/convert/endnoteLayout.d.ts +65 -0
- package/dist/layout-bridge/convert/endnoteLayout.js +227 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +19 -3
- package/dist/layout-bridge/convert/footnoteLayout.js +40 -31
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -7
- package/dist/layout-bridge/convert/headerFooterLayout.js +5 -20
- package/dist/layout-bridge/convert/paragraphMarkFormatting.d.ts +10 -0
- package/dist/layout-bridge/convert/paragraphMarkFormatting.js +59 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +29 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +284 -39
- package/dist/layout-bridge/engine/hitTest.js +5 -3
- package/dist/layout-bridge/engine/selectionRects.js +5 -3
- package/dist/layout-engine/anchorLayoutInCellCompatibility.d.ts +10 -0
- package/dist/layout-engine/anchorLayoutInCellCompatibility.js +22 -0
- package/dist/layout-engine/index.d.ts +2 -2
- package/dist/layout-engine/index.js +102 -14
- package/dist/layout-engine/justificationCompatibility.d.ts +1 -1
- package/dist/layout-engine/justificationCompatibility.js +9 -5
- package/dist/layout-engine/keep-together.d.ts +15 -6
- package/dist/layout-engine/keep-together.js +43 -16
- package/dist/layout-engine/layoutInstrumentation.d.ts +8 -2
- package/dist/layout-engine/layoutInstrumentation.js +8 -1
- package/dist/layout-engine/measure/advanceComposition.js +50 -7
- package/dist/layout-engine/measure/hyphenationDictionaries.d.ts +74 -0
- package/dist/layout-engine/measure/hyphenationDictionaries.js +138 -0
- package/dist/layout-engine/measure/hyphenationPreload.d.ts +11 -0
- package/dist/layout-engine/measure/hyphenationPreload.js +24 -0
- package/dist/layout-engine/measure/lineBreakProvider.d.ts +12 -2
- package/dist/layout-engine/measure/lineBreakProvider.js +30 -30
- package/dist/layout-engine/measure/lineBreaks.d.ts +6 -1
- package/dist/layout-engine/measure/lineBreaks.js +10 -3
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +9 -6
- package/dist/layout-engine/measure/listMarkerWidth.js +20 -22
- package/dist/layout-engine/measure/measureBlocks.js +46 -10
- package/dist/layout-engine/measure/measureContainer.js +51 -8
- package/dist/layout-engine/measure/measureHelpers.d.ts +15 -3
- package/dist/layout-engine/measure/measureHelpers.js +34 -8
- package/dist/layout-engine/measure/measureParagraph.js +143 -101
- package/dist/layout-engine/measure/measureTypes.d.ts +5 -0
- package/dist/layout-engine/measure/smallCapsCasing.d.ts +56 -0
- package/dist/layout-engine/measure/smallCapsCasing.js +88 -0
- package/dist/layout-engine/measure/tabCalculator.d.ts +2 -0
- package/dist/layout-engine/measure/tabCalculator.js +2 -1
- package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
- package/dist/layout-engine/measure/tableCellFloating.js +51 -19
- package/dist/layout-engine/measure/tableCellGrid.d.ts +28 -3
- package/dist/layout-engine/measure/tableCellGrid.js +45 -5
- package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +2 -1
- package/dist/layout-engine/noteAreaFlow.d.ts +19 -0
- package/dist/layout-engine/noteAreaFlow.js +83 -0
- package/dist/layout-engine/paginator.d.ts +12 -1
- package/dist/layout-engine/paginator.js +18 -2
- package/dist/layout-engine/paragraphSpacing.d.ts +4 -2
- package/dist/layout-engine/paragraphSpacing.js +2 -1
- package/dist/layout-engine/tableRowBreak.d.ts +8 -1
- package/dist/layout-engine/tableRowBreak.js +25 -2
- package/dist/layout-engine/types.d.ts +108 -3
- package/dist/layout-engine/types.js +96 -1
- package/dist/layout-painter/index.d.ts +3 -0
- package/dist/layout-painter/renderPage.js +32 -83
- package/dist/layout-painter/renderParagraph.d.ts +6 -1
- package/dist/layout-painter/renderParagraph.js +75 -26
- package/dist/layout-painter/renderTable.js +26 -13
- package/dist/layout-painter/renderTextBox.d.ts +12 -2
- package/dist/layout-painter/renderTextBox.js +26 -2
- package/dist/prosemirror/alternateContentAttrs.d.ts +9 -0
- package/dist/prosemirror/alternateContentAttrs.js +35 -0
- package/dist/prosemirror/attrs/index.d.ts +9 -9
- package/dist/prosemirror/attrs/index.js +133 -11
- 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 +54 -23
- package/dist/prosemirror/conversion/markInterner.d.ts +21 -0
- package/dist/prosemirror/conversion/markInterner.js +90 -0
- package/dist/prosemirror/conversion/toProseDoc.js +117 -58
- package/dist/prosemirror/extensions/core/DocExtension.js +2 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +7 -7
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +7 -7
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +6 -2
- package/dist/prosemirror/extensions/marks/markUtils.js +39 -51
- 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 +5 -1
- package/dist/prosemirror/listMarker.d.ts +1 -0
- package/dist/prosemirror/listMarker.js +4 -2
- package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
- package/dist/prosemirror/listRenderingAttrs.js +3 -0
- 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 +50 -6
- package/dist/prosemirror/textBoxHostParagraph.d.ts +13 -0
- package/dist/prosemirror/textBoxHostParagraph.js +21 -0
- package/dist/prosemirror/validation.js +91 -80
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/createDocument.js +10 -1
- package/dist/utils/scriptSegments.d.ts +33 -4
- package/dist/utils/scriptSegments.js +39 -6
- package/dist/utils/textFormattingMerge.d.ts +17 -3
- package/dist/utils/textFormattingMerge.js +18 -12
- package/dist/utils/trailingText.d.ts +22 -0
- package/dist/utils/trailingText.js +32 -0
- package/package.json +2 -2
- package/dist/layout-engine/justifiedLineFit.d.ts +0 -7
- package/dist/layout-engine/justifiedLineFit.js +0 -6
|
@@ -4,7 +4,7 @@ import { buildRunFontStyle } from "../../layout-engine/measure/measureHelpers.js
|
|
|
4
4
|
import { measureParagraph } from "../../layout-engine/measure/measureParagraph.js";
|
|
5
5
|
import { measureRun } from "../../layout-engine/measure/measureProvider.js";
|
|
6
6
|
import { buildTableCellFloatingZones, getTableCellContentWidth, getTableCellFloatingImages } from "../../layout-engine/measure/tableCellFloating.js";
|
|
7
|
-
import { buildTableCellGrid, buildTableCellPlacements } from "../../layout-engine/measure/tableCellGrid.js";
|
|
7
|
+
import { buildTableCellGrid, buildTableCellPlacements, getTableCellSpacingInsetsY } from "../../layout-engine/measure/tableCellGrid.js";
|
|
8
8
|
import { resolveTableCellPadding } from "../../layout-engine/types.js";
|
|
9
9
|
import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
|
|
10
10
|
import { resolvePhysicalParagraphInlineLayout } from "../../utils/paragraphInlineLayout.js";
|
|
@@ -312,7 +312,8 @@ function selectionToRects(layout, blocks, measures, from, to) {
|
|
|
312
312
|
cellPlacements = buildTableCellPlacements({
|
|
313
313
|
grid: buildTableCellGrid(tableBlock.rows, tableMeasure.columnWidths.length),
|
|
314
314
|
columnWidths: tableMeasure.columnWidths,
|
|
315
|
-
bidi: tableBlock.bidi === true
|
|
315
|
+
bidi: tableBlock.bidi === true,
|
|
316
|
+
cellSpacing: tableBlock.cellSpacing
|
|
316
317
|
});
|
|
317
318
|
tableCellPlacements.set(tableBlock, cellPlacements);
|
|
318
319
|
}
|
|
@@ -333,7 +334,8 @@ function selectionToRects(layout, blocks, measures, from, to) {
|
|
|
333
334
|
const contentWidth = getTableCellContentWidth(cell, cellMeasure);
|
|
334
335
|
const floatingZones = buildTableCellFloatingZones(getTableCellFloatingImages(cell, cellMeasure, contentWidth), contentWidth);
|
|
335
336
|
const contentOffsetX = getCellContentOffsetX(cell);
|
|
336
|
-
const
|
|
337
|
+
const spacing = getTableCellSpacingInsetsY(tableBlock.cellSpacing, rowIndex, cell.rowSpan ?? 1, tableBlock.rows.length);
|
|
338
|
+
const contentOffsetY = spacing.top + getCellContentOffsetY(cell, cellMeasure, Math.max(0, rowMeasure.height - spacing.top - spacing.bottom));
|
|
337
339
|
let blockY = 0;
|
|
338
340
|
for (let blockIdx = 0; blockIdx < cell.blocks.length; blockIdx++) {
|
|
339
341
|
const cellBlock = cell.blocks[blockIdx];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/layout-engine/anchorLayoutInCellCompatibility.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* `true` when the document's compatibility mode forces every table-cell
|
|
4
|
+
* anchor to lay out inside its cell, ignoring an authored
|
|
5
|
+
* `layoutInCell="0"`. `false` means the authored attribute (or its
|
|
6
|
+
* OOXML default of "confined to the cell") should be honoured as stated.
|
|
7
|
+
*/
|
|
8
|
+
declare const resolveAnchorLayoutInCellCompatibility: (compatibilityMode: number | undefined) => boolean;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { resolveAnchorLayoutInCellCompatibility };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/layout-engine/anchorLayoutInCellCompatibility.ts
|
|
2
|
+
/**
|
|
3
|
+
* First `compatibilityMode` that ignores `wp:anchor/@layoutInCell="0"`.
|
|
4
|
+
*
|
|
5
|
+
* From `compatibilityMode` 15 onward, an anchor inside a table cell is laid
|
|
6
|
+
* out in the cell regardless of what `wp:anchor/@layoutInCell` states: the
|
|
7
|
+
* attribute stops opting the anchor out of the cell's coordinate space.
|
|
8
|
+
* Earlier modes still honour an explicit `layoutInCell="0"` and let the
|
|
9
|
+
* anchor position itself relative to the page. A document that declares no
|
|
10
|
+
* `compatSetting` at all is read with the oldest semantics, so it honours
|
|
11
|
+
* the attribute too.
|
|
12
|
+
*/
|
|
13
|
+
const FIRST_ALWAYS_IN_CELL_COMPATIBILITY_MODE = 15;
|
|
14
|
+
/**
|
|
15
|
+
* `true` when the document's compatibility mode forces every table-cell
|
|
16
|
+
* anchor to lay out inside its cell, ignoring an authored
|
|
17
|
+
* `layoutInCell="0"`. `false` means the authored attribute (or its
|
|
18
|
+
* OOXML default of "confined to the cell") should be honoured as stated.
|
|
19
|
+
*/
|
|
20
|
+
const resolveAnchorLayoutInCellCompatibility = (compatibilityMode) => compatibilityMode !== void 0 && compatibilityMode >= FIRST_ALWAYS_IN_CELL_COMPATIBILITY_MODE;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { resolveAnchorLayoutInCellCompatibility };
|
|
@@ -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, ListMarkerFormatting, 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, isListNumPr, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, tableColumnsArePinned } from "./types.js";
|
|
1
|
+
import { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, MathRun, Measure, MeasuredLine, NOTE_SEPARATOR_RULE_THICKNESS, NOTE_SEPARATOR_WIDTH_FRACTION, NoteAreaLayout, NoteSeparatorKind, NoteSeparatorRule, 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, TextBoxGradientFill, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isListNumPr, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, stripFlowBlockPmAnchors, 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";
|
|
@@ -42,4 +42,4 @@ declare function layoutDocument(blocks: FlowBlock[], measures: Measure[], option
|
|
|
42
42
|
*/
|
|
43
43
|
declare function getHeaderRowsHeight(measure: TableMeasure, headerRowCount: number): number;
|
|
44
44
|
//#endregion
|
|
45
|
-
export { BlockId, BorderStyle, type BreakDecision, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, type KeepNextChain, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, 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, isListNumPr, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, resolveTableCellPadding, resolveTableWidthPx, scheduleSectionBreak, tableColumnsArePinned };
|
|
45
|
+
export { BlockId, BorderStyle, type BreakDecision, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, type KeepNextChain, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, MathRun, Measure, MeasuredLine, NOTE_SEPARATOR_RULE_THICKNESS, NOTE_SEPARATOR_WIDTH_FRACTION, NoteAreaLayout, NoteSeparatorKind, NoteSeparatorRule, 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, TextBoxGradientFill, TextBoxMeasure, TextRun, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, getTableRowLeadingWidth, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isListNumPr, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, resolveTableCellPadding, resolveTableWidthPx, scheduleSectionBreak, stripFlowBlockPmAnchors, tableColumnsArePinned };
|
|
@@ -2,9 +2,10 @@ import { emuToPixels } from "../utils/units.js";
|
|
|
2
2
|
import { reflowFootnoteColumns } from "./footnoteColumnReflow.js";
|
|
3
3
|
import { resolveSectionHeaderFooterRefs } from "./headerFooterRefs.js";
|
|
4
4
|
import { calculateChainHeight, computeKeepNextChains, getMidChainIndices, hasKeepLines, hasPageBreakBefore } from "./keep-together.js";
|
|
5
|
-
import { measuredLineAdvance } from "./lineFlow.js";
|
|
5
|
+
import { measuredLineAdvance, measuredLineRangeHeight } from "./lineFlow.js";
|
|
6
6
|
import { resolveFloatingTablePageX } from "./measure/floatingTablePosition.js";
|
|
7
7
|
import { resolveTableInlineOffset } from "./measure/tableInlinePlacement.js";
|
|
8
|
+
import { annotateNoteSeparators, continuesNoteArea, createNoteAreaContinuation } from "./noteAreaFlow.js";
|
|
8
9
|
import { SECTION_START_PLACEMENT, createPaginator } from "./paginator.js";
|
|
9
10
|
import { getParagraphFragmentPmRange } from "./paragraphFragmentRange.js";
|
|
10
11
|
import { collapseParagraphSpacing, getParagraphSpacingAfter, getParagraphSpacingBefore, isEmptyParagraph, paragraphsShareStyle, resolveEffectiveParagraphSpacingTree } from "./paragraphSpacing.js";
|
|
@@ -12,9 +13,9 @@ import { assertExhaustiveFlowBlock, findPageIndexContainingPmPos } from "./pmPag
|
|
|
12
13
|
import { INITIAL_RENDERED_BREAK_STATE, PAGE_ADVANCE, reconcileAfterBlock, reconcileBreakBeforeBlock, recordReflowBoundary } from "./renderedBreakReconciliation.js";
|
|
13
14
|
import { applyPendingToActive, createInitialSectionState, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, normalizeSectionBreakType, physicalColumnRegionIsShared, scheduleSectionBreak } from "./section-breaks.js";
|
|
14
15
|
import { applySectionVerticalAlignment } from "./sectionVerticalAlignment.js";
|
|
15
|
-
import { buildTableRowBreakInfo, getRowContinuationSkip, snapRowBreak } from "./tableRowBreak.js";
|
|
16
|
+
import { buildTableRowBreakInfo, getRowContinuationSkip, snapRowBreak, tableKeepNextOpeningHeight } from "./tableRowBreak.js";
|
|
16
17
|
import { bandFragmentX, bandTopContentY, isPageFrameRelativeAnchor } from "./textBoxFlow.js";
|
|
17
|
-
import { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isListNumPr, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, tableColumnsArePinned } from "./types.js";
|
|
18
|
+
import { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, NOTE_SEPARATOR_RULE_THICKNESS, NOTE_SEPARATOR_WIDTH_FRACTION, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isListNumPr, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, stripFlowBlockPmAnchors, tableColumnsArePinned } from "./types.js";
|
|
18
19
|
import { panic } from "better-result";
|
|
19
20
|
//#region src/layout-engine/index.ts
|
|
20
21
|
/**
|
|
@@ -147,14 +148,14 @@ function applyContextualSpacing(blocks) {
|
|
|
147
148
|
*/
|
|
148
149
|
function layoutDocument(blocks, measures, options) {
|
|
149
150
|
const initialLayout = layoutDocumentPass(blocks, measures, options);
|
|
150
|
-
return applySectionVerticalAlignment(options.footnoteHeightById ? reflowFootnoteColumns({
|
|
151
|
+
return annotateNoteSeparators(applySectionVerticalAlignment(options.footnoteHeightById ? reflowFootnoteColumns({
|
|
151
152
|
initialLayout,
|
|
152
153
|
...options.footnoteReservedHeights ? { initialReserveFloors: options.footnoteReservedHeights } : {},
|
|
153
154
|
runLayout: (reserveFloors) => layoutDocumentPass(blocks, measures, {
|
|
154
155
|
...options,
|
|
155
156
|
footnoteReservedHeights: reserveFloors
|
|
156
157
|
})
|
|
157
|
-
}) : initialLayout, options.sectionVerticalAlignments);
|
|
158
|
+
}) : initialLayout, options.sectionVerticalAlignments), blocks, measures, options.noteAreas);
|
|
158
159
|
}
|
|
159
160
|
function layoutDocumentPass(blocks, measures, options) {
|
|
160
161
|
if (blocks.length !== measures.length) panic(`layoutDocument: expected one measure per block (blocks=${blocks.length}, measures=${measures.length})`);
|
|
@@ -193,6 +194,7 @@ function layoutDocumentPass(blocks, measures, options) {
|
|
|
193
194
|
...options.mirrorMargins === true ? { mirrorMargins: true } : {},
|
|
194
195
|
...options.firstPageMargins !== void 0 ? { firstPageMargins: options.firstPageMargins } : {},
|
|
195
196
|
...options.sectionEvenPageMargins !== void 0 ? { sectionEvenPageMargins: options.sectionEvenPageMargins } : {},
|
|
197
|
+
...options.sectionFirstPageMargins !== void 0 ? { sectionFirstPageMargins: options.sectionFirstPageMargins } : {},
|
|
196
198
|
columns: initialConfig.columns ?? DEFAULT_COLUMNS,
|
|
197
199
|
pageNumbering: initialConfig.pageNumbering,
|
|
198
200
|
...options.footnoteReservedHeights !== void 0 ? { footnoteReservedHeights: options.footnoteReservedHeights } : {},
|
|
@@ -208,9 +210,11 @@ function layoutDocumentPass(blocks, measures, options) {
|
|
|
208
210
|
let activeSectionPageHeight = initialConfig.pageSize.h;
|
|
209
211
|
let activeSectionMarginBottom = initialConfig.margins.bottom;
|
|
210
212
|
let renderedBreakState = INITIAL_RENDERED_BREAK_STATE;
|
|
213
|
+
const noteAreaContinuation = createNoteAreaContinuation(options.noteAreas, paginator);
|
|
211
214
|
for (let i = 0; i < blocks.length; i++) {
|
|
212
215
|
const block = blocks[i];
|
|
213
216
|
const measure = measures[i];
|
|
217
|
+
if (noteAreaContinuation !== void 0) paginator.setPageTopContinuation(continuesNoteArea(options.noteAreas, block) ? noteAreaContinuation : void 0);
|
|
214
218
|
const firstLine = measure.kind === "paragraph" ? measure.lines.at(0) : void 0;
|
|
215
219
|
const firstLineAdvance = firstLine ? measuredLineAdvance(firstLine) : 0;
|
|
216
220
|
const renderedBreakNeedsSnap = measure.kind === "paragraph" && (!paginator.fits(measure.totalHeight) || firstLineAdvance > 0 && paginator.getAvailableHeight() <= firstLineAdvance * RENDERED_BREAK_REFLOW_TOLERANCE_LINES);
|
|
@@ -225,13 +229,13 @@ function layoutDocumentPass(blocks, measures, options) {
|
|
|
225
229
|
renderedBreakNeedsSnap
|
|
226
230
|
});
|
|
227
231
|
if (block.kind !== "pageBreak") {
|
|
228
|
-
if (breakDecision.pageAdvance === PAGE_ADVANCE.PHYSICAL) paginator.forcePageBreak();
|
|
232
|
+
if (breakDecision.pageAdvance === PAGE_ADVANCE.PHYSICAL) paginator.forcePageBreak({ coalesceBlankPage: hasPageBreakBefore(block) });
|
|
229
233
|
else if (breakDecision.pageAdvance === PAGE_ADVANCE.COALESCED) paginator.coalescePageBreak();
|
|
230
234
|
}
|
|
231
235
|
renderedBreakState = breakDecision.state;
|
|
232
236
|
const chain = keepNextChains.get(i);
|
|
233
237
|
if (chain && !midChainIndices.has(i)) {
|
|
234
|
-
const chainHeight = calculateChainHeight(chain, blocks, measures);
|
|
238
|
+
const chainHeight = calculateChainHeight(chain, blocks, measures, paginator.getCurrentState().trailingSpacing, tableKeepNextOpeningHeight);
|
|
235
239
|
const pageBeforeChainLayout = paginator.getCurrentState().page.number;
|
|
236
240
|
paginator.ensureFits(chainHeight);
|
|
237
241
|
if (paginator.getCurrentState().page.number > pageBeforeChainLayout) renderedBreakState = recordReflowBoundary(renderedBreakState, true);
|
|
@@ -306,6 +310,7 @@ function layoutDocumentPass(blocks, measures, options) {
|
|
|
306
310
|
previousPage: paginator.states[pageBeforeBlockLayout - 1]?.page
|
|
307
311
|
});
|
|
308
312
|
}
|
|
313
|
+
paginator.setPageTopContinuation(void 0);
|
|
309
314
|
if (paginator.states.length === 0) paginator.getCurrentState();
|
|
310
315
|
return {
|
|
311
316
|
pageSize,
|
|
@@ -376,6 +381,16 @@ function layoutParagraph({ block, measure, paginator, contentWidth, footnoteHeig
|
|
|
376
381
|
}
|
|
377
382
|
const spaceBefore = suppressSpaceBefore ? 0 : getParagraphSpacingBefore(block);
|
|
378
383
|
const spaceAfter = getParagraphSpacingAfter(block);
|
|
384
|
+
let keepLinesDemand;
|
|
385
|
+
if (lines.length > 1 && hasKeepLines(block)) {
|
|
386
|
+
let footnoteHeight = 0;
|
|
387
|
+
for (const line of lines) footnoteHeight += getLineFootnoteRefs(block, line.fromRun, line.toRun, footnoteHeightById).height;
|
|
388
|
+
keepLinesDemand = {
|
|
389
|
+
linesHeight: measuredLineRangeHeight(lines, 0, lines.length),
|
|
390
|
+
footnoteHeight
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
let keepLinesMoveAttempted = false;
|
|
379
394
|
let currentLineIndex = 0;
|
|
380
395
|
while (currentLineIndex < lines.length) {
|
|
381
396
|
const state = paginator.getCurrentState();
|
|
@@ -400,6 +415,19 @@ function layoutParagraph({ block, measure, paginator, contentWidth, footnoteHeig
|
|
|
400
415
|
continue;
|
|
401
416
|
}
|
|
402
417
|
}
|
|
418
|
+
if (keepLinesDemand !== void 0 && !keepLinesMoveAttempted && currentLineIndex === 0 && state.cursorY !== state.topMargin) {
|
|
419
|
+
const wholeHeight = keepLinesDemand.linesHeight + projectedFootnoteReserveGrowth(state, keepLinesDemand.footnoteHeight);
|
|
420
|
+
const collapsedLead = collapseParagraphSpacing({
|
|
421
|
+
before: spaceBefore,
|
|
422
|
+
after: state.trailingSpacing
|
|
423
|
+
});
|
|
424
|
+
const columnCapacity = state.contentBottom - state.topMargin;
|
|
425
|
+
if (collapsedLead + wholeHeight > availableHeight && spaceBefore + wholeHeight <= columnCapacity) {
|
|
426
|
+
keepLinesMoveAttempted = true;
|
|
427
|
+
paginator.ensureFits(collapsedLead + wholeHeight);
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
403
431
|
let linesHeight = 0;
|
|
404
432
|
let linesFnHeight = 0;
|
|
405
433
|
const linesFnIds = [];
|
|
@@ -561,13 +589,19 @@ function layoutTable(block, measure, paginator, footnoteHeightById) {
|
|
|
561
589
|
return previous?.kind === "table" && previous.blockId === block.id && previous.toRow === rowIndex && previous.y + previous.height === state.cursorY;
|
|
562
590
|
};
|
|
563
591
|
const shouldRepeatHeaderRows = (rowIndex, consumed, state = paginator.getCurrentState()) => headerRowCount > 0 && rowIndex >= headerRowCount && !(consumed === 0 && hasAdjacentPriorTableRows(rowIndex, state));
|
|
592
|
+
const rowOpensFlowRegion = (rowIndex, state) => {
|
|
593
|
+
if (state.cursorY === state.topMargin) return true;
|
|
594
|
+
const previous = state.page.fragments.at(-1);
|
|
595
|
+
return rowIndex > 0 && rowIndex <= headerRowCount && previous?.kind === "table" && previous.blockId === block.id && previous.fromRow === 0 && previous.toRow === rowIndex && previous.y === state.topMargin && previous.y + previous.height === state.cursorY;
|
|
596
|
+
};
|
|
564
597
|
const canSplitRow = (rowIndex, state = paginator.getCurrentState()) => {
|
|
565
598
|
const row = rows[rowIndex];
|
|
566
599
|
const sourceRow = block.rows[rowIndex];
|
|
567
|
-
if (!row || !sourceRow || sourceRow.
|
|
600
|
+
if (!row || !sourceRow || sourceRow.isHeader || verticallyMergedRows.has(rowIndex)) return false;
|
|
568
601
|
if ((breakInfo.breakOffsets[rowIndex]?.length ?? 0) <= 1) return false;
|
|
569
602
|
const freshHeaderOverhead = headerRowCount > 0 && rowIndex >= headerRowCount ? headerRowsHeight : 0;
|
|
570
603
|
const oversized = row.height + freshHeaderOverhead > getCurrentRowCapacity(state);
|
|
604
|
+
if (sourceRow.cantSplit) return oversized && sourceRow.heightRule !== "exact" && rowOpensFlowRegion(rowIndex, state);
|
|
571
605
|
if (!oversized && (state.footnoteHeight > 0 || (rowFootnoteIds[rowIndex]?.length ?? 0) > 0)) return false;
|
|
572
606
|
const currentHeaderOverhead = shouldRepeatHeaderRows(rowIndex, 0, state) ? headerRowsHeight : 0;
|
|
573
607
|
const currentAvailableHeight = paginator.getAvailableHeight() - currentHeaderOverhead - state.trailingSpacing;
|
|
@@ -955,18 +989,44 @@ function layoutTextBox(block, measure, { paginator, sectionMarginTop, sectionPag
|
|
|
955
989
|
paginator.addUnflowedFragment(fragment);
|
|
956
990
|
return;
|
|
957
991
|
}
|
|
958
|
-
const
|
|
992
|
+
const effect = block.effectExtent;
|
|
993
|
+
const occupiedHeight = measure.height + (effect?.top ?? 0) + (effect?.bottom ?? 0);
|
|
994
|
+
const occupiedWidth = measure.width + (effect?.left ?? 0) + (effect?.right ?? 0);
|
|
995
|
+
const host = block.hostParagraph;
|
|
959
996
|
const fragment = {
|
|
960
997
|
kind: "textBox",
|
|
961
998
|
blockId: block.id,
|
|
962
|
-
x:
|
|
999
|
+
x: 0,
|
|
963
1000
|
y: 0,
|
|
964
1001
|
width: measure.width,
|
|
965
1002
|
height: measure.height,
|
|
966
1003
|
...block.pmStart !== void 0 ? { pmStart: block.pmStart } : {},
|
|
967
1004
|
...block.pmEnd !== void 0 ? { pmEnd: block.pmEnd } : {}
|
|
968
1005
|
};
|
|
969
|
-
|
|
1006
|
+
const result = paginator.addFragment(fragment, occupiedHeight, host?.spacing?.before ?? 0, host?.spacing?.after ?? 0);
|
|
1007
|
+
fragment.x = result.x + hostParagraphLineOffset(host, paginator.columnWidth, occupiedWidth) + (effect?.left ?? 0);
|
|
1008
|
+
fragment.y = result.y + (effect?.top ?? 0);
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Where a line holding only an object of `width` starts within a column:
|
|
1012
|
+
* after the host paragraph's start and first-line indents, then aligned in
|
|
1013
|
+
* what remains before its end indent.
|
|
1014
|
+
*/
|
|
1015
|
+
function hostParagraphLineOffset(host, columnWidth, width) {
|
|
1016
|
+
if (!host) return 0;
|
|
1017
|
+
const indent = host.indent;
|
|
1018
|
+
const start = (indent?.left ?? 0) + (indent?.firstLine ?? 0) - (indent?.hanging ?? 0);
|
|
1019
|
+
const slack = Math.max(0, columnWidth - start - (indent?.right ?? 0) - width);
|
|
1020
|
+
switch (host.alignment) {
|
|
1021
|
+
case "center": return start + slack / 2;
|
|
1022
|
+
case "right": return start + slack;
|
|
1023
|
+
case "left":
|
|
1024
|
+
case "justify":
|
|
1025
|
+
case void 0: return start;
|
|
1026
|
+
default:
|
|
1027
|
+
host.alignment;
|
|
1028
|
+
return start;
|
|
1029
|
+
}
|
|
970
1030
|
}
|
|
971
1031
|
/**
|
|
972
1032
|
* A topAndBottom text box whose vertical anchor pins it to the page frame
|
|
@@ -1011,6 +1071,32 @@ function startSectionInPlace(paginator, nextSectionConfig, nextSectionIndex) {
|
|
|
1011
1071
|
paginator.retargetCurrentBlankPage();
|
|
1012
1072
|
}
|
|
1013
1073
|
/**
|
|
1074
|
+
* Whether a section opening on `target` would give two consecutive sheets page
|
|
1075
|
+
* numbers that are both odd or both even under `w:evenAndOddHeaders` (§17.10.1). Odd and
|
|
1076
|
+
* even page numbers alternate between right- and left-hand sheets, so a
|
|
1077
|
+
* `w:pgNumType w:start` restart that repeats whether the previous sheet's number is odd or even
|
|
1078
|
+
* needs a blank sheet between them.
|
|
1079
|
+
*/
|
|
1080
|
+
function sectionStartRepeatsOddEven(paginator, target) {
|
|
1081
|
+
if (target.page.headerFooterRefs?.evenAndOddHeaders !== true) return false;
|
|
1082
|
+
const previous = paginator.states.at(-2)?.page;
|
|
1083
|
+
if (previous === void 0 || previous.number !== target.page.number - 1) return false;
|
|
1084
|
+
return previous.logicalNumber % 2 === target.page.logicalNumber % 2;
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Keep the blank sheet the section break opened as a filler with no page
|
|
1088
|
+
* furniture, and open the section again on the following sheet so its first
|
|
1089
|
+
* page keeps the restarted page number.
|
|
1090
|
+
*/
|
|
1091
|
+
function insertOddEvenFillerPage(paginator, filler, sectionIndex, sectionConfig) {
|
|
1092
|
+
filler.page.headerFooterRefs = {};
|
|
1093
|
+
paginator.startSection({
|
|
1094
|
+
sectionIndex,
|
|
1095
|
+
pageNumbering: sectionConfig.pageNumbering
|
|
1096
|
+
});
|
|
1097
|
+
paginator.forcePageBreak();
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1014
1100
|
* Handle a section break block.
|
|
1015
1101
|
* @param block - The section break block (current section's properties)
|
|
1016
1102
|
* @param paginator - The paginator instance
|
|
@@ -1019,14 +1105,16 @@ function startSectionInPlace(paginator, nextSectionConfig, nextSectionIndex) {
|
|
|
1019
1105
|
*/
|
|
1020
1106
|
function handleSectionBreak(_block, paginator, nextSectionConfig, nextSectionType, nextSectionIndex) {
|
|
1021
1107
|
switch (nextSectionType) {
|
|
1022
|
-
case "nextPage":
|
|
1108
|
+
case "nextPage": {
|
|
1023
1109
|
paginator.updatePageLayout(nextSectionConfig.pageSize, nextSectionConfig.margins);
|
|
1024
1110
|
if (nextSectionIndex !== void 0) paginator.startSection({
|
|
1025
1111
|
sectionIndex: nextSectionIndex,
|
|
1026
1112
|
pageNumbering: nextSectionConfig.pageNumbering
|
|
1027
1113
|
});
|
|
1028
|
-
paginator.forcePageBreak({ coalesceBlankPage: true });
|
|
1114
|
+
const target = paginator.forcePageBreak({ coalesceBlankPage: true });
|
|
1115
|
+
if (nextSectionIndex !== void 0 && sectionStartRepeatsOddEven(paginator, target)) insertOddEvenFillerPage(paginator, target, nextSectionIndex, nextSectionConfig);
|
|
1029
1116
|
break;
|
|
1117
|
+
}
|
|
1030
1118
|
case "evenPage":
|
|
1031
1119
|
if (paginator.forcePageBreak({ coalesceBlankPage: true }).page.number % 2 !== 0) paginator.forcePageBreak();
|
|
1032
1120
|
paginator.updatePageLayout(nextSectionConfig.pageSize, nextSectionConfig.margins);
|
|
@@ -1072,4 +1160,4 @@ function handleSectionBreak(_block, paginator, nextSectionConfig, nextSectionTyp
|
|
|
1072
1160
|
paginator.updateColumns(nextSectionConfig.columns ?? DEFAULT_COLUMNS);
|
|
1073
1161
|
}
|
|
1074
1162
|
//#endregion
|
|
1075
|
-
export { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, getTableRowLeadingWidth, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isListNumPr, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, resolveTableCellPadding, resolveTableWidthPx, scheduleSectionBreak, tableColumnsArePinned };
|
|
1163
|
+
export { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, NOTE_SEPARATOR_RULE_THICKNESS, NOTE_SEPARATOR_WIDTH_FRACTION, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, getTableRowLeadingWidth, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isListNumPr, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, resolveTableCellPadding, resolveTableWidthPx, scheduleSectionBreak, stripFlowBlockPmAnchors, tableColumnsArePinned };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ParagraphAttrs } from "./types.js";
|
|
2
2
|
//#region src/layout-engine/justificationCompatibility.d.ts
|
|
3
|
-
declare
|
|
3
|
+
declare const resolveJustificationCompatibility: (compatibilityMode: number | undefined) => NonNullable<ParagraphAttrs["justificationCompatibility"]> | undefined;
|
|
4
4
|
//#endregion
|
|
5
5
|
export { resolveJustificationCompatibility };
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
//#region src/layout-engine/justificationCompatibility.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
/**
|
|
3
|
+
* First `compatibilityMode` that fits justified lines with the current rules.
|
|
4
|
+
*
|
|
5
|
+
* Earlier modes keep strict justified fitting. A document that declares no
|
|
6
|
+
* `compatSetting` at all is read with the oldest semantics, so it takes the
|
|
7
|
+
* legacy rule too.
|
|
8
|
+
*/
|
|
9
|
+
const FIRST_MODERN_JUSTIFICATION_COMPATIBILITY_MODE = 15;
|
|
10
|
+
const resolveJustificationCompatibility = (compatibilityMode) => compatibilityMode !== void 0 && compatibilityMode >= FIRST_MODERN_JUSTIFICATION_COMPATIBILITY_MODE ? void 0 : { type: "legacy" };
|
|
7
11
|
//#endregion
|
|
8
12
|
export { resolveJustificationCompatibility };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FlowBlock, Measure } from "./types.js";
|
|
1
|
+
import { FlowBlock, Measure, TableBlock, TableMeasure } from "./types.js";
|
|
2
2
|
//#region src/layout-engine/keep-together.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* A chain of paragraphs that Word keeps with following content. This includes
|
|
@@ -30,12 +30,21 @@ declare function computeKeepNextChains(blocks: FlowBlock[]): Map<number, KeepNex
|
|
|
30
30
|
* Calculate the height needed to keep consecutive paragraph boundaries from
|
|
31
31
|
* breaking across pages.
|
|
32
32
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
33
|
+
* Each successor (later member or the anchor) must bring its minimum
|
|
34
|
+
* unbreakable opening onto the page: see {@link minimumOpeningLineCount}. When
|
|
35
|
+
* that opening is the whole paragraph, the successor is indivisible and the
|
|
36
|
+
* reservation continues through it; otherwise the chain stops after the
|
|
37
|
+
* opening, because a later split cannot separate it from its predecessor.
|
|
38
|
+
*
|
|
39
|
+
* A table anchor contributes `tableOpeningHeight`: the part of the table
|
|
40
|
+
* that must start on the same page as the paragraph before it.
|
|
41
|
+
*
|
|
42
|
+
* A paragraph measure's `totalHeight` already includes its own spacing before
|
|
43
|
+
* and after. The chain accounts for spacing separately (collapsing each gap to
|
|
44
|
+
* the larger side, as the paginator does), so members contribute only their
|
|
45
|
+
* line advances; otherwise every gap would be reserved twice.
|
|
37
46
|
*/
|
|
38
|
-
declare function calculateChainHeight(chain: KeepNextChain, blocks: FlowBlock[], measures: Measure[]): number;
|
|
47
|
+
declare function calculateChainHeight(chain: KeepNextChain, blocks: FlowBlock[], measures: Measure[], incomingSpacing?: number, tableOpeningHeight?: (block: TableBlock, measure: TableMeasure) => number): number;
|
|
39
48
|
/**
|
|
40
49
|
* Get the set of indices that are mid-chain (not chain starters).
|
|
41
50
|
* These should skip the keepNext check since their chain starter already decided.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { measuredLineRangeHeight } from "./lineFlow.js";
|
|
1
2
|
import { collapseParagraphSpacing, isAuthoredEmptyParagraph, isEmptyParagraph } from "./paragraphSpacing.js";
|
|
2
3
|
//#region src/layout-engine/keep-together.ts
|
|
3
4
|
/**
|
|
@@ -6,6 +7,8 @@ import { collapseParagraphSpacing, isAuthoredEmptyParagraph, isEmptyParagraph }
|
|
|
6
7
|
* DOCX paragraphs can have keepNext (keep with next paragraph) and keepLines
|
|
7
8
|
* (keep all lines together) properties that affect pagination.
|
|
8
9
|
*/
|
|
10
|
+
/** Lines §17.3.1.44 widow control keeps on each side of a paragraph split. */
|
|
11
|
+
const MIN_WIDOW_CONTROL_SPLIT_LINES = 2;
|
|
9
12
|
/**
|
|
10
13
|
* Whether an empty paragraph is only a structural separator through which a
|
|
11
14
|
* keep-with-next chain may pass. An explicitly styled or directly formatted
|
|
@@ -74,23 +77,50 @@ function computeKeepNextChains(blocks) {
|
|
|
74
77
|
return chains;
|
|
75
78
|
}
|
|
76
79
|
/**
|
|
80
|
+
* Lines of a paragraph that must share a page with the paragraph before it for
|
|
81
|
+
* a `w:keepNext` link (§17.3.1.15) to hold.
|
|
82
|
+
*
|
|
83
|
+
* - `w:keepLines` (§17.3.1.14): the paragraph never splits, so all of it.
|
|
84
|
+
* - `w:widowControl` (§17.3.1.44): a split leaves at least two lines on each
|
|
85
|
+
* side, so a paragraph shorter than four lines cannot split at all and a
|
|
86
|
+
* longer one needs its first two lines.
|
|
87
|
+
* - Otherwise a single line.
|
|
88
|
+
*/
|
|
89
|
+
function minimumOpeningLineCount(block, measure) {
|
|
90
|
+
const lineCount = measure.lines.length;
|
|
91
|
+
if (block.attrs?.keepLines === true) return lineCount;
|
|
92
|
+
if (block.attrs?.widowControl !== false) return lineCount < MIN_WIDOW_CONTROL_SPLIT_LINES * 2 ? lineCount : MIN_WIDOW_CONTROL_SPLIT_LINES;
|
|
93
|
+
return Math.min(1, lineCount);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
77
96
|
* Calculate the height needed to keep consecutive paragraph boundaries from
|
|
78
97
|
* breaking across pages.
|
|
79
98
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
99
|
+
* Each successor (later member or the anchor) must bring its minimum
|
|
100
|
+
* unbreakable opening onto the page: see {@link minimumOpeningLineCount}. When
|
|
101
|
+
* that opening is the whole paragraph, the successor is indivisible and the
|
|
102
|
+
* reservation continues through it; otherwise the chain stops after the
|
|
103
|
+
* opening, because a later split cannot separate it from its predecessor.
|
|
104
|
+
*
|
|
105
|
+
* A table anchor contributes `tableOpeningHeight`: the part of the table
|
|
106
|
+
* that must start on the same page as the paragraph before it.
|
|
107
|
+
*
|
|
108
|
+
* A paragraph measure's `totalHeight` already includes its own spacing before
|
|
109
|
+
* and after. The chain accounts for spacing separately (collapsing each gap to
|
|
110
|
+
* the larger side, as the paginator does), so members contribute only their
|
|
111
|
+
* line advances; otherwise every gap would be reserved twice.
|
|
84
112
|
*/
|
|
85
|
-
function calculateChainHeight(chain, blocks, measures) {
|
|
113
|
+
function calculateChainHeight(chain, blocks, measures, incomingSpacing = 0, tableOpeningHeight) {
|
|
86
114
|
const firstMemberIndex = chain.memberIndices.at(0);
|
|
87
115
|
if (firstMemberIndex === void 0) return 0;
|
|
88
116
|
const firstBlock = blocks[firstMemberIndex];
|
|
89
117
|
const firstMeasure = measures[firstMemberIndex];
|
|
90
118
|
if (firstBlock?.kind !== "paragraph" || firstMeasure?.kind !== "paragraph") return 0;
|
|
91
|
-
let totalHeight = (
|
|
119
|
+
let totalHeight = collapseParagraphSpacing({
|
|
120
|
+
before: firstBlock.attrs?.spacing?.before ?? 0,
|
|
121
|
+
after: incomingSpacing
|
|
122
|
+
}) + measuredLineRangeHeight(firstMeasure.lines, 0, firstMeasure.lines.length);
|
|
92
123
|
let trailingSpacing = firstBlock.attrs?.spacing?.after ?? 0;
|
|
93
|
-
const startsWithTrailingTableSeparator = blocks[firstMemberIndex - 1]?.kind === "table" && isEmptyParagraph(firstBlock) && !firstBlock.attrs?.keepNext;
|
|
94
124
|
const successorIndices = [...chain.memberIndices.slice(1)];
|
|
95
125
|
if (chain.anchorIndex !== -1) successorIndices.push(chain.anchorIndex);
|
|
96
126
|
for (let index = 0; index < successorIndices.length; index++) {
|
|
@@ -98,21 +128,18 @@ function calculateChainHeight(chain, blocks, measures) {
|
|
|
98
128
|
if (successorIndex === void 0) continue;
|
|
99
129
|
const successorBlock = blocks[successorIndex];
|
|
100
130
|
const successorMeasure = measures[successorIndex];
|
|
131
|
+
if (tableOpeningHeight !== void 0 && successorBlock?.kind === "table" && successorMeasure?.kind === "table" && successorBlock.floating === void 0) return totalHeight + trailingSpacing + tableOpeningHeight(successorBlock, successorMeasure);
|
|
101
132
|
if (successorBlock?.kind !== "paragraph" || successorMeasure?.kind !== "paragraph") return totalHeight;
|
|
102
133
|
totalHeight += collapseParagraphSpacing({
|
|
103
134
|
before: successorBlock.attrs?.spacing?.before ?? 0,
|
|
104
135
|
after: trailingSpacing
|
|
105
136
|
});
|
|
106
|
-
const
|
|
107
|
-
if (
|
|
137
|
+
const lineCount = successorMeasure.lines.length;
|
|
138
|
+
if (lineCount === 0) return totalHeight;
|
|
108
139
|
const isAnchor = index === successorIndices.length - 1 && chain.anchorIndex !== -1;
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return totalHeight + firstLine.lineHeight + (secondLine?.lineHeight ?? 0);
|
|
113
|
-
}
|
|
114
|
-
if (isAnchor || isSplittable) return totalHeight + firstLine.lineHeight;
|
|
115
|
-
totalHeight += successorMeasure.totalHeight;
|
|
140
|
+
const openingLines = minimumOpeningLineCount(successorBlock, successorMeasure);
|
|
141
|
+
totalHeight += measuredLineRangeHeight(successorMeasure.lines, 0, openingLines);
|
|
142
|
+
if (isAnchor || openingLines < lineCount) return totalHeight;
|
|
116
143
|
trailingSpacing = successorBlock.attrs?.spacing?.after ?? 0;
|
|
117
144
|
}
|
|
118
145
|
return totalHeight;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FlowBlock } from "./types.js";
|
|
2
2
|
//#region src/layout-engine/layoutInstrumentation.d.ts
|
|
3
|
-
type LayoutRunReason = "font-ready" | "initial" | "layout-input" | "manual" | "transaction";
|
|
3
|
+
type LayoutRunReason = "font-ready" | "hyphenation-ready" | "initial" | "layout-input" | "manual" | "transaction";
|
|
4
4
|
type LayoutPhase = "flow-blocks" | "header-footer" | "initial-fonts" | "layout-document" | "measure-blocks" | "render-pages";
|
|
5
5
|
type HiddenEditorStateReason = "external-document" | "mount";
|
|
6
6
|
type HiddenEditorPhase = "editor-state" | "editor-view" | "to-prose-doc" | "update-state";
|
|
@@ -18,6 +18,10 @@ type LayoutInstrumentation = {
|
|
|
18
18
|
onHiddenEditorStateCreate?: (event: {
|
|
19
19
|
reason: HiddenEditorStateReason;
|
|
20
20
|
}) => void;
|
|
21
|
+
onHyphenationDictionaryError?: (event: {
|
|
22
|
+
dictionary: string;
|
|
23
|
+
message: string;
|
|
24
|
+
}) => void;
|
|
21
25
|
onLayoutComplete?: (event: {
|
|
22
26
|
reason: LayoutRunReason;
|
|
23
27
|
}) => void;
|
|
@@ -51,9 +55,11 @@ declare function recordMeasureBlockError(blockIndex: number, block: FlowBlock, e
|
|
|
51
55
|
declare function recordLayoutComplete(reason?: LayoutRunReason): void;
|
|
52
56
|
declare function recordLayoutStart(reason: LayoutRunReason): void;
|
|
53
57
|
declare function recordLayoutError(reason: LayoutRunReason, error: unknown): void;
|
|
58
|
+
/** A dictionary failed to load; layout continues without hyphenating that language. */
|
|
59
|
+
declare function recordHyphenationDictionaryError(dictionary: string, error: Error): void;
|
|
54
60
|
declare function recordLayoutPhase(reason: LayoutRunReason, phase: LayoutPhase, durationMs: number): void;
|
|
55
61
|
declare function recordHiddenEditorStateCreate(reason: HiddenEditorStateReason): void;
|
|
56
62
|
declare function recordHiddenEditorPhase(reason: HiddenEditorStateReason, phase: HiddenEditorPhase, durationMs: number): void;
|
|
57
63
|
declare function recordDocumentLoadPhase(phase: DocumentLoadPhase, durationMs: number): void;
|
|
58
64
|
//#endregion
|
|
59
|
-
export { DocumentLoadPhase, HiddenEditorPhase, HiddenEditorStateReason, LayoutInstrumentation, LayoutPhase, LayoutRunReason, recordDocumentLoadPhase, recordHiddenEditorPhase, recordHiddenEditorStateCreate, recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayoutStart, recordMeasureBlock, recordMeasureBlockError };
|
|
65
|
+
export { DocumentLoadPhase, HiddenEditorPhase, HiddenEditorStateReason, LayoutInstrumentation, LayoutPhase, LayoutRunReason, recordDocumentLoadPhase, recordHiddenEditorPhase, recordHiddenEditorStateCreate, recordHyphenationDictionaryError, recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayoutStart, recordMeasureBlock, recordMeasureBlockError };
|
|
@@ -25,6 +25,13 @@ function recordLayoutError(reason, error) {
|
|
|
25
25
|
reason
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
|
+
/** A dictionary failed to load; layout continues without hyphenating that language. */
|
|
29
|
+
function recordHyphenationDictionaryError(dictionary, error) {
|
|
30
|
+
globalThis.__folioLayoutInstrumentation?.onHyphenationDictionaryError?.({
|
|
31
|
+
dictionary,
|
|
32
|
+
message: error.message
|
|
33
|
+
});
|
|
34
|
+
}
|
|
28
35
|
function recordLayoutPhase(reason, phase, durationMs) {
|
|
29
36
|
globalThis.__folioLayoutInstrumentation?.onLayoutPhase?.({
|
|
30
37
|
durationMs,
|
|
@@ -49,4 +56,4 @@ function recordDocumentLoadPhase(phase, durationMs) {
|
|
|
49
56
|
});
|
|
50
57
|
}
|
|
51
58
|
//#endregion
|
|
52
|
-
export { recordDocumentLoadPhase, recordHiddenEditorPhase, recordHiddenEditorStateCreate, recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayoutStart, recordMeasureBlock, recordMeasureBlockError };
|
|
59
|
+
export { recordDocumentLoadPhase, recordHiddenEditorPhase, recordHiddenEditorStateCreate, recordHyphenationDictionaryError, recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayoutStart, recordMeasureBlock, recordMeasureBlockError };
|