@stll/folio-core 0.32.1 → 0.33.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/__fixtures__/paragraphs.d.ts +17 -0
- package/dist/ai-edits/__fixtures__/paragraphs.js +33 -0
- package/dist/ai-edits/apply.d.ts +49 -3
- package/dist/ai-edits/apply.js +692 -75
- package/dist/ai-edits/blockRange.d.ts +7 -3
- package/dist/ai-edits/blockRange.js +14 -6
- package/dist/ai-edits/headless.d.ts +39 -5
- package/dist/ai-edits/headless.js +76 -17
- package/dist/ai-edits/index.d.ts +6 -6
- package/dist/ai-edits/index.js +3 -3
- package/dist/ai-edits/read.d.ts +4 -0
- package/dist/ai-edits/read.js +30 -6
- package/dist/ai-edits/scoped-reading.js +4 -3
- package/dist/ai-edits/snapshot.d.ts +42 -2
- package/dist/ai-edits/snapshot.js +127 -62
- package/dist/ai-edits/table-row-column-mutations.d.ts +24 -1
- package/dist/ai-edits/table-row-column-mutations.js +98 -6
- package/dist/ai-edits/table-targets.d.ts +12 -3
- package/dist/ai-edits/table-targets.js +15 -5
- package/dist/ai-edits/types.d.ts +235 -7
- package/dist/ai-edits/word-diff.d.ts +54 -11
- package/dist/ai-edits/word-diff.js +221 -61
- package/dist/compare/__fixtures__/body-sequence.d.ts +33 -0
- package/dist/compare/__fixtures__/body-sequence.js +67 -0
- package/dist/compare/__fixtures__/nested-table.d.ts +16 -0
- package/dist/compare/__fixtures__/nested-table.js +50 -0
- package/dist/compare/__fixtures__/numbered-list.d.ts +34 -0
- package/dist/compare/__fixtures__/numbered-list.js +85 -0
- package/dist/compare/column-alignment.d.ts +27 -0
- package/dist/compare/column-alignment.js +162 -0
- package/dist/compare/compare.d.ts +107 -0
- package/dist/compare/compare.js +406 -0
- package/dist/compare/formatting.d.ts +29 -0
- package/dist/compare/formatting.js +84 -0
- package/dist/compare/plan.d.ts +22 -0
- package/dist/compare/plan.js +1059 -0
- package/dist/compare/reproducible-package.d.ts +17 -0
- package/dist/compare/reproducible-package.js +30 -0
- package/dist/compare/scenario.d.ts +77 -0
- package/dist/compare/scenario.js +263 -0
- package/dist/compare/types.d.ts +282 -0
- package/dist/compare/types.js +32 -0
- package/dist/compare/verification.d.ts +55 -0
- package/dist/compare/verification.js +146 -0
- package/dist/compat/eigenpal.d.ts +9 -6
- package/dist/compat/eigenpal.js +6 -3
- package/dist/controller/layoutPipeline.d.ts +13 -0
- package/dist/controller/layoutPipeline.js +15 -1
- package/dist/display-list/build/buildContext.d.ts +39 -0
- package/dist/display-list/build/buildContext.js +31 -0
- package/dist/display-list/build/buildDisplayList.d.ts +79 -0
- package/dist/display-list/build/buildDisplayList.js +283 -0
- package/dist/display-list/build/colors.d.ts +20 -0
- package/dist/display-list/build/colors.js +136 -0
- package/dist/display-list/build/floatingImages.d.ts +24 -0
- package/dist/display-list/build/floatingImages.js +41 -0
- package/dist/display-list/build/fontTable.d.ts +31 -0
- package/dist/display-list/build/fontTable.js +97 -0
- package/dist/display-list/build/furniture.d.ts +86 -0
- package/dist/display-list/build/furniture.js +98 -0
- package/dist/display-list/build/glyphs.d.ts +55 -0
- package/dist/display-list/build/glyphs.js +103 -0
- package/dist/display-list/build/headerFooterPrimitives.d.ts +17 -0
- package/dist/display-list/build/headerFooterPrimitives.js +40 -0
- package/dist/display-list/build/imagePrimitives.d.ts +35 -0
- package/dist/display-list/build/imagePrimitives.js +264 -0
- package/dist/display-list/build/pageBorderPrimitives.d.ts +23 -0
- package/dist/display-list/build/pageBorderPrimitives.js +111 -0
- package/dist/display-list/build/pageFurniture.d.ts +35 -0
- package/dist/display-list/build/pageFurniture.js +141 -0
- package/dist/display-list/build/paragraphPrimitives.d.ts +19 -0
- package/dist/display-list/build/paragraphPrimitives.js +819 -0
- package/dist/display-list/build/regions.d.ts +46 -0
- package/dist/display-list/build/regions.js +56 -0
- package/dist/display-list/build/storyPrimitives.d.ts +29 -0
- package/dist/display-list/build/storyPrimitives.js +279 -0
- package/dist/display-list/build/strokes.d.ts +19 -0
- package/dist/display-list/build/strokes.js +78 -0
- package/dist/display-list/build/tablePrimitives.d.ts +38 -0
- package/dist/display-list/build/tablePrimitives.js +409 -0
- package/dist/display-list/build/textBoxPrimitives.d.ts +14 -0
- package/dist/display-list/build/textBoxPrimitives.js +129 -0
- package/dist/display-list/build/textDecorations.d.ts +29 -0
- package/dist/display-list/build/textDecorations.js +29 -0
- package/dist/display-list/build/unsupported.d.ts +57 -0
- package/dist/display-list/build/unsupported.js +0 -0
- package/dist/display-list/build/watermarkPrimitives.d.ts +15 -0
- package/dist/display-list/build/watermarkPrimitives.js +128 -0
- package/dist/display-list/dom/renderDisplayListToDom.d.ts +26 -0
- package/dist/display-list/dom/renderDisplayListToDom.js +620 -0
- package/dist/display-list/editor/displayListPagePainter.d.ts +22 -0
- package/dist/display-list/editor/displayListPagePainter.js +63 -0
- package/dist/display-list/editor/pageRenderer.d.ts +24 -0
- package/dist/display-list/editor/pageRenderer.js +36 -0
- package/dist/display-list/primitives.d.ts +95 -0
- package/dist/display-list/primitives.js +127 -0
- package/dist/display-list/types.d.ts +472 -0
- package/dist/display-list/types.js +0 -0
- package/dist/document-operations.d.ts +42 -9
- package/dist/document-operations.js +171 -16
- package/dist/document-stories.d.ts +16 -0
- package/dist/document-stories.js +48 -4
- package/dist/docx/packageParts.d.ts +35 -0
- package/dist/docx/packageParts.js +120 -0
- package/dist/docx/paragraphParser.js +22 -22
- package/dist/docx/paragraphTraversal.js +1 -1
- package/dist/docx/renderedPageBreakNormalization.js +3 -1
- package/dist/docx/revisionIdNormalization.d.ts +13 -0
- package/dist/docx/revisionIdNormalization.js +103 -0
- package/dist/docx/rezip.js +26 -17
- package/dist/docx/selectiveSave.js +2 -2
- package/dist/docx/serializer/commentSerializer.js +6 -1
- package/dist/docx/serializer/paragraphSerializer.js +33 -4
- package/dist/docx/serializer/runSerializer.js +11 -10
- package/dist/docx/serializer/tableSerializer.js +2 -1
- package/dist/docx/server/applyDocxXmlPatchProposal.js +1 -1
- package/dist/docx/server/createBilingualDocx.js +3 -2
- package/dist/docx/streamingXmlParser.d.ts +13 -1
- package/dist/docx/streamingXmlParser.js +49 -11
- package/dist/docx/unzip.d.ts +1 -2
- package/dist/docx/unzip.js +25 -6
- package/dist/docx/xmlParser.d.ts +3 -1
- package/dist/docx/xmlParser.js +33 -27
- package/dist/export-pdf.d.ts +43 -0
- package/dist/export-pdf.js +98 -0
- package/dist/fonts/headlessMeasure.d.ts +76 -0
- package/dist/fonts/headlessMeasure.js +0 -0
- package/dist/fonts/sfnt/parse.d.ts +51 -0
- package/dist/fonts/sfnt/parse.js +525 -0
- package/dist/fonts/sfnt/subset.d.ts +20 -0
- package/dist/fonts/sfnt/subset.js +350 -0
- package/dist/fonts/sfnt/tables.d.ts +88 -0
- package/dist/fonts/sfnt/tables.js +131 -0
- package/dist/fonts/sfnt/woff.d.ts +14 -0
- package/dist/fonts/sfnt/woff.js +163 -0
- package/dist/generated/text_shaper.js +324 -0
- package/dist/generated/text_shaper_bg.wasm +0 -0
- package/dist/headless-layout.d.ts +75 -0
- package/dist/headless-layout.js +350 -0
- package/dist/index.d.ts +9 -6
- package/dist/index.js +6 -3
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +2 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +3 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +2 -0
- package/dist/layout-engine/measure/advanceComposition.d.ts +62 -0
- package/dist/layout-engine/measure/advanceComposition.js +148 -0
- package/dist/layout-engine/measure/cache.d.ts +2 -0
- package/dist/layout-engine/measure/measureContainer.js +13 -0
- package/dist/layout-engine/measure/measureParagraph.js +1 -2
- package/dist/layout-engine/measure/measureTypes.d.ts +12 -0
- package/dist/layout-engine/measure/tableInlinePlacement.d.ts +3 -2
- package/dist/layout-engine/measure/tableInlinePlacement.js +14 -1
- package/dist/layout-engine/tableIndentCompatibility.d.ts +5 -0
- package/dist/layout-engine/tableIndentCompatibility.js +15 -0
- package/dist/layout-engine/types.d.ts +8 -0
- package/dist/layout-painter/renderPage.d.ts +29 -1
- package/dist/layout-painter/renderPage.js +47 -19
- package/dist/layout-painter/renderParagraph.d.ts +21 -2
- package/dist/layout-painter/renderParagraph.js +1 -1
- package/dist/layout-painter/renderTable.js +37 -4
- package/dist/managers/editorShortcuts.d.ts +33 -1
- package/dist/managers/editorShortcuts.js +20 -1
- package/dist/markdown/renderRuns.js +7 -2
- package/dist/markdown/renderTable.js +5 -1
- package/dist/model.d.ts +3 -3
- package/dist/model.js +2 -2
- package/dist/pdf/contentStream.d.ts +73 -0
- package/dist/pdf/contentStream.js +143 -0
- package/dist/pdf/fonts.d.ts +96 -0
- package/dist/pdf/fonts.js +593 -0
- package/dist/pdf/images.d.ts +28 -0
- package/dist/pdf/images.js +439 -0
- package/dist/pdf/objects.d.ts +93 -0
- package/dist/pdf/objects.js +237 -0
- package/dist/pdf/pageSpace.d.ts +43 -0
- package/dist/pdf/pageSpace.js +57 -0
- package/dist/pdf/paint.d.ts +32 -0
- package/dist/pdf/paint.js +442 -0
- package/dist/pdf/writePdf.d.ts +56 -0
- package/dist/pdf/writePdf.js +345 -0
- package/dist/prosemirror/commands/comments.js +91 -6
- package/dist/prosemirror/conversion/fromProseDoc.js +41 -7
- package/dist/prosemirror/conversion/toProseDoc.js +41 -4
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +15 -2
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +35 -6
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +2 -2
- package/dist/prosemirror/extensions/features/pasteCleanup.js +4 -3
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.d.ts +3 -1
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +5 -3
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -1
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +9 -3
- package/dist/prosemirror/extensions/nodes/TableExtension.js +56 -39
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +3 -1
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +5 -3
- package/dist/prosemirror/plugins/suggestionMode.js +1 -0
- package/dist/prosemirror/revisionCarriers.js +19 -2
- package/dist/prosemirror/utils/extractTrackedChanges.d.ts +2 -2
- package/dist/prosemirror/utils/extractTrackedChanges.js +59 -23
- package/dist/prosemirror/validation.js +55 -27
- package/dist/prosemirror/zeroWidthAnchors.d.ts +10 -0
- package/dist/prosemirror/zeroWidthAnchors.js +23 -0
- package/dist/redline.js +12 -79
- package/dist/server.d.ts +4 -4
- package/dist/server.js +2 -2
- package/dist/shaping/placeRun.d.ts +51 -0
- package/dist/shaping/placeRun.js +84 -0
- package/dist/shaping/shaper.d.ts +92 -0
- package/dist/shaping/shaper.js +102 -0
- package/dist/types/block-id.d.ts +18 -2
- package/dist/types/block-id.js +49 -5
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/clipboard.js +4 -3
- package/dist/utils/fontResolver.js +183 -0
- package/dist/utils/htmlComments.d.ts +17 -0
- package/dist/utils/htmlComments.js +22 -0
- package/dist/utils/scriptSegments.d.ts +12 -1
- package/dist/utils/scriptSegments.js +17 -1
- package/dist/version-comparison.d.ts +1 -1
- package/package.json +7 -3
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { BlockId } from "../../layout-engine/types.js";
|
|
2
|
+
import { DisplayHitRegion, DisplayHitRegionKind, DisplayHitRegionModel, DisplayPrimitive, DisplayRect, DisplayStoryRef } from "../types.js";
|
|
3
|
+
//#region src/display-list/build/regions.d.ts
|
|
4
|
+
type RegionDescriptor = {
|
|
5
|
+
readonly kind: DisplayHitRegionKind;
|
|
6
|
+
readonly rect: DisplayRect;
|
|
7
|
+
readonly model?: DisplayHitRegionModel;
|
|
8
|
+
};
|
|
9
|
+
type PageComposer = {
|
|
10
|
+
/** Append primitives to the page, in paint order. */
|
|
11
|
+
readonly push: (primitives: readonly DisplayPrimitive[]) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Everything `paint` appends belongs to this region. Regions opened inside
|
|
14
|
+
* `paint` become its children, so the tree is the nesting of the walk.
|
|
15
|
+
*/
|
|
16
|
+
readonly region: (descriptor: RegionDescriptor, paint: () => void) => void;
|
|
17
|
+
readonly primitives: () => readonly DisplayPrimitive[];
|
|
18
|
+
readonly regions: () => readonly DisplayHitRegion[];
|
|
19
|
+
};
|
|
20
|
+
declare const createPageComposer: () => PageComposer;
|
|
21
|
+
/**
|
|
22
|
+
* The region a whole block occupies, wherever it is painted.
|
|
23
|
+
*
|
|
24
|
+
* A body fragment, a picture inside a header, a text box inside a cell: each is
|
|
25
|
+
* one block at one place, and a surface asks the same questions of all of them.
|
|
26
|
+
* Taking the box and the range from the same fragment the painting uses is what
|
|
27
|
+
* keeps the answer the one that was drawn.
|
|
28
|
+
*/
|
|
29
|
+
type BlockRegionOptions = {
|
|
30
|
+
readonly fragment: {
|
|
31
|
+
readonly blockId: BlockId;
|
|
32
|
+
readonly x: number;
|
|
33
|
+
readonly y: number;
|
|
34
|
+
readonly width: number;
|
|
35
|
+
readonly height: number;
|
|
36
|
+
readonly pmStart?: number;
|
|
37
|
+
readonly pmEnd?: number;
|
|
38
|
+
};
|
|
39
|
+
readonly kind: DisplayHitRegionKind;
|
|
40
|
+
readonly context: {
|
|
41
|
+
readonly story: DisplayStoryRef;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
declare const blockRegion: ({ fragment, kind, context }: BlockRegionOptions) => RegionDescriptor;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { PageComposer, RegionDescriptor, blockRegion, createPageComposer };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//#region src/display-list/build/regions.ts
|
|
2
|
+
const createPageComposer = () => {
|
|
3
|
+
const primitives = [];
|
|
4
|
+
const roots = [];
|
|
5
|
+
const open = [];
|
|
6
|
+
const push = (added) => {
|
|
7
|
+
primitives.push(...added);
|
|
8
|
+
};
|
|
9
|
+
const region = (descriptor, paint) => {
|
|
10
|
+
const entry = {
|
|
11
|
+
descriptor,
|
|
12
|
+
from: primitives.length,
|
|
13
|
+
children: []
|
|
14
|
+
};
|
|
15
|
+
open.push(entry);
|
|
16
|
+
try {
|
|
17
|
+
paint();
|
|
18
|
+
} finally {
|
|
19
|
+
open.pop();
|
|
20
|
+
}
|
|
21
|
+
const closed = {
|
|
22
|
+
kind: descriptor.kind,
|
|
23
|
+
rect: descriptor.rect,
|
|
24
|
+
from: entry.from,
|
|
25
|
+
to: primitives.length,
|
|
26
|
+
children: entry.children,
|
|
27
|
+
...descriptor.model === void 0 ? {} : { model: descriptor.model }
|
|
28
|
+
};
|
|
29
|
+
(open.at(-1)?.children ?? roots).push(closed);
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
push,
|
|
33
|
+
region,
|
|
34
|
+
primitives: () => primitives,
|
|
35
|
+
regions: () => roots
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const blockRegion = ({ fragment, kind, context }) => ({
|
|
39
|
+
kind,
|
|
40
|
+
rect: {
|
|
41
|
+
xPx: fragment.x,
|
|
42
|
+
yPx: fragment.y,
|
|
43
|
+
widthPx: fragment.width,
|
|
44
|
+
heightPx: fragment.height
|
|
45
|
+
},
|
|
46
|
+
model: {
|
|
47
|
+
blockId: String(fragment.blockId),
|
|
48
|
+
...fragment.pmStart === void 0 || fragment.pmEnd === void 0 ? {} : { pmRange: {
|
|
49
|
+
start: fragment.pmStart,
|
|
50
|
+
end: fragment.pmEnd,
|
|
51
|
+
story: context.story
|
|
52
|
+
} }
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
//#endregion
|
|
56
|
+
export { blockRegion, createPageComposer };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FlowBlock, Measure } from "../../layout-engine/types.js";
|
|
2
|
+
import { BuildContext } from "./buildContext.js";
|
|
3
|
+
import { PageComposer } from "./regions.js";
|
|
4
|
+
//#region src/display-list/build/storyPrimitives.d.ts
|
|
5
|
+
type PaintStoryOptions = {
|
|
6
|
+
readonly composer: PageComposer;
|
|
7
|
+
readonly blocks: readonly FlowBlock[];
|
|
8
|
+
readonly measures: readonly Measure[];
|
|
9
|
+
/** Page-absolute origin of the story's own content box. */
|
|
10
|
+
readonly xPx: number;
|
|
11
|
+
readonly yPx: number;
|
|
12
|
+
readonly widthPx: number;
|
|
13
|
+
readonly context: BuildContext;
|
|
14
|
+
readonly label: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A footnote body: every block stacks by its measured height, which is the
|
|
18
|
+
* height the paginator reserved the band from.
|
|
19
|
+
*/
|
|
20
|
+
declare const paintFootnoteBlocks: ({ composer, blocks, measures, xPx, yPx, widthPx, context, label }: PaintStoryOptions) => void;
|
|
21
|
+
/**
|
|
22
|
+
* A header or footer story. Blocks that Word takes out of the flow (a floating
|
|
23
|
+
* table, an anchored image, a positioned text box) contribute no height, and
|
|
24
|
+
* they are reported rather than painted: their position resolves against page
|
|
25
|
+
* and margin anchors the display list producer does not carry.
|
|
26
|
+
*/
|
|
27
|
+
declare const paintHeaderFooterBlocks: ({ composer, blocks, measures, xPx, yPx, widthPx, context, label }: PaintStoryOptions) => void;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { PaintStoryOptions, paintFootnoteBlocks, paintHeaderFooterBlocks };
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { isFloatingImageRun, isFloatingTextBoxBlock } from "../../layout-engine/types.js";
|
|
2
|
+
import { HIT_REGION_KINDS } from "../primitives.js";
|
|
3
|
+
import { paintImageFragment } from "./imagePrimitives.js";
|
|
4
|
+
import { paintParagraphFragment } from "./paragraphPrimitives.js";
|
|
5
|
+
import { blockRegion } from "./regions.js";
|
|
6
|
+
import { paintTableFragment } from "./tablePrimitives.js";
|
|
7
|
+
import { paintTextBoxFragment } from "./textBoxPrimitives.js";
|
|
8
|
+
import { UNSUPPORTED_CONSTRUCT } from "./unsupported.js";
|
|
9
|
+
//#region src/display-list/build/storyPrimitives.ts
|
|
10
|
+
/**
|
|
11
|
+
* Stacked story blocks: the header, the footer and a footnote body.
|
|
12
|
+
*
|
|
13
|
+
* These three are not fragments. The layout engine paginates the body only, so
|
|
14
|
+
* a story arrives as a `(blocks, measures)` pair already measured against its
|
|
15
|
+
* own width, and whoever paints it stacks the blocks itself. Every block is
|
|
16
|
+
* then handed to the *same* paragraph, table, image and text-box builders the
|
|
17
|
+
* body uses: a second text painter for headers is exactly how a header comes to
|
|
18
|
+
* disagree with the body about a tab stop or a justified space.
|
|
19
|
+
*
|
|
20
|
+
* The stacking rules differ between the two callers and both are the painter's:
|
|
21
|
+
* `renderFootnoteContent` advances by the measured height of every block, while
|
|
22
|
+
* `renderHeaderFooterContent` honours explicit `w:spacing w:before`, offsets an
|
|
23
|
+
* inline table by `w:jc`/`w:tblInd`, and lets a floating or page-anchored
|
|
24
|
+
* object out of the flow entirely.
|
|
25
|
+
*/
|
|
26
|
+
/** Mirrors `isPositionedHeaderFooterTextBoxBlock`: an explicit display mode keeps a box in the flow. */
|
|
27
|
+
const isPositionedTextBox = (block) => block.displayMode !== "block" && block.displayMode !== "inline" && isFloatingTextBoxBlock(block);
|
|
28
|
+
const isAnchoredImage = (block) => block.anchor?.isAnchored === true;
|
|
29
|
+
/** `w:jc` / `w:tblInd` for an inline story table, as the body's `desiredX` resolves them. */
|
|
30
|
+
const inlineTableOffsetPx = (block, tableWidthPx, widthPx) => {
|
|
31
|
+
if (block.justification === "center") return (widthPx - tableWidthPx) / 2;
|
|
32
|
+
if (block.justification === "right") return widthPx - tableWidthPx;
|
|
33
|
+
return block.indent ?? 0;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Explicit `w:spacing w:before` only. `normalizeHeaderFooterMeasureBlocks`
|
|
37
|
+
* strips style-inherited spacing from the measurement copy, so offsetting by an
|
|
38
|
+
* inherited value would push the first line below the space its own measure
|
|
39
|
+
* reserved and every following block with it.
|
|
40
|
+
*/
|
|
41
|
+
const explicitSpaceBeforePx = (block) => block.attrs?.spacingExplicit?.before === true ? block.attrs.spacing?.before ?? 0 : 0;
|
|
42
|
+
/** One block of a story, painted at an absolute page position. */
|
|
43
|
+
const paintStoryBlock = ({ composer, block, measure, xPx, yPx, widthPx, context, label, construct }) => {
|
|
44
|
+
if (block.kind === "paragraph" && measure.kind === "paragraph") {
|
|
45
|
+
const fragment = {
|
|
46
|
+
kind: "paragraph",
|
|
47
|
+
blockId: block.id,
|
|
48
|
+
x: xPx,
|
|
49
|
+
y: yPx,
|
|
50
|
+
width: widthPx,
|
|
51
|
+
height: measure.totalHeight,
|
|
52
|
+
fromLine: 0,
|
|
53
|
+
toLine: measure.lines.length
|
|
54
|
+
};
|
|
55
|
+
composer.region(blockRegion({
|
|
56
|
+
fragment,
|
|
57
|
+
kind: HIT_REGION_KINDS.paragraph,
|
|
58
|
+
context
|
|
59
|
+
}), () => {
|
|
60
|
+
paintParagraphFragment({
|
|
61
|
+
fragment,
|
|
62
|
+
block,
|
|
63
|
+
measure,
|
|
64
|
+
context,
|
|
65
|
+
composer
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (block.kind === "table" && measure.kind === "table") {
|
|
71
|
+
const fragment = {
|
|
72
|
+
kind: "table",
|
|
73
|
+
blockId: block.id,
|
|
74
|
+
x: xPx,
|
|
75
|
+
y: yPx,
|
|
76
|
+
width: measure.totalWidth,
|
|
77
|
+
height: measure.totalHeight,
|
|
78
|
+
fromRow: 0,
|
|
79
|
+
toRow: block.rows.length
|
|
80
|
+
};
|
|
81
|
+
composer.region(blockRegion({
|
|
82
|
+
fragment,
|
|
83
|
+
kind: HIT_REGION_KINDS.table,
|
|
84
|
+
context
|
|
85
|
+
}), () => {
|
|
86
|
+
paintTableFragment({
|
|
87
|
+
fragment,
|
|
88
|
+
block,
|
|
89
|
+
measure,
|
|
90
|
+
context,
|
|
91
|
+
composer,
|
|
92
|
+
paintTextBox: paintTextBoxFragment
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (block.kind === "image" && measure.kind === "image") {
|
|
98
|
+
const fragment = {
|
|
99
|
+
kind: "image",
|
|
100
|
+
blockId: block.id,
|
|
101
|
+
x: xPx,
|
|
102
|
+
y: yPx,
|
|
103
|
+
width: measure.width,
|
|
104
|
+
height: measure.height
|
|
105
|
+
};
|
|
106
|
+
composer.region(blockRegion({
|
|
107
|
+
fragment,
|
|
108
|
+
kind: HIT_REGION_KINDS.image,
|
|
109
|
+
context
|
|
110
|
+
}), () => {
|
|
111
|
+
composer.push(paintImageFragment(fragment, block, context));
|
|
112
|
+
});
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (block.kind === "textBox" && measure.kind === "textBox") {
|
|
116
|
+
const fragment = {
|
|
117
|
+
kind: "textBox",
|
|
118
|
+
blockId: block.id,
|
|
119
|
+
x: xPx,
|
|
120
|
+
y: yPx,
|
|
121
|
+
width: measure.width,
|
|
122
|
+
height: measure.height
|
|
123
|
+
};
|
|
124
|
+
composer.region(blockRegion({
|
|
125
|
+
fragment,
|
|
126
|
+
kind: HIT_REGION_KINDS.textBox,
|
|
127
|
+
context
|
|
128
|
+
}), () => {
|
|
129
|
+
paintTextBoxFragment({
|
|
130
|
+
composer,
|
|
131
|
+
fragment,
|
|
132
|
+
block,
|
|
133
|
+
measure,
|
|
134
|
+
context
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
context.unsupported.report(construct, context.pageIndex, `${label}: a ${block.kind} block with a ${measure.kind} measure is not painted`);
|
|
140
|
+
};
|
|
141
|
+
const measuredHeightPx = (measure) => {
|
|
142
|
+
switch (measure.kind) {
|
|
143
|
+
case "paragraph":
|
|
144
|
+
case "table": return measure.totalHeight;
|
|
145
|
+
case "image":
|
|
146
|
+
case "textBox": return measure.height;
|
|
147
|
+
case "sectionBreak":
|
|
148
|
+
case "pageBreak":
|
|
149
|
+
case "columnBreak": return 0;
|
|
150
|
+
default: return 0;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* A footnote body: every block stacks by its measured height, which is the
|
|
155
|
+
* height the paginator reserved the band from.
|
|
156
|
+
*/
|
|
157
|
+
const paintFootnoteBlocks = ({ composer, blocks, measures, xPx, yPx, widthPx, context, label }) => {
|
|
158
|
+
let cursorYPx = yPx;
|
|
159
|
+
for (const [index, block] of blocks.entries()) {
|
|
160
|
+
const measure = measures[index];
|
|
161
|
+
if (measure === void 0) {
|
|
162
|
+
context.unsupported.report(UNSUPPORTED_CONSTRUCT.missingBlock, context.pageIndex, `${label}: block ${String(block.id)} has no measure`);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
paintStoryBlock({
|
|
166
|
+
composer,
|
|
167
|
+
block,
|
|
168
|
+
measure,
|
|
169
|
+
xPx,
|
|
170
|
+
yPx: cursorYPx,
|
|
171
|
+
widthPx,
|
|
172
|
+
context,
|
|
173
|
+
label,
|
|
174
|
+
construct: UNSUPPORTED_CONSTRUCT.footnoteContent
|
|
175
|
+
});
|
|
176
|
+
cursorYPx += measuredHeightPx(measure);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* A header or footer story. Blocks that Word takes out of the flow (a floating
|
|
181
|
+
* table, an anchored image, a positioned text box) contribute no height, and
|
|
182
|
+
* they are reported rather than painted: their position resolves against page
|
|
183
|
+
* and margin anchors the display list producer does not carry.
|
|
184
|
+
*/
|
|
185
|
+
const paintHeaderFooterBlocks = ({ composer, blocks, measures, xPx, yPx, widthPx, context, label }) => {
|
|
186
|
+
let cursorYPx = yPx;
|
|
187
|
+
const reportOutOfFlow = (detail) => {
|
|
188
|
+
context.unsupported.report(UNSUPPORTED_CONSTRUCT.headerFooterContent, context.pageIndex, `${label}: ${detail}`);
|
|
189
|
+
};
|
|
190
|
+
for (const [index, block] of blocks.entries()) {
|
|
191
|
+
const measure = measures[index];
|
|
192
|
+
if (measure === void 0) {
|
|
193
|
+
context.unsupported.report(UNSUPPORTED_CONSTRUCT.missingBlock, context.pageIndex, `${label}: block ${String(block.id)} has no measure`);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
switch (block.kind) {
|
|
197
|
+
case "paragraph":
|
|
198
|
+
if (measure.kind !== "paragraph") break;
|
|
199
|
+
if (block.runs.some((run) => run.kind === "image" && (isFloatingImageRun(run) || run.position !== void 0))) reportOutOfFlow(`paragraph ${String(block.id)} anchors a floating picture, which resolves against page and margin anchors the display list does not carry`);
|
|
200
|
+
paintStoryBlock({
|
|
201
|
+
composer,
|
|
202
|
+
block,
|
|
203
|
+
measure,
|
|
204
|
+
xPx,
|
|
205
|
+
yPx: cursorYPx + explicitSpaceBeforePx(block),
|
|
206
|
+
widthPx,
|
|
207
|
+
context,
|
|
208
|
+
label,
|
|
209
|
+
construct: UNSUPPORTED_CONSTRUCT.headerFooterContent
|
|
210
|
+
});
|
|
211
|
+
cursorYPx += measure.totalHeight;
|
|
212
|
+
continue;
|
|
213
|
+
case "table":
|
|
214
|
+
if (measure.kind !== "table") break;
|
|
215
|
+
if (block.floating) {
|
|
216
|
+
reportOutOfFlow(`table ${String(block.id)} is floating (w:tblpPr) and is not painted`);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
paintStoryBlock({
|
|
220
|
+
composer,
|
|
221
|
+
block,
|
|
222
|
+
measure,
|
|
223
|
+
xPx: xPx + inlineTableOffsetPx(block, measure.totalWidth, widthPx),
|
|
224
|
+
yPx: cursorYPx,
|
|
225
|
+
widthPx,
|
|
226
|
+
context,
|
|
227
|
+
label,
|
|
228
|
+
construct: UNSUPPORTED_CONSTRUCT.headerFooterContent
|
|
229
|
+
});
|
|
230
|
+
cursorYPx += measure.totalHeight;
|
|
231
|
+
continue;
|
|
232
|
+
case "image":
|
|
233
|
+
if (measure.kind !== "image") break;
|
|
234
|
+
if (isAnchoredImage(block)) {
|
|
235
|
+
reportOutOfFlow(`image ${String(block.id)} is anchored and is not painted`);
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
paintStoryBlock({
|
|
239
|
+
composer,
|
|
240
|
+
block,
|
|
241
|
+
measure,
|
|
242
|
+
xPx,
|
|
243
|
+
yPx: cursorYPx,
|
|
244
|
+
widthPx,
|
|
245
|
+
context,
|
|
246
|
+
label,
|
|
247
|
+
construct: UNSUPPORTED_CONSTRUCT.headerFooterContent
|
|
248
|
+
});
|
|
249
|
+
cursorYPx += measure.height;
|
|
250
|
+
continue;
|
|
251
|
+
case "textBox":
|
|
252
|
+
if (measure.kind !== "textBox") break;
|
|
253
|
+
if (isPositionedTextBox(block)) {
|
|
254
|
+
reportOutOfFlow(`text box ${String(block.id)} is positioned and is not painted`);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
paintStoryBlock({
|
|
258
|
+
composer,
|
|
259
|
+
block,
|
|
260
|
+
measure,
|
|
261
|
+
xPx,
|
|
262
|
+
yPx: cursorYPx,
|
|
263
|
+
widthPx,
|
|
264
|
+
context,
|
|
265
|
+
label,
|
|
266
|
+
construct: UNSUPPORTED_CONSTRUCT.headerFooterContent
|
|
267
|
+
});
|
|
268
|
+
cursorYPx += measure.height;
|
|
269
|
+
continue;
|
|
270
|
+
case "pageBreak":
|
|
271
|
+
case "columnBreak":
|
|
272
|
+
case "sectionBreak": continue;
|
|
273
|
+
default: continue;
|
|
274
|
+
}
|
|
275
|
+
context.unsupported.report(UNSUPPORTED_CONSTRUCT.measureMismatch, context.pageIndex, `${label}: block ${String(block.id)} is a ${block.kind} with a ${measure.kind} measure`);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
//#endregion
|
|
279
|
+
export { paintFootnoteBlocks, paintHeaderFooterBlocks };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BorderStyle } from "../../layout-engine/types.js";
|
|
2
|
+
import { DisplayStroke, DisplayStrokePattern } from "../types.js";
|
|
3
|
+
//#region src/display-list/build/strokes.d.ts
|
|
4
|
+
type BorderInput = Pick<BorderStyle, "color" | "style" | "width">;
|
|
5
|
+
type ResolveStrokeResult = {
|
|
6
|
+
readonly stroke?: DisplayStroke;
|
|
7
|
+
/** The authored colour, when it could not be parsed. Report it, do not paint. */
|
|
8
|
+
readonly unresolvedColor?: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Turn an authored border into a paintable stroke. `undefined` stroke means
|
|
12
|
+
* "draw nothing": an explicit `none`/`nil` style, a non-positive width, or a
|
|
13
|
+
* colour this producer cannot resolve.
|
|
14
|
+
*/
|
|
15
|
+
declare const resolveBorderStroke: (border: BorderInput) => ResolveStrokeResult;
|
|
16
|
+
/** CSS `text-decoration-style` → the display list's stroke patterns. */
|
|
17
|
+
declare const decorationPatternForStyle: (style: string | undefined) => DisplayStrokePattern;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { ResolveStrokeResult, decorationPatternForStyle, resolveBorderStroke };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { resolveCssBorderStroke } from "../../layout-painter/borderStroke.js";
|
|
2
|
+
import { parseDisplayColor } from "./colors.js";
|
|
3
|
+
//#region src/display-list/build/strokes.ts
|
|
4
|
+
/**
|
|
5
|
+
* Border and rule strokes.
|
|
6
|
+
*
|
|
7
|
+
* One deliberate divergence from `layout-painter/borderStroke.ts`: that helper
|
|
8
|
+
* encodes a sub-pixel border width as a `color-mix` alpha because CSS quantizes
|
|
9
|
+
* a fractional border to one device pixel. A display list has no device pixel,
|
|
10
|
+
* and a PDF strokes 0.4pt natively, so the authored fractional width and the
|
|
11
|
+
* plain colour survive here. Everything else (colour/style/width defaults) is
|
|
12
|
+
* taken from the painter's helper so the two cannot drift.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* CSS `border-style` and the raw OOXML `w:val` names both reach
|
|
16
|
+
* `BorderStyle.style` (the bridge maps most, `renderParagraph` maps the rest),
|
|
17
|
+
* so both vocabularies are resolved here. Everything decorative that folio does
|
|
18
|
+
* not draw degrades to a plain line, matching how Word degrades on a platform
|
|
19
|
+
* without the specialised glyphs.
|
|
20
|
+
*/
|
|
21
|
+
const STROKE_PATTERN_BY_STYLE = {
|
|
22
|
+
none: "none",
|
|
23
|
+
nil: "none",
|
|
24
|
+
hidden: "none",
|
|
25
|
+
solid: "solid",
|
|
26
|
+
single: "solid",
|
|
27
|
+
thick: "solid",
|
|
28
|
+
inset: "solid",
|
|
29
|
+
outset: "solid",
|
|
30
|
+
ridge: "solid",
|
|
31
|
+
groove: "solid",
|
|
32
|
+
double: "double",
|
|
33
|
+
dotted: "dotted",
|
|
34
|
+
dotdash: "dashed",
|
|
35
|
+
dotdotdash: "dashed",
|
|
36
|
+
dashed: "dashed",
|
|
37
|
+
dash: "dashed",
|
|
38
|
+
dashsmallgap: "dashed",
|
|
39
|
+
dashlong: "dashed",
|
|
40
|
+
wavy: "wavy",
|
|
41
|
+
wave: "wavy",
|
|
42
|
+
wavydouble: "double"
|
|
43
|
+
};
|
|
44
|
+
const DEFAULT_PATTERN = "solid";
|
|
45
|
+
const strokePatternForStyle = (style) => {
|
|
46
|
+
if (style === void 0) return DEFAULT_PATTERN;
|
|
47
|
+
return STROKE_PATTERN_BY_STYLE[style.trim().toLowerCase()] ?? DEFAULT_PATTERN;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Turn an authored border into a paintable stroke. `undefined` stroke means
|
|
51
|
+
* "draw nothing": an explicit `none`/`nil` style, a non-positive width, or a
|
|
52
|
+
* colour this producer cannot resolve.
|
|
53
|
+
*/
|
|
54
|
+
const resolveBorderStroke = (border) => {
|
|
55
|
+
const pattern = strokePatternForStyle(border.style);
|
|
56
|
+
if (pattern === "none") return {};
|
|
57
|
+
const css = resolveCssBorderStroke(border);
|
|
58
|
+
const isSubPixelEncoded = css.color.startsWith("color-mix");
|
|
59
|
+
const authoredWidth = border.width ?? css.width;
|
|
60
|
+
const thicknessPx = isSubPixelEncoded ? authoredWidth : css.width;
|
|
61
|
+
if (thicknessPx <= 0) return {};
|
|
62
|
+
const colorSource = isSubPixelEncoded ? border.color ?? "#000000" : css.color;
|
|
63
|
+
const color = parseDisplayColor(colorSource);
|
|
64
|
+
if (!color) return { unresolvedColor: colorSource };
|
|
65
|
+
return { stroke: {
|
|
66
|
+
color,
|
|
67
|
+
thicknessPx,
|
|
68
|
+
pattern
|
|
69
|
+
} };
|
|
70
|
+
};
|
|
71
|
+
/** CSS `text-decoration-style` → the display list's stroke patterns. */
|
|
72
|
+
const decorationPatternForStyle = (style) => {
|
|
73
|
+
if (style === void 0) return DEFAULT_PATTERN;
|
|
74
|
+
const pattern = STROKE_PATTERN_BY_STYLE[style.trim().toLowerCase()];
|
|
75
|
+
return pattern === void 0 || pattern === "none" ? DEFAULT_PATTERN : pattern;
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
78
|
+
export { decorationPatternForStyle, resolveBorderStroke };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { TableBlock, TableFragment, TableMeasure, TextBoxBlock, TextBoxFragment, TextBoxMeasure } from "../../layout-engine/types.js";
|
|
2
|
+
import { BuildContext } from "./buildContext.js";
|
|
3
|
+
import { PageComposer } from "./regions.js";
|
|
4
|
+
//#region src/display-list/build/tablePrimitives.d.ts
|
|
5
|
+
type PaintTextBox = (options: {
|
|
6
|
+
readonly composer: PageComposer;
|
|
7
|
+
readonly fragment: TextBoxFragment;
|
|
8
|
+
readonly block: TextBoxBlock;
|
|
9
|
+
readonly measure: TextBoxMeasure;
|
|
10
|
+
readonly context: BuildContext;
|
|
11
|
+
}) => void;
|
|
12
|
+
type TableBlockPaintOptions = {
|
|
13
|
+
readonly composer: PageComposer;
|
|
14
|
+
readonly block: TableBlock;
|
|
15
|
+
readonly measure: TableMeasure;
|
|
16
|
+
readonly xPx: number;
|
|
17
|
+
readonly yPx: number;
|
|
18
|
+
readonly context: BuildContext;
|
|
19
|
+
readonly paintTextBox: PaintTextBox;
|
|
20
|
+
};
|
|
21
|
+
/** A whole, unpaginated table: what a nested table inside a cell or box is. */
|
|
22
|
+
declare const paintTableBlock: ({ composer, block, measure, xPx, yPx, context, paintTextBox }: TableBlockPaintOptions) => void;
|
|
23
|
+
type TablePaintOptions = {
|
|
24
|
+
readonly composer: PageComposer;
|
|
25
|
+
readonly fragment: TableFragment;
|
|
26
|
+
readonly block: TableBlock;
|
|
27
|
+
readonly measure: TableMeasure;
|
|
28
|
+
readonly context: BuildContext;
|
|
29
|
+
readonly paintTextBox: PaintTextBox;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* A table fragment's primitives. A fragment that cuts a row mid-content wraps
|
|
33
|
+
* its rows in a `clipGroup` and starts them `topClip` px higher, which is what
|
|
34
|
+
* the painter's negative row-stack offset plus `overflow: hidden` does.
|
|
35
|
+
*/
|
|
36
|
+
declare const paintTableFragment: ({ composer, fragment, block, measure, context, paintTextBox }: TablePaintOptions) => void;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { TableBlockPaintOptions, TablePaintOptions, paintTableBlock, paintTableFragment };
|