@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,264 @@
|
|
|
1
|
+
import { parseRotationDegrees } from "../../utils/rotationBoundingBox.js";
|
|
2
|
+
import { sanitizeImageSrc } from "../../utils/sanitizeImageSrc.js";
|
|
3
|
+
import { resolveBorderStroke } from "./strokes.js";
|
|
4
|
+
import { UNSUPPORTED_CONSTRUCT } from "./unsupported.js";
|
|
5
|
+
import { Result } from "better-result";
|
|
6
|
+
//#region src/display-list/build/imagePrimitives.ts
|
|
7
|
+
/**
|
|
8
|
+
* Images: the source table, and the primitives an image draws.
|
|
9
|
+
*
|
|
10
|
+
* The display list carries raw bytes plus the format they are already in, so a
|
|
11
|
+
* backend never owns a codec. This module therefore decodes only far enough to
|
|
12
|
+
* fill `pixelWidth`/`pixelHeight` and to know PNG from JPEG. It transcodes
|
|
13
|
+
* nothing: a WMF, EMF, TIFF, SVG, GIF or BMP source is reported through
|
|
14
|
+
* `unsupported` and paints nothing, because a silently missing picture is worse
|
|
15
|
+
* than a named one.
|
|
16
|
+
*/
|
|
17
|
+
const DATA_URL_PATTERN = /^data:([^;,]*)(;base64)?,(.*)$/su;
|
|
18
|
+
/**
|
|
19
|
+
* `undefined` for a payload `atob` rejects: a malformed `data:` URL is a
|
|
20
|
+
* document the builder reports, not an exception that aborts the build.
|
|
21
|
+
*/
|
|
22
|
+
const decodeBase64 = (encoded) => {
|
|
23
|
+
const decoded = Result.try(() => atob(encoded));
|
|
24
|
+
if (decoded.isErr()) return;
|
|
25
|
+
const binary = decoded.value;
|
|
26
|
+
const bytes = new Uint8Array(binary.length);
|
|
27
|
+
for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
|
|
28
|
+
return bytes;
|
|
29
|
+
};
|
|
30
|
+
const readUint32BE = (bytes, offset) => bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3];
|
|
31
|
+
const readUint16BE = (bytes, offset) => bytes[offset] << 8 | bytes[offset + 1];
|
|
32
|
+
const startsWith = (bytes, signature) => bytes.length >= signature.length && signature.every((byte, index) => bytes[index] === byte);
|
|
33
|
+
const PNG_SIGNATURE = [
|
|
34
|
+
137,
|
|
35
|
+
80,
|
|
36
|
+
78,
|
|
37
|
+
71,
|
|
38
|
+
13,
|
|
39
|
+
10,
|
|
40
|
+
26,
|
|
41
|
+
10
|
|
42
|
+
];
|
|
43
|
+
const JPEG_SIGNATURE = [
|
|
44
|
+
255,
|
|
45
|
+
216,
|
|
46
|
+
255
|
|
47
|
+
];
|
|
48
|
+
/** PNG's IHDR is always the first chunk: 8-byte signature, 8-byte header, then w/h. */
|
|
49
|
+
const PNG_WIDTH_OFFSET = 16;
|
|
50
|
+
const decodePng = (bytes) => {
|
|
51
|
+
if (bytes.length < 24) return { reason: "PNG shorter than its IHDR chunk" };
|
|
52
|
+
return {
|
|
53
|
+
format: "png",
|
|
54
|
+
bytes,
|
|
55
|
+
pixelWidth: readUint32BE(bytes, PNG_WIDTH_OFFSET),
|
|
56
|
+
pixelHeight: readUint32BE(bytes, 20)
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Frame markers that carry the image dimensions. Every other `SOFn` code in the
|
|
61
|
+
* `0xC0..0xCF` block is a table or restart marker, not a frame header.
|
|
62
|
+
*/
|
|
63
|
+
const JPEG_FRAME_MARKERS = /* @__PURE__ */ new Set([
|
|
64
|
+
192,
|
|
65
|
+
193,
|
|
66
|
+
194,
|
|
67
|
+
195,
|
|
68
|
+
197,
|
|
69
|
+
198,
|
|
70
|
+
199,
|
|
71
|
+
201,
|
|
72
|
+
202,
|
|
73
|
+
203,
|
|
74
|
+
205,
|
|
75
|
+
206,
|
|
76
|
+
207
|
|
77
|
+
]);
|
|
78
|
+
const decodeJpeg = (bytes) => {
|
|
79
|
+
let offset = 2;
|
|
80
|
+
while (offset + 9 < bytes.length) {
|
|
81
|
+
if (bytes[offset] !== 255) {
|
|
82
|
+
offset += 1;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const marker = bytes[offset + 1];
|
|
86
|
+
if (JPEG_FRAME_MARKERS.has(marker)) return {
|
|
87
|
+
format: "jpeg",
|
|
88
|
+
bytes,
|
|
89
|
+
pixelHeight: readUint16BE(bytes, offset + 5),
|
|
90
|
+
pixelWidth: readUint16BE(bytes, offset + 7)
|
|
91
|
+
};
|
|
92
|
+
const segmentLength = readUint16BE(bytes, offset + 2);
|
|
93
|
+
if (segmentLength < 2) return { reason: "JPEG segment length is degenerate" };
|
|
94
|
+
offset += 2 + segmentLength;
|
|
95
|
+
}
|
|
96
|
+
return { reason: "JPEG carries no frame header" };
|
|
97
|
+
};
|
|
98
|
+
const sniffOtherFormat = (bytes) => {
|
|
99
|
+
if (startsWith(bytes, [
|
|
100
|
+
71,
|
|
101
|
+
73,
|
|
102
|
+
70,
|
|
103
|
+
56
|
|
104
|
+
])) return "GIF";
|
|
105
|
+
if (startsWith(bytes, [66, 77])) return "BMP";
|
|
106
|
+
if (startsWith(bytes, [
|
|
107
|
+
73,
|
|
108
|
+
73,
|
|
109
|
+
42,
|
|
110
|
+
0
|
|
111
|
+
]) || startsWith(bytes, [
|
|
112
|
+
77,
|
|
113
|
+
77,
|
|
114
|
+
0,
|
|
115
|
+
42
|
|
116
|
+
])) return "TIFF";
|
|
117
|
+
if (startsWith(bytes, [
|
|
118
|
+
215,
|
|
119
|
+
205,
|
|
120
|
+
198,
|
|
121
|
+
154
|
|
122
|
+
]) || startsWith(bytes, [
|
|
123
|
+
1,
|
|
124
|
+
0,
|
|
125
|
+
0,
|
|
126
|
+
0
|
|
127
|
+
])) return "WMF/EMF";
|
|
128
|
+
if (startsWith(bytes, [
|
|
129
|
+
60,
|
|
130
|
+
63,
|
|
131
|
+
120,
|
|
132
|
+
109
|
|
133
|
+
]) || startsWith(bytes, [
|
|
134
|
+
60,
|
|
135
|
+
115,
|
|
136
|
+
118,
|
|
137
|
+
103
|
|
138
|
+
])) return "SVG";
|
|
139
|
+
};
|
|
140
|
+
const decodeImageBytes = (bytes) => {
|
|
141
|
+
if (startsWith(bytes, PNG_SIGNATURE)) return decodePng(bytes);
|
|
142
|
+
if (startsWith(bytes, JPEG_SIGNATURE)) return decodeJpeg(bytes);
|
|
143
|
+
const other = sniffOtherFormat(bytes);
|
|
144
|
+
return { reason: other === void 0 ? "unrecognised image bytes" : `${other} is not PNG or JPEG` };
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Sources interned in first-use order, so two builds of one layout produce the
|
|
148
|
+
* same `DisplayImageRef` for the same picture.
|
|
149
|
+
*/
|
|
150
|
+
var ImageTable = class {
|
|
151
|
+
sources = [];
|
|
152
|
+
refBySrc = /* @__PURE__ */ new Map();
|
|
153
|
+
failureBySrc = /* @__PURE__ */ new Map();
|
|
154
|
+
/** `undefined` means "do not paint"; the reason is available via {@link failureFor}. */
|
|
155
|
+
intern(src) {
|
|
156
|
+
const cached = this.refBySrc.get(src);
|
|
157
|
+
if (cached !== void 0) return cached ?? void 0;
|
|
158
|
+
const fail = (reason) => {
|
|
159
|
+
this.refBySrc.set(src, null);
|
|
160
|
+
this.failureBySrc.set(src, reason);
|
|
161
|
+
};
|
|
162
|
+
const safeSrc = sanitizeImageSrc(src);
|
|
163
|
+
if (safeSrc === void 0) return fail("image source is not a data: or blob: URL");
|
|
164
|
+
const match = DATA_URL_PATTERN.exec(safeSrc);
|
|
165
|
+
if (!match) return fail("image bytes are not inline (blob: URLs need a fetch the builder cannot do)");
|
|
166
|
+
if (match[2] === void 0) return fail("only base64 data: URLs carry decodable bytes");
|
|
167
|
+
const bytes = decodeBase64(match[3]);
|
|
168
|
+
if (bytes === void 0) return fail("image data: URL payload is not valid base64");
|
|
169
|
+
if (bytes.length === 0) return fail("image data: URL decoded to no bytes");
|
|
170
|
+
const decoded = decodeImageBytes(bytes);
|
|
171
|
+
if ("reason" in decoded) return fail(decoded.reason);
|
|
172
|
+
const ref = this.sources.length;
|
|
173
|
+
this.sources.push(decoded);
|
|
174
|
+
this.refBySrc.set(src, ref);
|
|
175
|
+
return ref;
|
|
176
|
+
}
|
|
177
|
+
failureFor(src) {
|
|
178
|
+
return this.failureBySrc.get(src);
|
|
179
|
+
}
|
|
180
|
+
snapshot() {
|
|
181
|
+
return this.sources;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
const cropOf = (source) => {
|
|
185
|
+
const l = source.cropLeft ?? 0;
|
|
186
|
+
const t = source.cropTop ?? 0;
|
|
187
|
+
const r = source.cropRight ?? 0;
|
|
188
|
+
const b = source.cropBottom ?? 0;
|
|
189
|
+
if (!(l || t || r || b)) return;
|
|
190
|
+
return {
|
|
191
|
+
l,
|
|
192
|
+
t,
|
|
193
|
+
r,
|
|
194
|
+
b
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* The primitives one picture draws: the bitmap (rotated and/or washed as the
|
|
199
|
+
* source asks) followed by its border. Empty when the bytes are unusable, with
|
|
200
|
+
* the reason already reported.
|
|
201
|
+
*/
|
|
202
|
+
const paintImage = ({ source, rect, context, label }) => {
|
|
203
|
+
const primitives = [];
|
|
204
|
+
const ref = context.images.intern(source.src);
|
|
205
|
+
if (ref === void 0) {
|
|
206
|
+
const reason = context.images.failureFor(source.src) ?? "image could not be decoded";
|
|
207
|
+
const construct = reason.includes("not PNG or JPEG") ? UNSUPPORTED_CONSTRUCT.imageFormat : UNSUPPORTED_CONSTRUCT.imageSource;
|
|
208
|
+
context.unsupported.report(construct, context.pageIndex, `${label}: ${reason}`);
|
|
209
|
+
} else {
|
|
210
|
+
const crop = cropOf(source);
|
|
211
|
+
const image = {
|
|
212
|
+
kind: "image",
|
|
213
|
+
image: ref,
|
|
214
|
+
rect,
|
|
215
|
+
...crop === void 0 ? {} : { crop },
|
|
216
|
+
opacity: source.opacity == null ? 1 : Math.min(1, Math.max(0, source.opacity))
|
|
217
|
+
};
|
|
218
|
+
const degrees = parseRotationDegrees(source.transform);
|
|
219
|
+
if (degrees === 0) primitives.push(image);
|
|
220
|
+
else primitives.push({
|
|
221
|
+
kind: "rotateGroup",
|
|
222
|
+
degrees,
|
|
223
|
+
originXPx: rect.xPx + rect.widthPx / 2,
|
|
224
|
+
originYPx: rect.yPx + rect.heightPx / 2,
|
|
225
|
+
children: [image]
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
if (source.borderWidth != null && source.borderWidth > 0) {
|
|
229
|
+
const { stroke, unresolvedColor } = resolveBorderStroke({
|
|
230
|
+
width: source.borderWidth,
|
|
231
|
+
style: source.borderStyle ?? "solid",
|
|
232
|
+
color: source.borderColor ?? "#000000"
|
|
233
|
+
});
|
|
234
|
+
if (unresolvedColor !== void 0) context.unsupported.report(UNSUPPORTED_CONSTRUCT.unresolvedColor, context.pageIndex, `${label} border colour ${unresolvedColor}`);
|
|
235
|
+
if (stroke) {
|
|
236
|
+
const inset = stroke.thicknessPx / 2;
|
|
237
|
+
primitives.push({
|
|
238
|
+
kind: "rect",
|
|
239
|
+
rect: {
|
|
240
|
+
xPx: rect.xPx + inset,
|
|
241
|
+
yPx: rect.yPx + inset,
|
|
242
|
+
widthPx: Math.max(0, rect.widthPx - stroke.thicknessPx),
|
|
243
|
+
heightPx: Math.max(0, rect.heightPx - stroke.thicknessPx)
|
|
244
|
+
},
|
|
245
|
+
stroke
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return primitives;
|
|
250
|
+
};
|
|
251
|
+
/** An anchored or block image fragment placed by the layout engine. */
|
|
252
|
+
const paintImageFragment = (fragment, block, context) => paintImage({
|
|
253
|
+
source: block,
|
|
254
|
+
rect: {
|
|
255
|
+
xPx: fragment.x,
|
|
256
|
+
yPx: fragment.y,
|
|
257
|
+
widthPx: fragment.width,
|
|
258
|
+
heightPx: fragment.height
|
|
259
|
+
},
|
|
260
|
+
context,
|
|
261
|
+
label: `image block ${String(fragment.blockId)}`
|
|
262
|
+
});
|
|
263
|
+
//#endregion
|
|
264
|
+
export { ImageTable, paintImage, paintImageFragment };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { document_d_exports } from "../../types/document.js";
|
|
2
|
+
import { Page } from "../../layout-engine/types.js";
|
|
3
|
+
import { RenderPageOptions } from "../../layout-painter/renderPage.js";
|
|
4
|
+
import { DisplayPrimitive } from "../types.js";
|
|
5
|
+
import { BuildContext } from "./buildContext.js";
|
|
6
|
+
//#region src/display-list/build/pageBorderPrimitives.d.ts
|
|
7
|
+
/** The section's `w:pgBorders`, as the painter already receives them. */
|
|
8
|
+
type PageBorders = NonNullable<RenderPageOptions["pageBorders"]>;
|
|
9
|
+
type PageBorderPaintOptions = {
|
|
10
|
+
readonly page: Page;
|
|
11
|
+
readonly borders: PageBorders;
|
|
12
|
+
readonly theme?: document_d_exports.Theme | null;
|
|
13
|
+
readonly context: BuildContext;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The four page-border strokes, or nothing when this page does not carry them.
|
|
17
|
+
* `offsetFrom` decides what the box is measured from: `page` insets `w:space`
|
|
18
|
+
* from the paper edge, `text` insets the margin less `w:space` and the stroke
|
|
19
|
+
* itself, so the authored gap between text and border survives a thick rule.
|
|
20
|
+
*/
|
|
21
|
+
declare const paintPageBorders: ({ page, borders, theme, context }: PageBorderPaintOptions) => readonly DisplayPrimitive[];
|
|
22
|
+
//#endregion
|
|
23
|
+
export { PageBorderPaintOptions, PageBorders, paintPageBorders };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { resolveColor } from "../../utils/colorResolver.js";
|
|
2
|
+
import { eighthsToPixels, pointsToPixels } from "../../utils/units.js";
|
|
3
|
+
import { resolveBorderStroke } from "./strokes.js";
|
|
4
|
+
import { UNSUPPORTED_CONSTRUCT } from "./unsupported.js";
|
|
5
|
+
//#region src/display-list/build/pageBorderPrimitives.ts
|
|
6
|
+
/** `borderToStyle`: a border with no `w:sz` paints a hairline, not nothing. */
|
|
7
|
+
const HAIRLINE_WIDTH_PX = 1;
|
|
8
|
+
const SIDES = [
|
|
9
|
+
"top",
|
|
10
|
+
"right",
|
|
11
|
+
"bottom",
|
|
12
|
+
"left"
|
|
13
|
+
];
|
|
14
|
+
/** `pageBorderShouldRender`: `w:display` is about the physical page number. */
|
|
15
|
+
const shouldRender = (pageNumber, display) => {
|
|
16
|
+
switch (display ?? "allPages") {
|
|
17
|
+
case "firstPage": return pageNumber === 1;
|
|
18
|
+
case "notFirstPage": return pageNumber !== 1;
|
|
19
|
+
case "allPages": return true;
|
|
20
|
+
default: return true;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const spacePx = (border) => border?.space === void 0 ? 0 : pointsToPixels(border.space);
|
|
24
|
+
const strokeOf = (border, theme, context) => {
|
|
25
|
+
if (!border) return;
|
|
26
|
+
const { stroke, unresolvedColor } = resolveBorderStroke({
|
|
27
|
+
width: border.size === void 0 || border.size === 0 ? HAIRLINE_WIDTH_PX : eighthsToPixels(border.size),
|
|
28
|
+
style: border.style,
|
|
29
|
+
color: resolveColor(border.color, theme)
|
|
30
|
+
});
|
|
31
|
+
if (unresolvedColor !== void 0) context.unsupported.report(UNSUPPORTED_CONSTRUCT.unresolvedColor, context.pageIndex, `page border colour ${unresolvedColor}`);
|
|
32
|
+
return stroke;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The four page-border strokes, or nothing when this page does not carry them.
|
|
36
|
+
* `offsetFrom` decides what the box is measured from: `page` insets `w:space`
|
|
37
|
+
* from the paper edge, `text` insets the margin less `w:space` and the stroke
|
|
38
|
+
* itself, so the authored gap between text and border survives a thick rule.
|
|
39
|
+
*/
|
|
40
|
+
const paintPageBorders = ({ page, borders, theme, context }) => {
|
|
41
|
+
if (!shouldRender(page.number, borders.display)) return [];
|
|
42
|
+
const strokes = {
|
|
43
|
+
top: strokeOf(borders.top, theme, context),
|
|
44
|
+
right: strokeOf(borders.right, theme, context),
|
|
45
|
+
bottom: strokeOf(borders.bottom, theme, context),
|
|
46
|
+
left: strokeOf(borders.left, theme, context)
|
|
47
|
+
};
|
|
48
|
+
if (SIDES.every((side) => strokes[side] === void 0)) return [];
|
|
49
|
+
const insetPx = (side) => {
|
|
50
|
+
const border = borders[side];
|
|
51
|
+
if ((borders.offsetFrom ?? "text") === "page") return spacePx(border);
|
|
52
|
+
const marginPx = page.margins[side];
|
|
53
|
+
return Math.max(0, marginPx - spacePx(border) - (strokes[side]?.thicknessPx ?? 0));
|
|
54
|
+
};
|
|
55
|
+
const leftPx = insetPx("left");
|
|
56
|
+
const topPx = insetPx("top");
|
|
57
|
+
const rightPx = page.size.w - insetPx("right");
|
|
58
|
+
const bottomPx = page.size.h - insetPx("bottom");
|
|
59
|
+
const primitives = [];
|
|
60
|
+
for (const side of SIDES) {
|
|
61
|
+
const stroke = strokes[side];
|
|
62
|
+
if (stroke === void 0) continue;
|
|
63
|
+
const half = stroke.thicknessPx / 2;
|
|
64
|
+
switch (side) {
|
|
65
|
+
case "top":
|
|
66
|
+
primitives.push({
|
|
67
|
+
kind: "line",
|
|
68
|
+
x1Px: leftPx,
|
|
69
|
+
y1Px: topPx + half,
|
|
70
|
+
x2Px: rightPx,
|
|
71
|
+
y2Px: topPx + half,
|
|
72
|
+
stroke
|
|
73
|
+
});
|
|
74
|
+
break;
|
|
75
|
+
case "bottom":
|
|
76
|
+
primitives.push({
|
|
77
|
+
kind: "line",
|
|
78
|
+
x1Px: leftPx,
|
|
79
|
+
y1Px: bottomPx - half,
|
|
80
|
+
x2Px: rightPx,
|
|
81
|
+
y2Px: bottomPx - half,
|
|
82
|
+
stroke
|
|
83
|
+
});
|
|
84
|
+
break;
|
|
85
|
+
case "left":
|
|
86
|
+
primitives.push({
|
|
87
|
+
kind: "line",
|
|
88
|
+
x1Px: leftPx + half,
|
|
89
|
+
y1Px: topPx,
|
|
90
|
+
x2Px: leftPx + half,
|
|
91
|
+
y2Px: bottomPx,
|
|
92
|
+
stroke
|
|
93
|
+
});
|
|
94
|
+
break;
|
|
95
|
+
case "right":
|
|
96
|
+
primitives.push({
|
|
97
|
+
kind: "line",
|
|
98
|
+
x1Px: rightPx - half,
|
|
99
|
+
y1Px: topPx,
|
|
100
|
+
x2Px: rightPx - half,
|
|
101
|
+
y2Px: bottomPx,
|
|
102
|
+
stroke
|
|
103
|
+
});
|
|
104
|
+
break;
|
|
105
|
+
default:
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return primitives;
|
|
109
|
+
};
|
|
110
|
+
//#endregion
|
|
111
|
+
export { paintPageBorders };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { FootnoteContent, Page } from "../../layout-engine/types.js";
|
|
2
|
+
import { DisplayColor, DisplayPrimitive } from "../types.js";
|
|
3
|
+
import { BuildContext } from "./buildContext.js";
|
|
4
|
+
import { PageComposer } from "./regions.js";
|
|
5
|
+
//#region src/display-list/build/pageFurniture.d.ts
|
|
6
|
+
declare const paintPageBackground: (page: Page, fill: DisplayColor) => DisplayPrimitive;
|
|
7
|
+
/**
|
|
8
|
+
* Vertical rules between newspaper columns. The painter assumes equal columns
|
|
9
|
+
* with a uniform gap (it ignores `columns.widths` / `columns.gaps`), and so
|
|
10
|
+
* does this: diverging here would put the export's rules somewhere the editor
|
|
11
|
+
* never drew them.
|
|
12
|
+
*/
|
|
13
|
+
declare const paintColumnSeparators: (page: Page) => readonly DisplayPrimitive[];
|
|
14
|
+
type FootnoteAreaPaintOptions = {
|
|
15
|
+
readonly composer: PageComposer;
|
|
16
|
+
readonly page: Page;
|
|
17
|
+
readonly context: BuildContext;
|
|
18
|
+
/**
|
|
19
|
+
* The bodies, by `w:footnote` id. Absent, or missing an id the page carries,
|
|
20
|
+
* means the caller did not supply that body: the band still opens with its
|
|
21
|
+
* rule and reserves its height, and the missing bodies are named.
|
|
22
|
+
*/
|
|
23
|
+
readonly contentById?: ReadonlyMap<number, FootnoteContent>;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The footnote band at the foot of the body column: the separator rule, then
|
|
27
|
+
* one body per note the paginator put on this page.
|
|
28
|
+
*
|
|
29
|
+
* The band's top comes from the reservation the paginator made, clamped up to
|
|
30
|
+
* what the bodies actually need, so a stack that under-reserved by a pixel ends
|
|
31
|
+
* at the page bottom instead of spilling past it.
|
|
32
|
+
*/
|
|
33
|
+
declare const paintFootnoteArea: ({ composer, page, context, contentById }: FootnoteAreaPaintOptions) => void;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { FootnoteAreaPaintOptions, paintColumnSeparators, paintFootnoteArea, paintPageBackground };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import "../../layout-engine/types.js";
|
|
2
|
+
import { calculateFootnoteAreaRenderHeight } from "../../layout-painter/renderPage.js";
|
|
3
|
+
import { HIT_REGION_KINDS } from "../primitives.js";
|
|
4
|
+
import { DOC_CANVAS_TEXT } from "./colors.js";
|
|
5
|
+
import { paintFootnoteBlocks } from "./storyPrimitives.js";
|
|
6
|
+
import { UNSUPPORTED_CONSTRUCT } from "./unsupported.js";
|
|
7
|
+
//#region src/display-list/build/pageFurniture.ts
|
|
8
|
+
/**
|
|
9
|
+
* Page furniture: everything on a page that is not a body fragment.
|
|
10
|
+
*
|
|
11
|
+
* `renderPage.ts` is the authority on the order and on the geometry, and it
|
|
12
|
+
* takes most of this from `RenderPageOptions` rather than from the `Layout`:
|
|
13
|
+
* page borders, watermarks, footnote bodies and header/footer stories all reach
|
|
14
|
+
* the DOM painter as render options the layout never carried. The builder is
|
|
15
|
+
* handed the same inputs, so a construct the caller supplies is painted and a
|
|
16
|
+
* construct the layout shows evidence of but the caller withheld is reported.
|
|
17
|
+
* The furniture that is derivable from the `Layout` alone — the page
|
|
18
|
+
* background, the column separators and the footnote separator rule — is always
|
|
19
|
+
* painted.
|
|
20
|
+
*/
|
|
21
|
+
/** `renderPage.ts:2049`: a hairline in the canvas ink colour. */
|
|
22
|
+
const COLUMN_SEPARATOR_WIDTH_PX = .5;
|
|
23
|
+
/** `renderPage.ts:1354-1360`: a 0.5px rule across a third of the column, centred in its 12px slot. */
|
|
24
|
+
const FOOTNOTE_RULE_THICKNESS_PX = .5;
|
|
25
|
+
const FOOTNOTE_RULE_WIDTH_FRACTION = .33;
|
|
26
|
+
const FOOTNOTE_RULE_MARGIN_PX = (12 - FOOTNOTE_RULE_THICKNESS_PX) / 2;
|
|
27
|
+
const paintPageBackground = (page, fill) => ({
|
|
28
|
+
kind: "rect",
|
|
29
|
+
rect: {
|
|
30
|
+
xPx: 0,
|
|
31
|
+
yPx: 0,
|
|
32
|
+
widthPx: page.size.w,
|
|
33
|
+
heightPx: page.size.h
|
|
34
|
+
},
|
|
35
|
+
fill
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Vertical rules between newspaper columns. The painter assumes equal columns
|
|
39
|
+
* with a uniform gap (it ignores `columns.widths` / `columns.gaps`), and so
|
|
40
|
+
* does this: diverging here would put the export's rules somewhere the editor
|
|
41
|
+
* never drew them.
|
|
42
|
+
*/
|
|
43
|
+
const paintColumnSeparators = (page) => {
|
|
44
|
+
const columns = page.columns;
|
|
45
|
+
if (!columns?.separator || columns.count <= 1) return [];
|
|
46
|
+
const contentWidthPx = page.size.w - page.margins.left - page.margins.right;
|
|
47
|
+
const contentHeightPx = page.size.h - page.margins.top - page.margins.bottom;
|
|
48
|
+
const columnWidthPx = (contentWidthPx - (columns.count - 1) * columns.gap) / columns.count;
|
|
49
|
+
const primitives = [];
|
|
50
|
+
for (let column = 0; column < columns.count - 1; column += 1) {
|
|
51
|
+
const offsetPx = (column + 1) * columnWidthPx + column * columns.gap + columns.gap / 2;
|
|
52
|
+
primitives.push({
|
|
53
|
+
kind: "rect",
|
|
54
|
+
rect: {
|
|
55
|
+
xPx: page.margins.left + offsetPx,
|
|
56
|
+
yPx: page.margins.top,
|
|
57
|
+
widthPx: COLUMN_SEPARATOR_WIDTH_PX,
|
|
58
|
+
heightPx: contentHeightPx
|
|
59
|
+
},
|
|
60
|
+
fill: DOC_CANVAS_TEXT
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return primitives;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* The footnote band at the foot of the body column: the separator rule, then
|
|
67
|
+
* one body per note the paginator put on this page.
|
|
68
|
+
*
|
|
69
|
+
* The band's top comes from the reservation the paginator made, clamped up to
|
|
70
|
+
* what the bodies actually need, so a stack that under-reserved by a pixel ends
|
|
71
|
+
* at the page bottom instead of spilling past it.
|
|
72
|
+
*/
|
|
73
|
+
const paintFootnoteArea = ({ composer, page, context, contentById }) => {
|
|
74
|
+
const reservedHeightPx = page.footnoteReservedHeight ?? 0;
|
|
75
|
+
const noteIds = page.footnoteIds ?? [];
|
|
76
|
+
if (reservedHeightPx <= 0 || noteIds.length === 0) return;
|
|
77
|
+
const bodies = noteIds.map((noteId) => ({
|
|
78
|
+
noteId,
|
|
79
|
+
content: contentById?.get(noteId)
|
|
80
|
+
}));
|
|
81
|
+
const missing = bodies.flatMap(({ noteId, content }) => content === void 0 ? [noteId] : []);
|
|
82
|
+
if (missing.length > 0) context.unsupported.report(UNSUPPORTED_CONSTRUCT.footnoteContent, context.pageIndex, `footnote bodies ${missing.join(", ")} were not supplied to the builder, so the band reserves their height and paints nothing`);
|
|
83
|
+
const items = bodies.map(({ noteId, content }) => ({
|
|
84
|
+
noteId,
|
|
85
|
+
displayNumber: String(content?.displayNumber ?? noteId),
|
|
86
|
+
...content === void 0 ? {} : { content: {
|
|
87
|
+
blocks: content.blocks,
|
|
88
|
+
measures: content.measures,
|
|
89
|
+
height: content.height
|
|
90
|
+
} }
|
|
91
|
+
}));
|
|
92
|
+
const contentHeightPx = page.size.h - page.margins.top - page.margins.bottom;
|
|
93
|
+
const contentWidthPx = page.size.w - page.margins.left - page.margins.right;
|
|
94
|
+
const bandHeightPx = Math.max(reservedHeightPx, calculateFootnoteAreaRenderHeight(items));
|
|
95
|
+
const areaTopPx = page.margins.top + Math.max(-page.margins.top, contentHeightPx - bandHeightPx);
|
|
96
|
+
const primitives = [{
|
|
97
|
+
kind: "rect",
|
|
98
|
+
rect: {
|
|
99
|
+
xPx: page.margins.left,
|
|
100
|
+
yPx: areaTopPx + FOOTNOTE_RULE_MARGIN_PX,
|
|
101
|
+
widthPx: contentWidthPx * FOOTNOTE_RULE_WIDTH_FRACTION,
|
|
102
|
+
heightPx: FOOTNOTE_RULE_THICKNESS_PX
|
|
103
|
+
},
|
|
104
|
+
fill: DOC_CANVAS_TEXT
|
|
105
|
+
}];
|
|
106
|
+
composer.push(primitives);
|
|
107
|
+
for (const [index, { noteId, content }] of bodies.entries()) {
|
|
108
|
+
if (content === void 0) continue;
|
|
109
|
+
const offsetPx = calculateFootnoteAreaRenderHeight(items.slice(0, index));
|
|
110
|
+
const story = {
|
|
111
|
+
kind: "footnote",
|
|
112
|
+
id: noteId
|
|
113
|
+
};
|
|
114
|
+
composer.region({
|
|
115
|
+
kind: HIT_REGION_KINDS.note,
|
|
116
|
+
rect: {
|
|
117
|
+
xPx: page.margins.left,
|
|
118
|
+
yPx: areaTopPx + offsetPx,
|
|
119
|
+
widthPx: contentWidthPx,
|
|
120
|
+
heightPx: content.height
|
|
121
|
+
},
|
|
122
|
+
model: { story }
|
|
123
|
+
}, () => {
|
|
124
|
+
paintFootnoteBlocks({
|
|
125
|
+
composer,
|
|
126
|
+
blocks: content.blocks,
|
|
127
|
+
measures: content.measures,
|
|
128
|
+
xPx: page.margins.left,
|
|
129
|
+
yPx: areaTopPx + offsetPx,
|
|
130
|
+
widthPx: contentWidthPx,
|
|
131
|
+
context: {
|
|
132
|
+
...context,
|
|
133
|
+
story
|
|
134
|
+
},
|
|
135
|
+
label: `footnote ${content.displayNumber}`
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
//#endregion
|
|
141
|
+
export { paintColumnSeparators, paintFootnoteArea, paintPageBackground };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphMeasure } from "../../layout-engine/types.js";
|
|
2
|
+
import { BuildContext } from "./buildContext.js";
|
|
3
|
+
import { PageComposer } from "./regions.js";
|
|
4
|
+
//#region src/display-list/build/paragraphPrimitives.d.ts
|
|
5
|
+
type ParagraphPaintOptions = {
|
|
6
|
+
/** Where the primitives and the regions over them are collected. */
|
|
7
|
+
readonly composer: PageComposer;
|
|
8
|
+
readonly fragment: ParagraphFragment;
|
|
9
|
+
readonly block: ParagraphBlock;
|
|
10
|
+
readonly measure: ParagraphMeasure;
|
|
11
|
+
readonly context: BuildContext;
|
|
12
|
+
/** Borders of the adjacent paragraphs, for ECMA-376 §17.3.1.24 border grouping. */
|
|
13
|
+
readonly prevBorders?: ParagraphBorders;
|
|
14
|
+
readonly nextBorders?: ParagraphBorders;
|
|
15
|
+
};
|
|
16
|
+
/** Every primitive a paragraph fragment paints, back to front. */
|
|
17
|
+
declare const paintParagraphFragment: (options: ParagraphPaintOptions) => void;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { ParagraphPaintOptions, paintParagraphFragment };
|