@docx-editor.dev/core 2.14.0 → 2.15.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/README.md +42 -0
- package/dist/automation.cjs +1 -1
- package/dist/automation.d.ts +6 -5
- package/dist/automation.js +1 -1
- package/dist/binding.cjs +1 -1
- package/dist/binding.d.ts +16 -10
- package/dist/binding.js +1 -1
- package/dist/chunk-24APKZAN.cjs +11 -0
- package/dist/chunk-2YH4MSHX.cjs +2 -0
- package/dist/chunk-5Y7AADI6.js +1 -0
- package/dist/chunk-AREFLNUP.js +11 -0
- package/dist/chunk-AS7YZNQE.cjs +2 -0
- package/dist/chunk-AVGCKH6A.cjs +20 -0
- package/dist/chunk-CDYVDQRI.cjs +5 -0
- package/dist/chunk-FGBADUSK.cjs +1 -0
- package/dist/chunk-HOEWFH5U.cjs +1 -0
- package/dist/chunk-KFELX7CN.js +2 -0
- package/dist/{chunk-OKEDGR65.js → chunk-KXPVOPR5.js} +1 -1
- package/dist/chunk-LGFKIF4M.cjs +1 -0
- package/dist/chunk-M52QXFKI.js +1 -0
- package/dist/chunk-MNUKSXRO.js +1 -0
- package/dist/chunk-PBOIGBDO.js +2 -0
- package/dist/chunk-PMHGONET.cjs +1 -0
- package/dist/chunk-PXKZUTHX.cjs +2 -0
- package/dist/chunk-Q4AB7E4O.cjs +1 -0
- package/dist/chunk-QJYH6AYD.js +1 -0
- package/dist/chunk-QRC37MWG.cjs +20 -0
- package/dist/chunk-RJSB6RJ7.js +20 -0
- package/dist/chunk-SB54HLFJ.js +20 -0
- package/dist/chunk-VP7SDFCM.js +1 -0
- package/dist/chunk-XCESLTJL.js +2 -0
- package/dist/{chunk-KIAP7PFQ.cjs → chunk-YL4Q5LZP.cjs} +1 -1
- package/dist/chunk-Z4527AXR.js +5 -0
- package/dist/collaboration/replication.cjs +1 -1
- package/dist/collaboration/replication.d.ts +4 -3
- package/dist/collaboration/replication.js +1 -1
- package/dist/collaboration.d.ts +4 -3
- package/dist/contracts/editor.d.ts +7 -7
- package/dist/contracts/interaction.d.ts +7 -7
- package/dist/contracts/modules.d.ts +8 -7
- package/dist/{custom-node-writes-DntmaAVW.d.ts → custom-node-writes-C9ArIlJh.d.ts} +2 -2
- package/dist/{editor-a6VvsfYU.d.ts → editor-sRxrFJd8.d.ts} +29 -21
- package/dist/editor.cjs +1 -1
- package/dist/editor.d.ts +27 -58
- package/dist/editor.js +1 -1
- package/dist/export.cjs +2 -0
- package/dist/export.d.ts +337 -0
- package/dist/export.js +2 -0
- package/dist/font-resolver-BYEHQGTw.d.ts +251 -0
- package/dist/headless-document-view-DELC4E5v.d.ts +134 -0
- package/dist/hf-references-DTrHkktY.d.ts +70 -0
- package/dist/{index-C5ZnSRkF.d.ts → index-C3Gvq4jN.d.ts} +55 -246
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +18 -16
- package/dist/index.js +1 -1
- package/dist/{shaped-measurer-CFPnXFs9.d.cts → layout-shaping-DoGR5cf8.d.ts} +86 -12
- package/dist/layout.cjs +1 -1
- package/dist/layout.d.ts +1106 -729
- package/dist/layout.js +1 -1
- package/dist/{note-properties-CDFiNXcD.d.ts → note-properties-DSe8igrz.d.ts} +2 -2
- package/dist/{omml-equation-BY49UOIF.d.ts → omml-equation-BpRmfDAf.d.ts} +1 -1
- package/dist/output.cjs +1 -1
- package/dist/output.d.ts +6 -6
- package/dist/output.js +1 -1
- package/dist/{protocol-gOY5GA8K.d.cts → protocol-DZzKxH5r.d.ts} +18 -12
- package/dist/{review-items-CCS1h93f.d.ts → review-items-DYRx187i.d.ts} +2 -2
- package/dist/{review-reads-BjZYeMd4.d.ts → review-reads-LbGUdNzn.d.ts} +22 -25
- package/dist/{revision-projection-BeXVrSSV.d.ts → revision-projection-DHRJH48u.d.ts} +1 -1
- package/dist/{semantic-cell-selection-BK91NCCG.d.ts → semantic-cell-selection-BXVWCBYm.d.ts} +4 -4
- package/dist/{semantic-interaction-BmQ7h2cq.d.ts → semantic-interaction-DZsDmPg5.d.ts} +1 -1
- package/dist/{semantic-paint-WJD2KeG1.d.ts → semantic-paint-f7SqN4oW.d.ts} +2 -2
- package/dist/{semantic-records-BpozY7-j.d.cts → semantic-records-EIdwId-a.d.ts} +301 -205
- package/dist/store.cjs +1 -1
- package/dist/store.d.ts +15 -65
- package/dist/store.js +1 -1
- package/dist/{tree-op-types-D6HzlPR4.d.ts → tree-op-types-egdarvH_.d.ts} +7 -3
- package/dist/{tree-package-fragment-CWFjgH6a.d.ts → tree-package-fragment-DjkH4ESI.d.ts} +4 -70
- package/dist/{tree-session-contract-B2HfGt79.d.ts → tree-session-contract-CGOOgPjW.d.ts} +29 -23
- package/dist/{tree-store-APgWx6qn.d.ts → tree-store-DKJB0IcA.d.ts} +2 -2
- package/package.json +7 -2
- package/dist/automation.d.cts +0 -82
- package/dist/binding.d.cts +0 -153
- package/dist/chunk-2PIHW2QM.cjs +0 -1
- package/dist/chunk-2QTY5S6T.js +0 -1
- package/dist/chunk-4Z5MODAE.cjs +0 -2
- package/dist/chunk-5TKAPFZT.cjs +0 -2
- package/dist/chunk-DRQHIQ4R.cjs +0 -1
- package/dist/chunk-F2K6SDHA.cjs +0 -20
- package/dist/chunk-FBA57EUJ.js +0 -2
- package/dist/chunk-KTAQ7BRQ.js +0 -20
- package/dist/chunk-LBAHXZCU.cjs +0 -5
- package/dist/chunk-MCDUQYWP.js +0 -5
- package/dist/chunk-MQP26KCF.js +0 -1
- package/dist/chunk-NDJGSR6M.cjs +0 -19
- package/dist/chunk-NJNFJPGB.cjs +0 -11
- package/dist/chunk-O5M4CR4P.cjs +0 -2
- package/dist/chunk-UKUOZXUD.js +0 -19
- package/dist/chunk-VQ4R5LTU.js +0 -2
- package/dist/chunk-ZBEJHJN2.js +0 -11
- package/dist/chunk-ZVTW7RGD.js +0 -2
- package/dist/collaboration/replication.d.cts +0 -216
- package/dist/collaboration.d.cts +0 -176
- package/dist/contracts/document.d.cts +0 -273
- package/dist/contracts/editor.d.cts +0 -10
- package/dist/contracts/interaction.d.cts +0 -10
- package/dist/contracts/modules.d.cts +0 -130
- package/dist/contracts/types.d.cts +0 -562
- package/dist/custom-node-writes-C46r3_5O.d.cts +0 -310
- package/dist/document-properties-D6Ahr8D6.d.cts +0 -28
- package/dist/document-properties-D6Ahr8D6.d.ts +0 -28
- package/dist/editor-AJ06hyyg.d.cts +0 -1994
- package/dist/editor.d.cts +0 -393
- package/dist/failure-BnGjoXf0.d.cts +0 -64
- package/dist/index-Cbw4lkOt.d.cts +0 -3391
- package/dist/index.d.cts +0 -23
- package/dist/layout.d.cts +0 -2486
- package/dist/note-properties-Y6qYh2Hv.d.cts +0 -67
- package/dist/omml-equation-DB8d-jCq.d.cts +0 -84
- package/dist/output.d.cts +0 -74
- package/dist/protocol-BsmQgblT.d.ts +0 -1358
- package/dist/review-items-CaAkgi5s.d.cts +0 -360
- package/dist/review-reads-DEsV0OOW.d.cts +0 -163
- package/dist/revision-projection-DXbrfNGD.d.cts +0 -156
- package/dist/semantic-cell-selection-BMhku3B1.d.cts +0 -451
- package/dist/semantic-interaction-DUAnxbgf.d.cts +0 -160
- package/dist/semantic-paint-DufNL1Zr.d.cts +0 -247
- package/dist/semantic-records-92UnKeU_.d.ts +0 -2821
- package/dist/shaped-measurer-BWbindlI.d.ts +0 -168
- package/dist/store.d.cts +0 -2500
- package/dist/tree-op-types-BUulYD5y.d.cts +0 -3099
- package/dist/tree-package-fragment-Dhyw7oPm.d.cts +0 -732
- package/dist/tree-session-contract-BY9xd7s_.d.cts +0 -613
- package/dist/tree-store-DEEQ9wz_.d.cts +0 -416
|
@@ -1,2821 +0,0 @@
|
|
|
1
|
-
import { a as OoxmlNode, s as OoxmlProperty, g as OoxmlElement, O as OoxmlPart, x as ImageResourceState, U as DrawingAccessibility, S as SourceCrop, W as DrawingTransform, X as VectorShapeProjection, z as DrawingHorizontalReferenceFrame, A as DrawingVerticalReferenceFrame, u as ImageWrapTarget, Y as DrawingProjection, Z as OoxmlDrawingNode, _ as TableBorderStyle } from './tree-op-types-D6HzlPR4.js';
|
|
2
|
-
import { b as RevisionAttribution } from './revision-projection-BeXVrSSV.js';
|
|
3
|
-
import { O as OmmlEquationProjection } from './omml-equation-BY49UOIF.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Whether a paragraph must start a new page (`w:pageBreakBefore`).
|
|
7
|
-
*
|
|
8
|
-
* LAST WINS, like every other toggle read off the cascade (`paragraphKeeps` does the same
|
|
9
|
-
* for `w:keepNext`). An any-wins `.some()` cannot be switched off: a Chapter or Heading style
|
|
10
|
-
* carries `w:pageBreakBefore`, and Word writes `w:val="0"` on the one instance whose author
|
|
11
|
-
* unchecked the box — that paragraph still broke, so the document grew a blank page and every
|
|
12
|
-
* page number after it was wrong.
|
|
13
|
-
*
|
|
14
|
-
* An absent `w:val` is on (§17.17.4), and the off vocabulary is the whole of it — `off` is a
|
|
15
|
-
* spelling too, which {@link isOn} beside this already accepts.
|
|
16
|
-
*/
|
|
17
|
-
declare function paragraphBreaksBefore(props: readonly OoxmlProperty[]): boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Soft ceiling matching the spike's resolved-style limit (31_680 twips ≈ 22"). Beyond
|
|
20
|
-
* that an attacker-authored spacing would push pagination into pathological page counts.
|
|
21
|
-
*/
|
|
22
|
-
declare const MAX_PARAGRAPH_SPACING_PT: number;
|
|
23
|
-
/** Soft ceiling on border width (96 eighths = 12pt). Word's UI tops out well below this. */
|
|
24
|
-
declare const MAX_BORDER_WIDTH_PT = 12;
|
|
25
|
-
/** Soft ceiling on border-to-text gap (`w:space`, already in points). */
|
|
26
|
-
declare const MAX_BORDER_SPACE_PT = 3168;
|
|
27
|
-
/**
|
|
28
|
-
* A paragraph's resolved space before and after, in points.
|
|
29
|
-
*
|
|
30
|
-
* Already collapsed against `w:contextualSpacing`, so adjacent same-style paragraphs that suppress
|
|
31
|
-
* their gap arrive here with it removed rather than leaving that to whoever stacks them.
|
|
32
|
-
*/
|
|
33
|
-
interface ParagraphSpacing {
|
|
34
|
-
/** `w:spacing/@before`, in points. */
|
|
35
|
-
readonly before: number;
|
|
36
|
-
/** `w:spacing/@after`, in points. */
|
|
37
|
-
readonly after: number;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* The gap Word substitutes when `w:beforeAutospacing` / `w:afterAutospacing` is on
|
|
41
|
-
* (ECMA-376 §17.3.1.33, the `w:spacing` clause both attributes belong to).
|
|
42
|
-
*
|
|
43
|
-
* The attribute means "the consumer decides", and the authored `@before` / `@after` beside it
|
|
44
|
-
* is IGNORED rather than used as the value. Word's answer is HTML's default `<p>` margin,
|
|
45
|
-
* 14pt, which is what a document round-tripped through Word's HTML filter carries — and this
|
|
46
|
-
* one is everywhere, because Word writes `w:before="100" w:beforeAutospacing="1"` for it. Reading
|
|
47
|
-
* only the literal 100 twips lays every such paragraph out 9pt tight, which moves page breaks.
|
|
48
|
-
*/
|
|
49
|
-
declare const AUTO_PARAGRAPH_SPACING_PT = 14;
|
|
50
|
-
/**
|
|
51
|
-
* Where a paragraph sits, for the two contexts in which Word's auto spacing resolves to 0
|
|
52
|
-
* instead of {@link AUTO_PARAGRAPH_SPACING_PT}.
|
|
53
|
-
*
|
|
54
|
-
* Both come from the HTML model the attribute emulates: a `<li>` and a `<td>` collapse the
|
|
55
|
-
* paragraph margin, a bare `<p>` does not. A caller that says nothing gets the body answer.
|
|
56
|
-
*/
|
|
57
|
-
interface ParagraphAutoSpacingContext {
|
|
58
|
-
/** The paragraph participates in numbering (`w:numPr`), i.e. it is a list item. */
|
|
59
|
-
readonly inList?: boolean;
|
|
60
|
-
/** The paragraph lives in a table cell. */
|
|
61
|
-
readonly inTableCell?: boolean;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Resolved line spacing (`w:spacing/@line` + `@lineRule`, ECMA-376 17.3.1.33).
|
|
65
|
-
*
|
|
66
|
-
* `auto` is the interesting one: `@line` is 240ths of a line, so 240 is single, 360 is
|
|
67
|
-
* one-and-a-half, 480 is double — and Word's own Normal style since 2013 is 259, i.e.
|
|
68
|
-
* 1.08. A document laid out at a flat single spacing is ~8% tight on EVERY line, which
|
|
69
|
-
* moves every page break, so this is not a cosmetic detail.
|
|
70
|
-
*
|
|
71
|
-
* `exact` fixes the line box at `@line` twips and lets tall glyphs clip, the way Word
|
|
72
|
-
* does. `atLeast` uses it as a floor.
|
|
73
|
-
*/
|
|
74
|
-
type LineSpacingRule = 'auto' | 'exact' | 'atLeast';
|
|
75
|
-
/**
|
|
76
|
-
* Resolved line spacing: the rule, and the value it applies.
|
|
77
|
-
*
|
|
78
|
-
* `value` means different things per rule — 240ths of a line under `auto`, points under `exact`
|
|
79
|
-
* and `atLeast` — which is why the two travel together and neither is useful alone.
|
|
80
|
-
*/
|
|
81
|
-
interface ParagraphLineSpacing {
|
|
82
|
-
readonly rule: LineSpacingRule;
|
|
83
|
-
/** `auto`: the 240ths-of-a-line multiplier numerator. Otherwise points. */
|
|
84
|
-
readonly value: number;
|
|
85
|
-
}
|
|
86
|
-
/** Single spacing: what a paragraph that says nothing gets. */
|
|
87
|
-
declare const SINGLE_LINE_SPACING: ParagraphLineSpacing;
|
|
88
|
-
/**
|
|
89
|
-
* One resolved `w:pBdr` edge: its style, colour, thickness and gap.
|
|
90
|
-
*
|
|
91
|
-
* `widthPt` and `spacePt` are already converted and CLAMPED — both come from a file, and an
|
|
92
|
-
* unbounded border width becomes a layout dimension.
|
|
93
|
-
*/
|
|
94
|
-
interface ParagraphBorderEdge {
|
|
95
|
-
/** Authored `ST_Border` value (`single`, `dashed`, …). */
|
|
96
|
-
readonly val: string;
|
|
97
|
-
/** RRGGBB, or null when auto/missing (paint defaults to black). */
|
|
98
|
-
readonly color: string | null;
|
|
99
|
-
/** Border thickness in points (`w:sz` is eighths of a point). */
|
|
100
|
-
readonly widthPt: number;
|
|
101
|
-
/** Gap from text to the rule, in points (`w:space`). */
|
|
102
|
-
readonly spacePt: number;
|
|
103
|
-
/**
|
|
104
|
-
* `w:shadow` — Word offsets a drop shadow behind the rule.
|
|
105
|
-
*
|
|
106
|
-
* Present only when authored true, so an edge that says nothing keeps the shape earlier
|
|
107
|
-
* fixtures assert. Resolved and carried; drawing it is deferred.
|
|
108
|
-
*/
|
|
109
|
-
readonly shadow?: true;
|
|
110
|
-
}
|
|
111
|
-
/** The six `CT_PBdr` children, in schema order (ECMA-376 §17.3.1.24). */
|
|
112
|
-
declare const PARAGRAPH_BORDER_SIDES: readonly ["top", "left", "bottom", "right", "between", "bar"];
|
|
113
|
-
/**
|
|
114
|
-
* Which of the six `CT_PBdr` edges.
|
|
115
|
-
*
|
|
116
|
-
* Four are physical box edges; `between` and `bar` are group-relative, drawn only where
|
|
117
|
-
* consecutive paragraphs share a border definition.
|
|
118
|
-
*/
|
|
119
|
-
type ParagraphBorderSide = (typeof PARAGRAPH_BORDER_SIDES)[number];
|
|
120
|
-
/**
|
|
121
|
-
* A paragraph's resolved `w:pBdr` (ECMA-376 §17.3.1.24).
|
|
122
|
-
*
|
|
123
|
-
* `top`/`left`/`bottom`/`right` are the four physical edges of the box. The other two are
|
|
124
|
-
* group-relative: `between` draws at a boundary INSIDE a run of consecutive paragraphs whose
|
|
125
|
-
* border settings are identical, and `bar` is the vertical change-bar rule beside the
|
|
126
|
-
* paragraph, drawn whether or not the paragraph groups with its neighbours.
|
|
127
|
-
*/
|
|
128
|
-
interface ParagraphBorders {
|
|
129
|
-
readonly top?: ParagraphBorderEdge;
|
|
130
|
-
readonly left?: ParagraphBorderEdge;
|
|
131
|
-
readonly bottom?: ParagraphBorderEdge;
|
|
132
|
-
readonly right?: ParagraphBorderEdge;
|
|
133
|
-
readonly between?: ParagraphBorderEdge;
|
|
134
|
-
readonly bar?: ParagraphBorderEdge;
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Resolve `w:spacing` before/after from flat paragraph properties.
|
|
138
|
-
*
|
|
139
|
-
* Line spacing (`w:line` / `w:lineRule`) is a separate concern — it changes measured line
|
|
140
|
-
* height, not the gap between paragraphs — and is not resolved here.
|
|
141
|
-
*
|
|
142
|
-
* `w:beforeAutospacing` / `w:afterAutospacing` REPLACE the authored measurement on their own
|
|
143
|
-
* side rather than adding to it; see {@link AUTO_PARAGRAPH_SPACING_PT}.
|
|
144
|
-
*/
|
|
145
|
-
declare function paragraphSpacing(props: readonly OoxmlProperty[], context?: ParagraphAutoSpacingContext): ParagraphSpacing;
|
|
146
|
-
/**
|
|
147
|
-
* Resolve `w:line` / `w:lineRule` from flat paragraph properties.
|
|
148
|
-
*
|
|
149
|
-
* Merged per attribute for the same reason as before/after: `w:spacing` is one element
|
|
150
|
-
* carrying independent attributes, and a style that states only `@line` must not reset the
|
|
151
|
-
* rule an earlier entry in the cascade set.
|
|
152
|
-
*/
|
|
153
|
-
declare function paragraphLineSpacing(props: readonly OoxmlProperty[]): ParagraphLineSpacing;
|
|
154
|
-
/**
|
|
155
|
-
* Apply resolved line spacing to a line's natural (glyph-derived) box.
|
|
156
|
-
*
|
|
157
|
-
* Word places `auto` / `atLeast` extras BELOW the line (the last line's multiple spacing
|
|
158
|
-
* still separates it from the next paragraph). Putting that delta above inverted cover-page
|
|
159
|
-
* rhythm: `w:line="460"` on "between" opened a large gap above the word and almost none
|
|
160
|
-
* before "MERIDIAN". `exact` taller than the glyphs centers the text (ECMA-376 17.3.1.33).
|
|
161
|
-
* An `exact` box smaller than the glyphs keeps the baseline inside so clipped text still
|
|
162
|
-
* sits on it.
|
|
163
|
-
*/
|
|
164
|
-
declare function applyLineSpacing(spacing: ParagraphLineSpacing, naturalHeight: number, naturalBaseline: number): {
|
|
165
|
-
height: number;
|
|
166
|
-
baseline: number;
|
|
167
|
-
};
|
|
168
|
-
/**
|
|
169
|
-
* `w:contextualSpacing` (17.3.1.9): drop before/after between paragraphs of the SAME
|
|
170
|
-
* style. Word's built-in `ListParagraph` sets it, so every list authored in Word gets a
|
|
171
|
-
* paragraph gap between items without this.
|
|
172
|
-
*/
|
|
173
|
-
declare function paragraphContextualSpacing(props: readonly OoxmlProperty[]): boolean;
|
|
174
|
-
/**
|
|
175
|
-
* Resolve `w:pBdr` from the paragraph-properties node.
|
|
176
|
-
*
|
|
177
|
-
* Nested — every edge is a child of `pBdr`, not an attribute — so this reads the typed tree
|
|
178
|
-
* rather than the flattened `OoxmlProperty[]` bag `propertiesOf` builds for leaf props.
|
|
179
|
-
*/
|
|
180
|
-
declare function paragraphBorders(pPr: OoxmlNode | undefined): ParagraphBorders;
|
|
181
|
-
/**
|
|
182
|
-
* `w:pBdr` after the style cascade: a later `w:pBdr` replaces an earlier one WHOLESALE.
|
|
183
|
-
*
|
|
184
|
-
* Word does not merge edges across the cascade. A style that states only `w:bottom` discards
|
|
185
|
-
* the box its `basedOn` ancestor declared, so folding edge by edge would leave a lone
|
|
186
|
-
* underline surrounded by a box no one authored. Absence inherits; `nil`/`none` clear.
|
|
187
|
-
*/
|
|
188
|
-
declare function cascadedParagraphBorders(paragraphPropertyNodes: readonly OoxmlNode[]): ParagraphBorders;
|
|
189
|
-
/**
|
|
190
|
-
* Visual stroke thickness layout publishes for one edge (points).
|
|
191
|
-
*
|
|
192
|
-
* Compound `ST_Border` values (`double`, …) use the shared inflated band so a thin
|
|
193
|
-
* `w:sz="3"` double still occupies a visible double-line box — matching table borders.
|
|
194
|
-
*/
|
|
195
|
-
declare function paragraphBorderStrokeWidthPt(edge: ParagraphBorderEdge): number;
|
|
196
|
-
/**
|
|
197
|
-
* Extent one border edge occupies away from the text it decorates: gap plus rule, in points.
|
|
198
|
-
*
|
|
199
|
-
* Vertically that is flow height — a top rule pushes the first line down, a bottom rule holds
|
|
200
|
-
* the page open below the last one — so pagination has to see it. Horizontally it is
|
|
201
|
-
* publish-only: Word draws left/right paragraph rules OUTSIDE the text column and never
|
|
202
|
-
* re-breaks the lines, which is why adding a box to a paragraph in Word does not reflow it.
|
|
203
|
-
*/
|
|
204
|
-
declare function paragraphBorderExtentPt(edge: ParagraphBorderEdge | undefined): number;
|
|
205
|
-
/** Vertical extent a bottom border adds below the last line (gap + rule). */
|
|
206
|
-
declare function bottomBorderExtentPt(edge: ParagraphBorderEdge | undefined): number;
|
|
207
|
-
/**
|
|
208
|
-
* Identity of a paragraph's border set, for the `w:between` group rule.
|
|
209
|
-
*
|
|
210
|
-
* Word treats consecutive paragraphs whose border settings are IDENTICAL as ONE bordered
|
|
211
|
-
* block: the top rule draws above the first, the bottom rule below the last, and each
|
|
212
|
-
* interior boundary gets `w:between` or nothing (§17.3.1.24). That is why applying a box to
|
|
213
|
-
* three selected paragraphs in Word draws one box and not three.
|
|
214
|
-
*
|
|
215
|
-
* Empty string means "no borders", which never groups with anything.
|
|
216
|
-
*/
|
|
217
|
-
declare function paragraphBordersFingerprint(borders: ParagraphBorders): string;
|
|
218
|
-
/**
|
|
219
|
-
* Gap to insert before a paragraph once the previous paragraph's `after` is already in the
|
|
220
|
-
* flow cursor — Word takes the larger of the two rather than summing them.
|
|
221
|
-
*/
|
|
222
|
-
declare function collapsedSpaceBefore(before: number, previousAfter: number): number;
|
|
223
|
-
/**
|
|
224
|
-
* Applied before-spacing for placement (Word 2013+ / compat mode 15).
|
|
225
|
-
*
|
|
226
|
-
* Adjacent before/after still collapse to the larger gap, but before is dropped entirely when
|
|
227
|
-
* the paragraph begins at the top of a page mid-section. The first paragraph of a document or
|
|
228
|
-
* section retains before. Callers publish this applied value on the fragment so shading, borders,
|
|
229
|
-
* selection, and paint share one geometry.
|
|
230
|
-
*/
|
|
231
|
-
declare function appliedSpaceBefore(before: number, previousAfter: number, atTopOfPage: boolean, firstParagraphOfSection: boolean): number;
|
|
232
|
-
|
|
233
|
-
/** Soft ceiling matching Word's practical custom-tab UI limit. */
|
|
234
|
-
declare const MAX_TAB_STOPS = 64;
|
|
235
|
-
/**
|
|
236
|
-
* Soft ceiling on a tab position (31_680 twips ≈ 22"), matching paragraph-spacing bounds so
|
|
237
|
-
* a hostile stop cannot shove layout into pathological widths.
|
|
238
|
-
*/
|
|
239
|
-
declare const MAX_TAB_POSITION_TWIPS = 31680;
|
|
240
|
-
/** OOXML / Word default when `w:settings/w:defaultTabStop` is absent: 720 twips = 0.5". */
|
|
241
|
-
declare const DEFAULT_TAB_INTERVAL_TWIPS = 720;
|
|
242
|
-
/** The default tab interval in points — {@link DEFAULT_TAB_INTERVAL_TWIPS} converted. */
|
|
243
|
-
declare const DEFAULT_TAB_INTERVAL_PT: number;
|
|
244
|
-
/**
|
|
245
|
-
* How a tab stop positions the text that follows it.
|
|
246
|
-
*
|
|
247
|
-
* Only `left` is a plain cursor jump. The other three size the tab glyph from the MEASURED
|
|
248
|
-
* following segment, so its end, centre or decimal point lands on the stop.
|
|
249
|
-
*/
|
|
250
|
-
type TabAlignment = 'left' | 'center' | 'right' | 'decimal';
|
|
251
|
-
/**
|
|
252
|
-
* `w:tab/@w:leader` (ECMA-376 §17.3.1.38, ST_TabTlc): the character repeated across the
|
|
253
|
-
* space a tab reserves. `none` is the default and is represented by an absent leader.
|
|
254
|
-
*
|
|
255
|
-
* This is the difference between a Word table of contents and a column of headings floating
|
|
256
|
-
* next to a column of page numbers, so it is carried through layout to paint rather than
|
|
257
|
-
* dropped as a geometry-irrelevant attribute.
|
|
258
|
-
*/
|
|
259
|
-
type TabLeader = 'dot' | 'hyphen' | 'underscore' | 'heavy' | 'middleDot';
|
|
260
|
-
/**
|
|
261
|
-
* The character each leader repeats (§17.3.1.38, ST_TabTlc).
|
|
262
|
-
*
|
|
263
|
-
* Lives with the type rather than with the painter because LAYOUT has to measure it: a
|
|
264
|
-
* leader is the same character typed over and over, and the only way to space it the way
|
|
265
|
-
* typing it would is to ask the measurer how wide it actually is.
|
|
266
|
-
*/
|
|
267
|
-
declare const TAB_LEADER_GLYPH: ReadonlyMap<TabLeader, string>;
|
|
268
|
-
/** One authored `w:tab`: where it sits, how it aligns, and what fills the gap. */
|
|
269
|
-
interface TabStop {
|
|
270
|
-
/** Position from the paragraph content origin, in points. */
|
|
271
|
-
readonly positionPt: number;
|
|
272
|
-
readonly alignment: TabAlignment;
|
|
273
|
-
/** Absent for `none` — the schema default and the overwhelming majority of stops. */
|
|
274
|
-
readonly leader?: TabLeader;
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* A paragraph's tab stops after the style cascade, with the default interval that applies past
|
|
278
|
-
* the last explicit one.
|
|
279
|
-
*/
|
|
280
|
-
interface ResolvedTabStops {
|
|
281
|
-
/** Custom stops sorted by ascending position. */
|
|
282
|
-
readonly stops: readonly TabStop[];
|
|
283
|
-
/** Default-tab interval in points (always positive and bounded). */
|
|
284
|
-
readonly defaultIntervalPt: number;
|
|
285
|
-
}
|
|
286
|
-
/** The frozen "no custom stops" value, so a paragraph without tabs mints no object. */
|
|
287
|
-
declare const EMPTY_TAB_STOPS: ResolvedTabStops;
|
|
288
|
-
/**
|
|
289
|
-
* Resolve tab stops from cascaded `w:pPr` nodes (docDefaults → style chain → direct).
|
|
290
|
-
*
|
|
291
|
-
* Each `w:tabs` merges with `clear` support; absence inherits. The leader travels with the
|
|
292
|
-
* stop that declared it — a `clear` at the same position discards both together.
|
|
293
|
-
*/
|
|
294
|
-
declare function cascadedTabStops(paragraphPropertyNodes: readonly OoxmlNode[]): ResolvedTabStops;
|
|
295
|
-
/** Direct `w:pPr` only — used when no style cascade table is present. */
|
|
296
|
-
declare function paragraphTabStops(pPr: OoxmlNode | undefined): ResolvedTabStops;
|
|
297
|
-
/**
|
|
298
|
-
* Republish stops under a document-wide default-tab interval (`w:defaultTabStop`).
|
|
299
|
-
*
|
|
300
|
-
* The cascade resolves stops from the paragraph's own property chain, which cannot see
|
|
301
|
-
* `settings.xml`; the interval is a document constant that arrives from the session. Returns
|
|
302
|
-
* the input unchanged when nothing moves, so a cache-key fingerprint stays stable.
|
|
303
|
-
*/
|
|
304
|
-
declare function withDefaultTabInterval(tabs: ResolvedTabStops, defaultIntervalPt: number | undefined): ResolvedTabStops;
|
|
305
|
-
/**
|
|
306
|
-
* Read `w:settings/w:defaultTabStop` (ECMA-376 §17.15.1.25), in points.
|
|
307
|
-
*
|
|
308
|
-
* Word's own interval, not a constant: a metric-locale template writes `w:val="1134"` (2cm)
|
|
309
|
-
* and every default-interval tab in the document lands on that grid instead of the 0.5"
|
|
310
|
-
* one. The value is FILE-DERIVED, so a non-integer, non-positive or out-of-range `val` falls
|
|
311
|
-
* back to the schema default rather than being trusted into layout arithmetic.
|
|
312
|
-
*
|
|
313
|
-
* `ST_TwipsMeasure` also admits a universal measure (`"2cm"`); Word writes plain twips, and
|
|
314
|
-
* the spelled form falls back to the default rather than being parsed here.
|
|
315
|
-
*/
|
|
316
|
-
declare function defaultTabIntervalFromSettings(settings: OoxmlNode | null | undefined): number;
|
|
317
|
-
/** Where one tab character lands: the resolved x, and the stop that decided it. */
|
|
318
|
-
interface TabDestination {
|
|
319
|
-
readonly positionPt: number;
|
|
320
|
-
readonly alignment: TabAlignment;
|
|
321
|
-
/** Leader of the stop that was reached; absent for `none` and for default-interval tabs. */
|
|
322
|
-
readonly leader?: TabLeader;
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Next tab destination strictly past `currentX`, preferring custom stops then the default
|
|
326
|
-
* interval. Destination is clamped to `rightEdge` so stops cannot escape the content box.
|
|
327
|
-
*/
|
|
328
|
-
declare function nextTabDestination(tabs: ResolvedTabStops, currentX: number, rightEdge: number): TabDestination;
|
|
329
|
-
/**
|
|
330
|
-
* Width of a tab glyph so the following segment lands on the destination.
|
|
331
|
-
*
|
|
332
|
-
* `segmentWidth` / `decimalOffset` are already measured in points. Decimal offset is the
|
|
333
|
-
* advance from the segment start to the decimal point (0 when none — treated like right).
|
|
334
|
-
*/
|
|
335
|
-
declare function tabAdvanceWidth(alignment: TabAlignment, currentX: number, destinationX: number, segmentWidth: number, decimalOffset: number): number;
|
|
336
|
-
/**
|
|
337
|
-
* Stable fingerprint for layout cache keys — nested `w:tabs` are not in flat `OoxmlProperty`
|
|
338
|
-
* bags, so style-inherited stops must be named explicitly or breaks would collide.
|
|
339
|
-
*/
|
|
340
|
-
declare function tabStopsFingerprint(tabs: ResolvedTabStops): string;
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* UAX #9 embedding levels, one per UTF-16 code unit, plus the paragraph ranges they were resolved
|
|
344
|
-
* within.
|
|
345
|
-
*
|
|
346
|
-
* The level is EXACT, not a direction: its parity gives direction, but the numeric value is what
|
|
347
|
-
* reordering needs, and collapsing it early loses nested isolates.
|
|
348
|
-
*/
|
|
349
|
-
interface BidiEmbeddingLevels {
|
|
350
|
-
readonly levels: Uint8Array;
|
|
351
|
-
readonly paragraphs: readonly {
|
|
352
|
-
readonly start: number;
|
|
353
|
-
readonly end: number;
|
|
354
|
-
readonly level: number;
|
|
355
|
-
}[];
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* A face, as something asks for it: family plus the two axes this engine admits.
|
|
360
|
-
*
|
|
361
|
-
* Only static weights and slants. Variable-font axes are deliberately outside this vocabulary —
|
|
362
|
-
* the shaper refuses variation axes, and a variable file admitted here would render bold at
|
|
363
|
-
* regular weight.
|
|
364
|
-
*/
|
|
365
|
-
interface FontRequest {
|
|
366
|
-
readonly family: string;
|
|
367
|
-
readonly weight: number;
|
|
368
|
-
readonly style: 'normal' | 'italic';
|
|
369
|
-
}
|
|
370
|
-
/**
|
|
371
|
-
* A request that was answered by a DIFFERENT face than the one asked for.
|
|
372
|
-
*
|
|
373
|
-
* Recorded rather than silently applied, because a substitution changes measurement: it is part
|
|
374
|
-
* of the shaping fingerprint, so a cached run shaped against a substitute is never reused for the
|
|
375
|
-
* real face.
|
|
376
|
-
*/
|
|
377
|
-
interface FontSubstitution {
|
|
378
|
-
readonly requested: FontRequest;
|
|
379
|
-
readonly resolved: FontRequest;
|
|
380
|
-
readonly lineMetrics?: {
|
|
381
|
-
readonly heightEm: number;
|
|
382
|
-
readonly baselineEm: number;
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
declare const RESOLVED_FONT_BRAND: unique symbol;
|
|
386
|
-
/**
|
|
387
|
-
* A face that passed admission: the bytes are present, within limits, hash-verified, and parse as
|
|
388
|
-
* a font.
|
|
389
|
-
*
|
|
390
|
-
* Branded, so a `ResolvedFont` cannot be constructed by an object literal. Holding one is proof
|
|
391
|
-
* the checks ran — which is what lets shaping skip re-validating on every call.
|
|
392
|
-
*/
|
|
393
|
-
interface ResolvedFont {
|
|
394
|
-
readonly [RESOLVED_FONT_BRAND]: true;
|
|
395
|
-
readonly id: string;
|
|
396
|
-
readonly identity: string;
|
|
397
|
-
readonly request: FontRequest;
|
|
398
|
-
readonly family: string;
|
|
399
|
-
/** Owned byte length, available without creating a defensive byte copy. */
|
|
400
|
-
readonly byteLength: number;
|
|
401
|
-
readonly bytes: Uint8Array;
|
|
402
|
-
readonly hash: string;
|
|
403
|
-
readonly faceIndex: number;
|
|
404
|
-
readonly substitution: FontSubstitution | null;
|
|
405
|
-
}
|
|
406
|
-
/**
|
|
407
|
-
* Largest single face this engine will ever admit, whatever a caller configures.
|
|
408
|
-
*
|
|
409
|
-
* A CEILING, not a default: a host may set a smaller `maxFontBytes`, but nothing can raise it
|
|
410
|
-
* past this. Font bytes come from files, and an unbounded face is a memory-exhaustion vector.
|
|
411
|
-
*/
|
|
412
|
-
declare const HARD_MAX_FONT_BYTES: number;
|
|
413
|
-
/** Most faces one snapshot may hold, whatever a caller configures. */
|
|
414
|
-
declare const HARD_MAX_FONT_SOURCES = 256;
|
|
415
|
-
/** Most bytes all admitted faces may total, whatever a caller configures. */
|
|
416
|
-
declare const HARD_MAX_AGGREGATE_FONT_BYTES: number;
|
|
417
|
-
/**
|
|
418
|
-
* Why a face was not admitted.
|
|
419
|
-
*
|
|
420
|
-
* `forbidden` and `hashMismatch` are adversarial signals rather than ordinary failures: the first
|
|
421
|
-
* is a face the host declared off-limits, the second is bytes that are not what their source
|
|
422
|
-
* claimed.
|
|
423
|
-
*/
|
|
424
|
-
type FontResolutionErrorCode = 'missing' | 'forbidden' | 'overLimit' | 'malformed' | 'hashMismatch';
|
|
425
|
-
/**
|
|
426
|
-
* A face that could not be admitted, carrying whatever evidence the refusal produced.
|
|
427
|
-
*
|
|
428
|
-
* RETURNED rather than thrown by `FontResourceSnapshot.resolve`, because a missing face is an
|
|
429
|
-
* ordinary condition — layout falls back and carries on. It extends `Error` so a caller that
|
|
430
|
-
* would rather throw can.
|
|
431
|
-
*/
|
|
432
|
-
declare class FontResolutionError extends Error {
|
|
433
|
-
readonly name = "FontResolutionError";
|
|
434
|
-
readonly request: FontRequest;
|
|
435
|
-
readonly code: FontResolutionErrorCode;
|
|
436
|
-
readonly limit?: number;
|
|
437
|
-
readonly actual?: number;
|
|
438
|
-
readonly diagnostic?: string;
|
|
439
|
-
readonly expectedHash?: string;
|
|
440
|
-
readonly actualHash?: string;
|
|
441
|
-
constructor(code: FontResolutionErrorCode, request: FontRequest, details?: {
|
|
442
|
-
readonly limit?: number;
|
|
443
|
-
readonly actual?: number;
|
|
444
|
-
readonly diagnostic?: string;
|
|
445
|
-
readonly expectedHash?: string;
|
|
446
|
-
readonly actualHash?: string;
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
/**
|
|
450
|
-
* One face offered to a snapshot, before admission.
|
|
451
|
-
*
|
|
452
|
-
* `hash` is checked against the bytes, so a source cannot claim a face it did not supply. Setting
|
|
453
|
-
* `availability` to `forbidden` declares a face that exists but must not be used, which resolves
|
|
454
|
-
* as a typed refusal rather than as "missing".
|
|
455
|
-
*/
|
|
456
|
-
interface FontResourceDefinition {
|
|
457
|
-
readonly request: FontRequest;
|
|
458
|
-
readonly id: string;
|
|
459
|
-
readonly bytes: Uint8Array;
|
|
460
|
-
readonly hash: string;
|
|
461
|
-
readonly faceIndex: number;
|
|
462
|
-
readonly availability?: 'available' | 'forbidden';
|
|
463
|
-
}
|
|
464
|
-
/**
|
|
465
|
-
* A host-declared redirect: requests for `from` resolve to `to`.
|
|
466
|
-
*
|
|
467
|
-
* How a metric-compatible substitute is wired in — a document naming Calibri resolves to Carlito
|
|
468
|
-
* without the document being rewritten.
|
|
469
|
-
*/
|
|
470
|
-
interface DeclaredFontSubstitution {
|
|
471
|
-
readonly from: FontRequest;
|
|
472
|
-
readonly to: FontRequest;
|
|
473
|
-
readonly lineMetrics?: {
|
|
474
|
-
readonly heightEm: number;
|
|
475
|
-
readonly baselineEm: number;
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
/** Whether bytes parse as a usable font, with a diagnostic when they do not. */
|
|
479
|
-
type FontValidationResult = {
|
|
480
|
-
readonly valid: true;
|
|
481
|
-
} | {
|
|
482
|
-
readonly valid: false;
|
|
483
|
-
readonly diagnostic: string;
|
|
484
|
-
};
|
|
485
|
-
/**
|
|
486
|
-
* The injected check that bytes really are a font.
|
|
487
|
-
*
|
|
488
|
-
* Injected because it is the shaper that knows — HarfBuzz can open a face and read its tables,
|
|
489
|
-
* and this layer must not duplicate that judgement. Every byte reaching it is file input.
|
|
490
|
-
*/
|
|
491
|
-
type FontByteValidator = (bytes: Uint8Array, faceIndex: number) => FontValidationResult;
|
|
492
|
-
/**
|
|
493
|
-
* An immutable set of admitted faces, and the only way to reach one.
|
|
494
|
-
*
|
|
495
|
-
* `epoch` identifies the snapshot: fonts change by REPLACING it, never by mutation, so a layout
|
|
496
|
-
* pass holds one snapshot for its whole run and cannot observe a face appearing or vanishing
|
|
497
|
-
* midway.
|
|
498
|
-
*/
|
|
499
|
-
interface FontResourceSnapshot {
|
|
500
|
-
readonly epoch: number;
|
|
501
|
-
/** The admitted face, or a typed refusal. Never throws. */
|
|
502
|
-
resolve(request: FontRequest): ResolvedFont | FontResolutionError;
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* How a snapshot is built: which faces, under what limits, validated how.
|
|
506
|
-
*
|
|
507
|
-
* `maxFontBytes` is clamped to {@link HARD_MAX_FONT_BYTES} — a caller may tighten the budget but
|
|
508
|
-
* never widen it past the engine's own ceiling.
|
|
509
|
-
*/
|
|
510
|
-
interface FontResourceSnapshotOptions {
|
|
511
|
-
readonly epoch: number;
|
|
512
|
-
readonly maxFontBytes: number;
|
|
513
|
-
readonly resources: readonly FontResourceDefinition[];
|
|
514
|
-
readonly substitutions?: readonly DeclaredFontSubstitution[];
|
|
515
|
-
readonly validateFont: FontByteValidator;
|
|
516
|
-
readonly instrumentation?: FontResourceInstrumentation;
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Optional counters for the operations font admission is expected to do RARELY.
|
|
520
|
-
*
|
|
521
|
-
* Exists so tests can assert the absence of work: hashing and byte-copying a 64 MB face on every
|
|
522
|
-
* resolve would not be visible in output, only in a stalled document, so the checks assert these
|
|
523
|
-
* fire once rather than per call.
|
|
524
|
-
*/
|
|
525
|
-
interface FontResourceInstrumentation {
|
|
526
|
-
readonly onOwnedByteCopy?: () => void;
|
|
527
|
-
readonly onHash?: () => void;
|
|
528
|
-
readonly onTableScan?: () => void;
|
|
529
|
-
readonly onAdmission?: () => void;
|
|
530
|
-
}
|
|
531
|
-
/**
|
|
532
|
-
* The canonical string identifying one face request.
|
|
533
|
-
*
|
|
534
|
-
* Case- and whitespace-normalized, so `"Times New Roman"` and `"times new roman"` are one key —
|
|
535
|
-
* a document may name a family either way and both must reach the same face.
|
|
536
|
-
*/
|
|
537
|
-
declare const fontRequestKey: (request: FontRequest) => string;
|
|
538
|
-
/** Bounded minimum sfnt/TTC check; Task 4 supplies full parser-backed validation. */
|
|
539
|
-
declare const boundedStructuralFontValidator: FontByteValidator;
|
|
540
|
-
/**
|
|
541
|
-
* Admit a set of faces and return the immutable snapshot layout resolves against.
|
|
542
|
-
*
|
|
543
|
-
* Admission is the trust boundary for font bytes: counts and sizes are checked against the hard
|
|
544
|
-
* ceilings, each face's hash is re-derived and compared, and the bytes are handed to the injected
|
|
545
|
-
* validator. A face failing any of these is recorded as a typed refusal rather than dropped, so
|
|
546
|
-
* `resolve` can explain itself instead of answering "missing".
|
|
547
|
-
*/
|
|
548
|
-
declare const createFontResourceSnapshot: (options: FontResourceSnapshotOptions) => FontResourceSnapshot;
|
|
549
|
-
|
|
550
|
-
declare const FIXED_POINT: unique symbol;
|
|
551
|
-
/** Fixed-point coordinates are safe integers in units declared by ShapingEnvironment.fixedPointScale. */
|
|
552
|
-
type FixedPoint = number & {
|
|
553
|
-
readonly [FIXED_POINT]: true;
|
|
554
|
-
};
|
|
555
|
-
/**
|
|
556
|
-
* Brand a safe integer as a {@link FixedPoint} coordinate.
|
|
557
|
-
*
|
|
558
|
-
* Fixed point rather than float throughout shaping so that two runs shaped identically compare
|
|
559
|
-
* EQUAL — float accumulation would make the same text measure differently depending on how it was
|
|
560
|
-
* split, and pagination is decided on those measurements.
|
|
561
|
-
*
|
|
562
|
-
* @throws RangeError when the value is not a safe integer.
|
|
563
|
-
*/
|
|
564
|
-
declare const fixedPoint: (value: number) => FixedPoint;
|
|
565
|
-
/** Which way a run reads. The parity projection of its bidi embedding level. */
|
|
566
|
-
type TextDirection = 'ltr' | 'rtl';
|
|
567
|
-
/** How fixed-point conversion breaks ties. Part of the shaping fingerprint. */
|
|
568
|
-
type FixedPointRoundingMode = 'halfAwayFromZero' | 'halfToEven' | 'towardZero';
|
|
569
|
-
/** Which Unicode normalization is applied before shaping, if any. */
|
|
570
|
-
type NormalizationPolicy = 'none' | 'NFC' | 'NFD' | 'NFKC' | 'NFKD';
|
|
571
|
-
/**
|
|
572
|
-
* The shaping library and its exact version.
|
|
573
|
-
*
|
|
574
|
-
* Versioned because a library upgrade can change glyph positioning, and a cached measurement
|
|
575
|
-
* taken under the old one must not be reused under the new one.
|
|
576
|
-
*/
|
|
577
|
-
interface VersionedShapingLibrary {
|
|
578
|
-
readonly name: string;
|
|
579
|
-
readonly version: string;
|
|
580
|
-
}
|
|
581
|
-
/**
|
|
582
|
-
* Everything that determines how text shapes — the complete input to a
|
|
583
|
-
* {@link ShapingEnvironment}.
|
|
584
|
-
*
|
|
585
|
-
* Exhaustive on purpose. Any field that could change a glyph's position belongs here, because the
|
|
586
|
-
* environment's fingerprint is what decides whether a cached shaped run may be reused.
|
|
587
|
-
*/
|
|
588
|
-
interface ShapingEnvironmentInput {
|
|
589
|
-
readonly font: ResolvedFont;
|
|
590
|
-
readonly variationAxes: Readonly<Record<string, number>>;
|
|
591
|
-
readonly shapingLibrary: VersionedShapingLibrary;
|
|
592
|
-
readonly unicodeDataVersion: string;
|
|
593
|
-
readonly normalization: NormalizationPolicy;
|
|
594
|
-
readonly script: string;
|
|
595
|
-
readonly language: string;
|
|
596
|
-
readonly direction: TextDirection;
|
|
597
|
-
readonly features: Readonly<Record<string, number>>;
|
|
598
|
-
readonly fallbackOrder: readonly ResolvedFont[];
|
|
599
|
-
readonly fixedPointScale: number;
|
|
600
|
-
readonly roundingMode: FixedPointRoundingMode;
|
|
601
|
-
}
|
|
602
|
-
/**
|
|
603
|
-
* A validated {@link ShapingEnvironmentInput} — build one with `createShapingEnvironment`.
|
|
604
|
-
*
|
|
605
|
-
* Structurally identical to its input, but the nominal distinction is the point: holding one
|
|
606
|
-
* means the tags, axes and fonts inside it have already been checked.
|
|
607
|
-
*/
|
|
608
|
-
interface ShapingEnvironment extends ShapingEnvironmentInput {
|
|
609
|
-
}
|
|
610
|
-
/** One shaping call: the text, its size, its bidi level, and the environment to shape it in. */
|
|
611
|
-
interface ShapeInput {
|
|
612
|
-
readonly text: string;
|
|
613
|
-
readonly fontSizeHalfPoints: number;
|
|
614
|
-
/** Exact UAX #9 embedding/isolate level; direction is its parity projection. */
|
|
615
|
-
readonly bidiLevel: number;
|
|
616
|
-
readonly environment: ShapingEnvironment;
|
|
617
|
-
}
|
|
618
|
-
/**
|
|
619
|
-
* One positioned glyph.
|
|
620
|
-
*
|
|
621
|
-
* `id` is a glyph index in its FACE, not a character — a ligature is one glyph spanning several
|
|
622
|
-
* characters, and a single character may produce several glyphs. Use `cluster` to get back to
|
|
623
|
-
* text.
|
|
624
|
-
*/
|
|
625
|
-
interface ShapedGlyph {
|
|
626
|
-
readonly id: number;
|
|
627
|
-
/** UTF-16 text offset identifying the cluster that produced this glyph. */
|
|
628
|
-
readonly cluster: number;
|
|
629
|
-
/** Pen origin before this glyph's shaping offsets, in fixed-point run coordinates. */
|
|
630
|
-
readonly originX: FixedPoint;
|
|
631
|
-
readonly originY: FixedPoint;
|
|
632
|
-
readonly advanceX: FixedPoint;
|
|
633
|
-
readonly advanceY: FixedPoint;
|
|
634
|
-
readonly offsetX: FixedPoint;
|
|
635
|
-
readonly offsetY: FixedPoint;
|
|
636
|
-
/** Exact monochrome outline returned by the admitted HarfBuzz face. */
|
|
637
|
-
readonly outline: GlyphOutline;
|
|
638
|
-
}
|
|
639
|
-
/** A glyph's outline as SVG path data, in font design units. */
|
|
640
|
-
interface GlyphOutline {
|
|
641
|
-
readonly path: string;
|
|
642
|
-
/** Design units per em — divide by this to scale the path to a point size. */
|
|
643
|
-
readonly unitsPerEm: number;
|
|
644
|
-
}
|
|
645
|
-
/**
|
|
646
|
-
* One cluster: the smallest indivisible text-to-glyph correspondence.
|
|
647
|
-
*
|
|
648
|
-
* The unit the CARET moves by. A cluster may be several characters (a ligature) or several glyphs
|
|
649
|
-
* (a decomposed mark), so neither a character index nor a glyph index is a valid caret position —
|
|
650
|
-
* `caretEdges` is, and it includes both endpoints.
|
|
651
|
-
*/
|
|
652
|
-
interface ShapedCluster {
|
|
653
|
-
/** Half-open logical UTF-16 range in ShapedRun.text. */
|
|
654
|
-
readonly textStart: number;
|
|
655
|
-
readonly textEnd: number;
|
|
656
|
-
/** Half-open visual glyph range in ShapedRun.glyphs. */
|
|
657
|
-
readonly glyphStart: number;
|
|
658
|
-
readonly glyphEnd: number;
|
|
659
|
-
readonly advance: FixedPoint;
|
|
660
|
-
/** Fixed-point edges from this cluster's visual origin, including both endpoints. */
|
|
661
|
-
readonly caretEdges: readonly FixedPoint[];
|
|
662
|
-
/** Index into ShapedRun.fontSpans, preserving the exact fallback choice. */
|
|
663
|
-
readonly fontSpan: number;
|
|
664
|
-
}
|
|
665
|
-
/** A run's vertical metrics, from the face that shaped it. Drives line height and baseline. */
|
|
666
|
-
interface ShapedVerticalMetrics {
|
|
667
|
-
readonly ascent: FixedPoint;
|
|
668
|
-
readonly descent: FixedPoint;
|
|
669
|
-
readonly lineGap: FixedPoint;
|
|
670
|
-
}
|
|
671
|
-
/**
|
|
672
|
-
* A stretch of glyphs that came from ONE face.
|
|
673
|
-
*
|
|
674
|
-
* A run whose text needed fallback has several of these. Recording the exact face per span is
|
|
675
|
-
* what lets a re-shape reproduce the same result rather than re-running fallback selection and
|
|
676
|
-
* possibly choosing differently.
|
|
677
|
-
*/
|
|
678
|
-
interface ShapedFontSpan {
|
|
679
|
-
readonly glyphStart: number;
|
|
680
|
-
readonly glyphEnd: number;
|
|
681
|
-
readonly font: ResolvedFont;
|
|
682
|
-
/** null denotes the primary font; otherwise this is the environment fallback-order index. */
|
|
683
|
-
readonly fallbackIndex: number | null;
|
|
684
|
-
}
|
|
685
|
-
/**
|
|
686
|
-
* One shaped run: text turned into positioned glyphs, with everything needed to measure it, paint
|
|
687
|
-
* it, and put a caret in it.
|
|
688
|
-
*
|
|
689
|
-
* The engine's measurement unit. Layout never measures characters — it measures these.
|
|
690
|
-
*/
|
|
691
|
-
interface ShapedRun {
|
|
692
|
-
readonly text: string;
|
|
693
|
-
readonly direction: TextDirection;
|
|
694
|
-
readonly bidiLevel: number;
|
|
695
|
-
readonly glyphs: readonly ShapedGlyph[];
|
|
696
|
-
readonly clusters: readonly ShapedCluster[];
|
|
697
|
-
readonly fontSpans: readonly ShapedFontSpan[];
|
|
698
|
-
readonly metrics: ShapedVerticalMetrics;
|
|
699
|
-
}
|
|
700
|
-
/**
|
|
701
|
-
* A {@link ShapedRun} reduced to the fields two shaping results must agree on to be considered
|
|
702
|
-
* identical.
|
|
703
|
-
*
|
|
704
|
-
* Fonts appear as {@link FontFingerprintInputs} rather than whole `ResolvedFont` objects, so the
|
|
705
|
-
* comparison is over VALUES and does not depend on object identity — which is what makes it work
|
|
706
|
-
* across a reload or a worker boundary.
|
|
707
|
-
*/
|
|
708
|
-
interface ShapedRunComparatorInputs {
|
|
709
|
-
readonly text: string;
|
|
710
|
-
readonly direction: TextDirection;
|
|
711
|
-
readonly script: string;
|
|
712
|
-
readonly language: string;
|
|
713
|
-
readonly bidiLevel: number;
|
|
714
|
-
readonly glyphs: readonly ShapedGlyph[];
|
|
715
|
-
readonly clusters: readonly ShapedCluster[];
|
|
716
|
-
readonly fontSpans: readonly {
|
|
717
|
-
readonly glyphStart: number;
|
|
718
|
-
readonly glyphEnd: number;
|
|
719
|
-
readonly fallbackIndex: number | null;
|
|
720
|
-
readonly font: FontFingerprintInputs;
|
|
721
|
-
}[];
|
|
722
|
-
readonly metrics: ShapedVerticalMetrics;
|
|
723
|
-
}
|
|
724
|
-
/**
|
|
725
|
-
* The one thing layout needs from a shaping backend.
|
|
726
|
-
*
|
|
727
|
-
* Injected rather than imported, which is what keeps layout DOM-free and testable: a fixed-metric
|
|
728
|
-
* shaper measures deterministically in a test, HarfBuzz measures for real in a browser, and
|
|
729
|
-
* layout cannot tell the difference.
|
|
730
|
-
*/
|
|
731
|
-
interface TextShaper {
|
|
732
|
-
shape(input: ShapeInput): ShapedRun;
|
|
733
|
-
}
|
|
734
|
-
/**
|
|
735
|
-
* A font reduced to the values that identify it for fingerprinting.
|
|
736
|
-
*
|
|
737
|
-
* Includes the content `hash` and `faceIndex`, so two faces with the same family name but
|
|
738
|
-
* different bytes fingerprint differently — which is what stops a cached measurement being reused
|
|
739
|
-
* against a substituted face.
|
|
740
|
-
*/
|
|
741
|
-
interface FontFingerprintInputs {
|
|
742
|
-
readonly identity: string;
|
|
743
|
-
readonly id: string;
|
|
744
|
-
readonly family: string;
|
|
745
|
-
readonly request: FontRequest;
|
|
746
|
-
readonly hash: string;
|
|
747
|
-
readonly faceIndex: number;
|
|
748
|
-
readonly byteLength: number;
|
|
749
|
-
readonly substitution: FontSubstitution | null;
|
|
750
|
-
}
|
|
751
|
-
/**
|
|
752
|
-
* A {@link ShapingEnvironment} reduced to comparable values.
|
|
753
|
-
*
|
|
754
|
-
* Records and axis maps become SORTED entry arrays, because two environments differing only in
|
|
755
|
-
* key insertion order must fingerprint the same — otherwise a cache would miss on a difference
|
|
756
|
-
* that changes no glyph.
|
|
757
|
-
*/
|
|
758
|
-
interface ShapingEnvironmentFingerprintInputs {
|
|
759
|
-
readonly font: FontFingerprintInputs;
|
|
760
|
-
readonly variationAxes: readonly (readonly [string, number])[];
|
|
761
|
-
readonly shapingLibrary: VersionedShapingLibrary;
|
|
762
|
-
readonly unicodeDataVersion: string;
|
|
763
|
-
readonly normalization: NormalizationPolicy;
|
|
764
|
-
readonly script: string;
|
|
765
|
-
readonly language: string;
|
|
766
|
-
readonly direction: TextDirection;
|
|
767
|
-
readonly features: readonly (readonly [string, number])[];
|
|
768
|
-
readonly fallbackOrder: readonly FontFingerprintInputs[];
|
|
769
|
-
readonly fixedPointScale: number;
|
|
770
|
-
readonly roundingMode: FixedPointRoundingMode;
|
|
771
|
-
}
|
|
772
|
-
/**
|
|
773
|
-
* Validate and freeze a shaping environment.
|
|
774
|
-
*
|
|
775
|
-
* Checks every field that could silently corrupt a measurement: OpenType tags must be four ASCII
|
|
776
|
-
* bytes, script and language must be non-blank and control-character free, fonts must already be
|
|
777
|
-
* validated. Throws rather than coercing — a bad tag that shapes anyway produces a document that
|
|
778
|
-
* measures wrong everywhere and looks fine.
|
|
779
|
-
*
|
|
780
|
-
* @throws TypeError on a malformed tag, name, or axis value.
|
|
781
|
-
*/
|
|
782
|
-
declare const createShapingEnvironment: (input: ShapingEnvironmentInput) => ShapingEnvironment;
|
|
783
|
-
/**
|
|
784
|
-
* Reduce an environment to its comparable form, with records sorted so key order cannot affect
|
|
785
|
-
* the result.
|
|
786
|
-
*/
|
|
787
|
-
declare const shapingEnvironmentFingerprintInputs: (input: ShapingEnvironmentInput) => ShapingEnvironmentFingerprintInputs;
|
|
788
|
-
/** Canonical serialization of every shaping variable, including byte hash and provenance. */
|
|
789
|
-
declare const shapingEnvironmentFingerprint: (environment: ShapingEnvironmentInput) => string;
|
|
790
|
-
/**
|
|
791
|
-
* Validate and freeze a shaped run against the environment that produced it.
|
|
792
|
-
*
|
|
793
|
-
* Checks the internal consistency a shaper must satisfy: direction matches the environment,
|
|
794
|
-
* cluster ranges tile the text without gaps or overlap, glyph ranges stay in bounds, font spans
|
|
795
|
-
* cover every glyph, and caret edges are monotonic. A shaper that violates any of these produces
|
|
796
|
-
* a caret that lands in the wrong place, which is far harder to diagnose downstream than here.
|
|
797
|
-
*
|
|
798
|
-
* @throws TypeError when the run and environment disagree, or the run is internally inconsistent.
|
|
799
|
-
*/
|
|
800
|
-
declare const createShapedRun: (input: ShapedRun, environmentInput: ShapingEnvironmentInput) => ShapedRun;
|
|
801
|
-
/**
|
|
802
|
-
* Reduce a shaped run to its comparable form, validating it on the way through.
|
|
803
|
-
*
|
|
804
|
-
* What the D9 determinism oracles compare: two shaping runs of the same text in the same
|
|
805
|
-
* environment must produce byte-identical structures here.
|
|
806
|
-
*/
|
|
807
|
-
declare const shapedRunComparatorInputs: (input: ShapedRun, environment: ShapingEnvironmentInput) => ShapedRunComparatorInputs;
|
|
808
|
-
|
|
809
|
-
/** `w:vertAlign` — script position, which also scales the run's effective size. */
|
|
810
|
-
type VerticalAlign = 'baseline' | 'superscript' | 'subscript';
|
|
811
|
-
/** A resolved underline: its variant, and its colour when it does not follow the text. */
|
|
812
|
-
interface ResolvedUnderline {
|
|
813
|
-
/** The authored `ST_Underline` variant. */
|
|
814
|
-
readonly variant: string;
|
|
815
|
-
/** RRGGBB, or null when the underline follows the text colour. */
|
|
816
|
-
readonly color: string | null;
|
|
817
|
-
}
|
|
818
|
-
/**
|
|
819
|
-
* A run's character properties after the full cascade, in the units layout works in.
|
|
820
|
-
*
|
|
821
|
-
* Points rather than half-points, RRGGBB rather than theme references — everything already
|
|
822
|
-
* resolved, so measurement and paint never re-run the cascade per glyph.
|
|
823
|
-
*/
|
|
824
|
-
interface ResolvedRunStyle {
|
|
825
|
-
readonly fontFamily: string | null;
|
|
826
|
-
/**
|
|
827
|
-
* The `eastAsia` slot's typeface (`w:rFonts w:eastAsia`/`w:eastAsiaTheme`), or null when
|
|
828
|
-
* no level authors one.
|
|
829
|
-
*
|
|
830
|
-
* OOXML picks a run's face per SCRIPT: `fontFamily` covers the ascii/hAnsi slots, and
|
|
831
|
-
* ideographic/kana/hangul text resolves through this one instead. Kept beside — not
|
|
832
|
-
* folded into — `fontFamily`, because a mixed run needs both at once and the split into
|
|
833
|
-
* slot-homogeneous pieces happens downstream (`piecesOfParagraph`).
|
|
834
|
-
*/
|
|
835
|
-
readonly fontFamilyEastAsia: string | null;
|
|
836
|
-
/** Points. `w:sz` is half-points, so 22 becomes 11. */
|
|
837
|
-
readonly fontSizePt: number;
|
|
838
|
-
/** RRGGBB, or null for the inherited/automatic colour. */
|
|
839
|
-
readonly color: string | null;
|
|
840
|
-
readonly bold: boolean;
|
|
841
|
-
readonly italic: boolean;
|
|
842
|
-
readonly underline: ResolvedUnderline | null;
|
|
843
|
-
readonly strike: boolean;
|
|
844
|
-
readonly doubleStrike: boolean;
|
|
845
|
-
/** An `ST_HighlightColor` name, or null. */
|
|
846
|
-
readonly highlight: string | null;
|
|
847
|
-
/**
|
|
848
|
-
* Character shading fill (`w:rPr/w:shd`), validated RRGGBB, or null.
|
|
849
|
-
*
|
|
850
|
-
* Paint applies this as the glyph-box background; a recognised highlight overrides it.
|
|
851
|
-
* Measurement ignores shading.
|
|
852
|
-
*/
|
|
853
|
-
readonly shading: string | null;
|
|
854
|
-
readonly verticalAlign: VerticalAlign;
|
|
855
|
-
/** `w:position`, in points. Positive raises the baseline. */
|
|
856
|
-
readonly baselineShiftPt: number;
|
|
857
|
-
readonly caps: boolean;
|
|
858
|
-
readonly smallCaps: boolean;
|
|
859
|
-
/** `w:spacing`, in points. Added to every advance. */
|
|
860
|
-
readonly characterSpacingPt: number;
|
|
861
|
-
/** `w:w`, as a percentage. 100 is unscaled. */
|
|
862
|
-
readonly horizontalScalePercent: number;
|
|
863
|
-
/** `w:kern`, in points: the size at or above which kerning applies. 0 disables it. */
|
|
864
|
-
readonly kerningMinPt: number;
|
|
865
|
-
/**
|
|
866
|
-
* `w:vanish` (ECMA-376 §17.3.2.45): the run is hidden text.
|
|
867
|
-
*
|
|
868
|
-
* Word does not draw it AND does not paginate it — hidden index or comment text takes no
|
|
869
|
-
* space at all. So this cannot be a paint-time opacity: a hidden run that is still measured
|
|
870
|
-
* pushes every following line, and every following page break, to the wrong place. Layout
|
|
871
|
-
* drops the content instead (see `piecesOfParagraph`).
|
|
872
|
-
*
|
|
873
|
-
* `w:specVanish` (§17.3.2.36) is a different property — an always-hidden paragraph mark on
|
|
874
|
-
* a heading — and never sets this.
|
|
875
|
-
*/
|
|
876
|
-
readonly hidden: boolean;
|
|
877
|
-
}
|
|
878
|
-
/** The style a run inherits when it authors nothing. */
|
|
879
|
-
declare const DEFAULT_RUN_STYLE: ResolvedRunStyle;
|
|
880
|
-
/**
|
|
881
|
-
* The theme part's typefaces, for resolving `w:rFonts` theme attributes.
|
|
882
|
-
*
|
|
883
|
-
* Structurally identical to the binding lane's `DocumentThemeFonts` and assignable from it.
|
|
884
|
-
* Declared here so this lane reads validated strings rather than the theme tree.
|
|
885
|
-
*/
|
|
886
|
-
interface ThemeFonts {
|
|
887
|
-
/** `a:majorFont` latin typeface — headings. */
|
|
888
|
-
readonly major: string | null;
|
|
889
|
-
/** `a:minorFont` latin typeface — body text. */
|
|
890
|
-
readonly minor: string | null;
|
|
891
|
-
/** `a:majorFont` east asian typeface (`a:ea`) — headings. Optional for back-compat. */
|
|
892
|
-
readonly majorEastAsia?: string | null;
|
|
893
|
-
/** `a:minorFont` east asian typeface (`a:ea`) — body text. Optional for back-compat. */
|
|
894
|
-
readonly minorEastAsia?: string | null;
|
|
895
|
-
}
|
|
896
|
-
/**
|
|
897
|
-
* Resolve one run's direct formatting.
|
|
898
|
-
*
|
|
899
|
-
* Unrecognised values are DROPPED rather than guessed: a `w:sz` of `"large"` leaves the
|
|
900
|
-
* default size rather than inventing one, because a wrong measurement moves every glyph
|
|
901
|
-
* after it and a missing one is visible immediately.
|
|
902
|
-
*
|
|
903
|
-
* `themeFonts` resolves `w:rFonts` theme references. Absent, a theme-only `rFonts` leaves
|
|
904
|
-
* the family inherited — which is what every run of a theme-fonted document does, so the
|
|
905
|
-
* whole document falls back to the surface default face.
|
|
906
|
-
*/
|
|
907
|
-
declare function resolveRunStyle(props: readonly OoxmlProperty[], themeFonts?: ThemeFonts): ResolvedRunStyle;
|
|
908
|
-
/** The text as it is DRAWN, after case transforms. Measurement must use this, not the source. */
|
|
909
|
-
declare function displayText(text: string, style: ResolvedRunStyle): string;
|
|
910
|
-
/** Measure run text the way layout breaks lines and paints glyphs (caps/small-caps aware). */
|
|
911
|
-
declare function measureDisplayText(text: string, style: ResolvedRunStyle, measurer: TextMeasurer): number;
|
|
912
|
-
/** Whether two resolved styles are identical, for span merging and cache keys. */
|
|
913
|
-
declare function runStylesEqual(a: ResolvedRunStyle, b: ResolvedRunStyle): boolean;
|
|
914
|
-
/**
|
|
915
|
-
* How far a run's glyphs are lifted off the line's baseline, in points. Positive is up.
|
|
916
|
-
*
|
|
917
|
-
* Super and subscript move the GLYPHS without moving the run's box, so the box keeps tiling
|
|
918
|
-
* the line and the selection band stays continuous. Anything drawing at the glyphs — the
|
|
919
|
-
* painter, and the caret — has to apply this itself, and from one place, or the two drift.
|
|
920
|
-
*/
|
|
921
|
-
declare function baselineShiftPtOf(style: ResolvedRunStyle): number;
|
|
922
|
-
|
|
923
|
-
/**
|
|
924
|
-
* Which `w:rFonts` slot a character resolves its face through.
|
|
925
|
-
*
|
|
926
|
-
* OOXML gives a run up to four faces and picks between them by SCRIPT, so one run of mixed Latin
|
|
927
|
-
* and CJK text uses two different fonts without saying so anywhere in its properties.
|
|
928
|
-
*/
|
|
929
|
-
type FontSlot = 'ascii' | 'hAnsi' | 'eastAsia' | 'cs';
|
|
930
|
-
/**
|
|
931
|
-
* A run of text sharing one script, direction and font slot — the unit handed to the shaper.
|
|
932
|
-
*
|
|
933
|
-
* Shaping cannot span a script change: Arabic and Latin in one call would produce wrong joining
|
|
934
|
-
* behaviour, so a run is itemized into these first.
|
|
935
|
-
*/
|
|
936
|
-
interface ScriptItem {
|
|
937
|
-
readonly from: number;
|
|
938
|
-
readonly to: number;
|
|
939
|
-
readonly direction: TextDirection;
|
|
940
|
-
readonly bidiLevel: number;
|
|
941
|
-
readonly script: 'Zyyy' | 'Latn' | 'Grek' | 'Cyrl' | 'Hani' | 'Hebr' | 'Arab' | 'Deva' | 'Beng' | 'Thai' | 'Khmr';
|
|
942
|
-
readonly slot: FontSlot;
|
|
943
|
-
}
|
|
944
|
-
/**
|
|
945
|
-
* A code point whose script this engine does not itemize.
|
|
946
|
-
*
|
|
947
|
-
* Carries the offending `codePoint` so the caller can report which character stopped it, rather
|
|
948
|
-
* than failing anonymously somewhere in the middle of a paragraph.
|
|
949
|
-
*/
|
|
950
|
-
declare class UnsupportedScriptError extends Error {
|
|
951
|
-
readonly name = "UnsupportedScriptError";
|
|
952
|
-
readonly code = "unsupportedScript";
|
|
953
|
-
readonly codePoint: number;
|
|
954
|
-
constructor(codePoint: number);
|
|
955
|
-
}
|
|
956
|
-
/**
|
|
957
|
-
* Split text into shapeable runs by script, bidi level and font slot.
|
|
958
|
-
*
|
|
959
|
-
* Consumes the bidi levels rather than re-deriving direction, so itemization and reordering agree
|
|
960
|
-
* by construction instead of by two implementations happening to match.
|
|
961
|
-
*/
|
|
962
|
-
declare function itemizeScriptFontSlots(text: string, paragraphOffset: number, embedding: BidiEmbeddingLevels): readonly ScriptItem[];
|
|
963
|
-
/**
|
|
964
|
-
* The style a piece's text is MEASURED AND PAINTED in, given the font slot it carries.
|
|
965
|
-
*
|
|
966
|
-
* This is the measurer-boundary resolution: pieces and spans keep the run's real resolved
|
|
967
|
-
* style — with `fontFamily` and `fontFamilyEastAsia` both intact, so formatting readback
|
|
968
|
-
* and the format painter see the run as authored — and every consumer that turns text into
|
|
969
|
-
* geometry or ink resolves the face through here. The derived object is memoized per
|
|
970
|
-
* (style, family) by {@link withFontFamily}, so measurers amortizing over style identity
|
|
971
|
-
* keep their caches.
|
|
972
|
-
*/
|
|
973
|
-
declare function styleForFontSlot(style: ResolvedRunStyle, slot: FontSlot | undefined): ResolvedRunStyle;
|
|
974
|
-
|
|
975
|
-
type AllowlistedPageField = 'PAGE' | 'NUMPAGES' | 'SECTIONPAGES';
|
|
976
|
-
/**
|
|
977
|
-
* Which allowlisted page fields a header/footer story actually contains.
|
|
978
|
-
*
|
|
979
|
-
* Drives layout reuse: no fields → one baseline; NUMPAGES only → one layout per page count;
|
|
980
|
-
* SECTIONPAGES only → one layout per section page count; PAGE (alone or combined) → per
|
|
981
|
-
* distinct evaluated values with a bounded cache. Counts both complex markers and
|
|
982
|
-
* `w:fldSimple` (including an allowlisted page field nested inside a non-page simple field).
|
|
983
|
-
*/
|
|
984
|
-
interface StoryPageFieldNeeds {
|
|
985
|
-
readonly hasPage: boolean;
|
|
986
|
-
readonly hasNumPages: boolean;
|
|
987
|
-
readonly hasSectionPages: boolean;
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
/** One recognized REF instruction: the target name and the supported switches, nothing else. */
|
|
991
|
-
interface RefFieldSpec {
|
|
992
|
-
readonly bookmark: string;
|
|
993
|
-
/** `r` / `w` paint the target's number; `n` the same without context; null the range text. */
|
|
994
|
-
readonly numberSwitch: 'r' | 'w' | 'n' | null;
|
|
995
|
-
/** `\h` parsed and inert — the reference paints; navigation is a follow-up. */
|
|
996
|
-
readonly hyperlink: boolean;
|
|
997
|
-
}
|
|
998
|
-
/**
|
|
999
|
-
* Recognize `REF <bookmark> [\r|\w|\n] [\t] [\h] [\* MERGEFORMAT]` or
|
|
1000
|
-
* `NOTEREF <bookmark> [\h] [\* MERGEFORMAT]`, or null for anything else.
|
|
1001
|
-
*
|
|
1002
|
-
* The keyword matches case-insensitively; the bookmark name keeps its authored case (it is a
|
|
1003
|
-
* lookup key into a Map, never an object property, so hostile names like `__proto__` are just
|
|
1004
|
-
* names that resolve to nothing). Any unrecognized switch fails the parse so the field falls
|
|
1005
|
-
* back to its cached result — never the raw instruction, never a guess. NOTEREF's `\p`
|
|
1006
|
-
* (above/below position text) and `\f` (note-style formatting) are unrecognized on purpose.
|
|
1007
|
-
*/
|
|
1008
|
-
declare function parseRefInstruction(raw: string): RefFieldSpec | null;
|
|
1009
|
-
|
|
1010
|
-
/** Soft ceiling on abstractNum / num entries read from one part. */
|
|
1011
|
-
declare const MAX_NUMBERING_DEFINITIONS = 512;
|
|
1012
|
-
/** Soft ceiling on override entries per `w:num`. */
|
|
1013
|
-
declare const MAX_LVL_OVERRIDES = 9;
|
|
1014
|
-
/** `w:suff` — what separates a list marker from the text after it. */
|
|
1015
|
-
type ListSuffix = 'tab' | 'space' | 'nothing';
|
|
1016
|
-
/** `w:lvlJc` — how a list marker aligns within its own indent. */
|
|
1017
|
-
type ListMarkerAlign = 'left' | 'center' | 'right';
|
|
1018
|
-
/**
|
|
1019
|
-
* One level's indent, plus which parts the level actually AUTHORED.
|
|
1020
|
-
*
|
|
1021
|
-
* The provenance matters: `w:ind` cascades per-attribute, so a level that authored only `left`
|
|
1022
|
-
* must not overwrite an inherited `hanging` with a synthesized zero.
|
|
1023
|
-
*/
|
|
1024
|
-
interface NumberingLevelIndent {
|
|
1025
|
-
readonly left: number;
|
|
1026
|
-
readonly right: number;
|
|
1027
|
-
readonly hanging: number;
|
|
1028
|
-
readonly firstLine: number;
|
|
1029
|
-
/**
|
|
1030
|
-
* Which of these the LEVEL actually authored.
|
|
1031
|
-
*
|
|
1032
|
-
* A level's `w:pPr/w:ind` sits between the paragraph style and direct formatting, so the
|
|
1033
|
-
* merge has to tell "the level says left = 0" from "the level says nothing about left and
|
|
1034
|
-
* the style's value stands". Absent (the default) reads as "says nothing", which is what a
|
|
1035
|
-
* hand-built level in a test means.
|
|
1036
|
-
*/
|
|
1037
|
-
readonly stated?: {
|
|
1038
|
-
readonly left: boolean;
|
|
1039
|
-
readonly right: boolean;
|
|
1040
|
-
/** `w:hanging`/`w:firstLine` are one mutually exclusive slot (§17.3.1.10, §17.3.1.12). */
|
|
1041
|
-
readonly firstLineOffset: boolean;
|
|
1042
|
-
};
|
|
1043
|
-
}
|
|
1044
|
-
/** One `w:lvl`: how this depth numbers, what its marker looks like, and how it indents. */
|
|
1045
|
-
interface NumberingLevel {
|
|
1046
|
-
readonly ilvl: number;
|
|
1047
|
-
readonly start: number;
|
|
1048
|
-
readonly numFmt: string;
|
|
1049
|
-
readonly lvlText: string;
|
|
1050
|
-
readonly lvlJc: ListMarkerAlign;
|
|
1051
|
-
readonly suff: ListSuffix;
|
|
1052
|
-
readonly indent: NumberingLevelIndent;
|
|
1053
|
-
/**
|
|
1054
|
-
* `w:lvlRestart` one-based trigger level, or `0` when the level never restarts.
|
|
1055
|
-
* Omitted in XML → restart when the previous level (or any earlier level) is used.
|
|
1056
|
-
*/
|
|
1057
|
-
readonly lvlRestart?: number;
|
|
1058
|
-
/**
|
|
1059
|
-
* `w:isLgl` (§17.9.9): render EVERY level referenced by this level's `w:lvlText` in
|
|
1060
|
-
* decimal, whatever number format those levels declare for themselves.
|
|
1061
|
-
*/
|
|
1062
|
-
readonly isLgl: boolean;
|
|
1063
|
-
/** Level `w:rPr` as flat properties (for marker face / vanish). */
|
|
1064
|
-
readonly runProperties: readonly OoxmlProperty[];
|
|
1065
|
-
/** True when level run props request vanish — marker must not paint. */
|
|
1066
|
-
readonly vanish: boolean;
|
|
1067
|
-
}
|
|
1068
|
-
/**
|
|
1069
|
-
* One `w:lvlOverride` on a `w:num`: a restart value, a replacement level, or both.
|
|
1070
|
-
*
|
|
1071
|
-
* How two lists share an abstract definition while numbering independently.
|
|
1072
|
-
*/
|
|
1073
|
-
interface LevelOverride {
|
|
1074
|
-
readonly startOverride?: number;
|
|
1075
|
-
/** Full level replacement when `w:lvl` is present under the override. */
|
|
1076
|
-
readonly level?: NumberingLevel;
|
|
1077
|
-
}
|
|
1078
|
-
/**
|
|
1079
|
-
* One `w:abstractNum` — the shape of a list, without being a list.
|
|
1080
|
-
*
|
|
1081
|
-
* Never referenced by a paragraph directly. Paragraphs name a {@link NumDefinition}, which names
|
|
1082
|
-
* one of these, so several lists can share a definition and still count separately.
|
|
1083
|
-
*/
|
|
1084
|
-
interface AbstractNumDefinition {
|
|
1085
|
-
readonly abstractNumId: string;
|
|
1086
|
-
readonly levels: ReadonlyMap<number, NumberingLevel>;
|
|
1087
|
-
/**
|
|
1088
|
-
* `w:numStyleLink` (§17.9.21): this definition carries no levels of its own — the numbering
|
|
1089
|
-
* lives on the named style. Word follows the link; resolve it with
|
|
1090
|
-
* {@link resolveNumberingStyleLinks} before reading levels, or every paragraph on this
|
|
1091
|
-
* abstract renders with NO marker at all.
|
|
1092
|
-
*/
|
|
1093
|
-
readonly numStyleLink?: string;
|
|
1094
|
-
/**
|
|
1095
|
-
* `w:styleLink` (§17.9.23): the definition side of the same pair — this abstract IS the
|
|
1096
|
-
* numbering of the named style. Kept so a link can be verified rather than assumed.
|
|
1097
|
-
*/
|
|
1098
|
-
readonly styleLink?: string;
|
|
1099
|
-
}
|
|
1100
|
-
/**
|
|
1101
|
-
* One `w:num` — the thing a paragraph's `w:numId` actually names.
|
|
1102
|
-
*
|
|
1103
|
-
* Points at an {@link AbstractNumDefinition} and may override any of its levels.
|
|
1104
|
-
*/
|
|
1105
|
-
interface NumDefinition {
|
|
1106
|
-
readonly numId: string;
|
|
1107
|
-
readonly abstractNumId: string;
|
|
1108
|
-
readonly overrides: ReadonlyMap<number, LevelOverride>;
|
|
1109
|
-
}
|
|
1110
|
-
/**
|
|
1111
|
-
* The bounded projection of `numbering.xml` that list layout resolves against.
|
|
1112
|
-
*
|
|
1113
|
-
* Projection ONLY — never a mutation or serialization authority. Hostile values are dropped or
|
|
1114
|
-
* clamped, and a missing definition resolves to "no list" rather than a guess.
|
|
1115
|
-
*/
|
|
1116
|
-
interface NumberingIndex {
|
|
1117
|
-
readonly abstractNums: ReadonlyMap<string, AbstractNumDefinition>;
|
|
1118
|
-
readonly nums: ReadonlyMap<string, NumDefinition>;
|
|
1119
|
-
}
|
|
1120
|
-
/**
|
|
1121
|
-
* Build a numbering index from the root of a numbering part (`w:numbering`).
|
|
1122
|
-
*
|
|
1123
|
-
* Empty / missing roots yield an empty index. Duplicate ids keep the first definition.
|
|
1124
|
-
*/
|
|
1125
|
-
/**
|
|
1126
|
-
* Project `numbering.xml` into the bounded index.
|
|
1127
|
-
*
|
|
1128
|
-
* Every ceiling here exists because the input is file-derived: definition counts, override
|
|
1129
|
-
* counts, indent magnitudes and style-link hop depth are all capped, and nothing from the file
|
|
1130
|
-
* becomes a loop bound or an allocation size.
|
|
1131
|
-
*/
|
|
1132
|
-
declare function buildNumberingIndex(root: OoxmlElement | null | undefined): NumberingIndex;
|
|
1133
|
-
/** Resolve the effective level for a `numId` + `ilvl`, applying overrides. */
|
|
1134
|
-
/**
|
|
1135
|
-
* The effective level for one paragraph's numbering reference, after overrides and style links.
|
|
1136
|
-
*
|
|
1137
|
-
* Answers null for a reference the index cannot resolve — a paragraph naming a definition the
|
|
1138
|
-
* file never declared is an unnumbered paragraph, not an error.
|
|
1139
|
-
*/
|
|
1140
|
-
declare function resolveNumberingLevel(index: NumberingIndex, numId: string, ilvl: number): {
|
|
1141
|
-
readonly abstractNumId: string;
|
|
1142
|
-
readonly level: NumberingLevel;
|
|
1143
|
-
readonly startOverride?: number;
|
|
1144
|
-
} | null;
|
|
1145
|
-
/** Empty index for tests / documents without numbering. */
|
|
1146
|
-
declare const EMPTY_NUMBERING_INDEX: NumberingIndex;
|
|
1147
|
-
|
|
1148
|
-
interface DrawingPoint {
|
|
1149
|
-
readonly x: number;
|
|
1150
|
-
readonly y: number;
|
|
1151
|
-
}
|
|
1152
|
-
interface DrawingInsets {
|
|
1153
|
-
readonly top: number;
|
|
1154
|
-
readonly right: number;
|
|
1155
|
-
readonly bottom: number;
|
|
1156
|
-
readonly left: number;
|
|
1157
|
-
}
|
|
1158
|
-
type DrawingClipFallback = 'none' | 'unsupported-preset';
|
|
1159
|
-
interface DrawingGeometry {
|
|
1160
|
-
readonly contentBounds: LayoutBox;
|
|
1161
|
-
readonly paintBounds: LayoutBox;
|
|
1162
|
-
readonly hitBounds: LayoutBox;
|
|
1163
|
-
readonly transformedCorners: readonly DrawingPoint[];
|
|
1164
|
-
readonly clipPolygon: readonly DrawingPoint[] | null;
|
|
1165
|
-
readonly clipFallback: DrawingClipFallback;
|
|
1166
|
-
readonly effectInsets: DrawingInsets;
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
/** Horizontal alignment of a paragraph (`w:jc`, ECMA-376 §17.3.1.13). */
|
|
1170
|
-
type Alignment = 'left' | 'center' | 'right' | 'both';
|
|
1171
|
-
|
|
1172
|
-
/** Soft ceiling on `basedOn` chain length — enough for real templates, refuses hostile graphs. */
|
|
1173
|
-
declare const MAX_STYLE_BASED_ON_DEPTH = 32;
|
|
1174
|
-
/** Soft ceiling on style definitions read from one styles part. */
|
|
1175
|
-
declare const MAX_STYLE_DEFINITIONS = 4096;
|
|
1176
|
-
/** One `w:style` as the cascade reads it: its properties, and the style it is based on. */
|
|
1177
|
-
interface StyleDefinition {
|
|
1178
|
-
readonly styleId: string;
|
|
1179
|
-
readonly type: string;
|
|
1180
|
-
readonly basedOn: string | null;
|
|
1181
|
-
/**
|
|
1182
|
-
* `w:next` — the style Word gives the paragraph that FOLLOWS one in this style.
|
|
1183
|
-
*
|
|
1184
|
-
* Nothing in layout reads it: it is a rule about authoring, not about painting. It is
|
|
1185
|
-
* read here because this is the one place `styles.xml` is parsed, and a second reader
|
|
1186
|
-
* would be a second answer to what a style id means.
|
|
1187
|
-
*/
|
|
1188
|
-
readonly next: string | null;
|
|
1189
|
-
readonly paragraphProperties: readonly OoxmlProperty[];
|
|
1190
|
-
readonly runProperties: readonly OoxmlProperty[];
|
|
1191
|
-
/** The style's `w:pPr` node, when present — needed for nested `w:pBdr`. */
|
|
1192
|
-
readonly paragraphPropertiesNode: OoxmlElement | undefined;
|
|
1193
|
-
/** The style's `w:tblPr`, for a `w:type="table"` style. */
|
|
1194
|
-
readonly tablePropertiesNode: OoxmlElement | undefined;
|
|
1195
|
-
/**
|
|
1196
|
-
* `w:tblStylePr` conditional formats by `w:type` (`firstRow`, `band1Horz`, …).
|
|
1197
|
-
*
|
|
1198
|
-
* Word puts a table's real appearance here: `Table Grid` carries its grid in the style's
|
|
1199
|
-
* `w:tblBorders`, and the banded/header looks live in these. A document states only
|
|
1200
|
-
* `<w:tblStyle w:val="TableGrid"/>`.
|
|
1201
|
-
*/
|
|
1202
|
-
readonly conditionalTableFormats: ReadonlyMap<string, OoxmlElement>;
|
|
1203
|
-
}
|
|
1204
|
-
/**
|
|
1205
|
-
* The whole styles part, indexed and ready to resolve against.
|
|
1206
|
-
*
|
|
1207
|
-
* `cacheToken` is load-bearing: it folds into layout cache producers so breaks measured under one
|
|
1208
|
-
* styles part are never reused under another.
|
|
1209
|
-
*/
|
|
1210
|
-
interface StyleCascadeTable {
|
|
1211
|
-
/**
|
|
1212
|
-
* Bounded fingerprint folded into layout cache producers so a different styles part cannot
|
|
1213
|
-
* reuse breaks measured under another cascade. Computed once per table (FNV-1a hex).
|
|
1214
|
-
*/
|
|
1215
|
-
readonly cacheToken: string;
|
|
1216
|
-
readonly docDefaultsRun: readonly OoxmlProperty[];
|
|
1217
|
-
readonly docDefaultsParagraph: readonly OoxmlProperty[];
|
|
1218
|
-
readonly docDefaultsParagraphNode: OoxmlElement | undefined;
|
|
1219
|
-
/** `w:style[@w:default='1'][@w:type='paragraph']` — last wins among defaults of that type. */
|
|
1220
|
-
readonly defaultParagraphStyleId: string | null;
|
|
1221
|
-
/** `w:style[@w:default='1'][@w:type='character']` — last wins among defaults of that type. */
|
|
1222
|
-
readonly defaultCharacterStyleId: string | null;
|
|
1223
|
-
/**
|
|
1224
|
-
* `w:style[@w:default='1'][@w:type='table']` — last wins among defaults of that type.
|
|
1225
|
-
*
|
|
1226
|
-
* A `w:tbl` with no `w:tblStyle` still resolves against this one. Word's own
|
|
1227
|
-
* `TableNormal` is where the 0/108/0/108 twip cell margins live, so skipping it gives
|
|
1228
|
-
* every unstyled table padding the document says it does not have.
|
|
1229
|
-
*/
|
|
1230
|
-
readonly defaultTableStyleId: string | null;
|
|
1231
|
-
/**
|
|
1232
|
-
* The theme part's typefaces, for `w:rFonts` theme references.
|
|
1233
|
-
*
|
|
1234
|
-
* Lives on the cascade because it is document-level style material with the same
|
|
1235
|
-
* lifetime, and because every site that resolves run properties already holds this table.
|
|
1236
|
-
*/
|
|
1237
|
-
readonly themeFonts: ThemeFonts;
|
|
1238
|
-
readonly styles: ReadonlyMap<string, StyleDefinition>;
|
|
1239
|
-
}
|
|
1240
|
-
/**
|
|
1241
|
-
* A paragraph's properties after the cascade, plus the same list WITHOUT its own `w:pPr`.
|
|
1242
|
-
*
|
|
1243
|
-
* Both, because a writer needs to know what a paragraph INHERITS to decide whether setting a
|
|
1244
|
-
* value is a change or a no-op — and writing back an inherited value freezes it into the
|
|
1245
|
-
* paragraph as though the author had chosen it.
|
|
1246
|
-
*/
|
|
1247
|
-
interface CascadedParagraphFormatting {
|
|
1248
|
-
/** Flat paragraph properties in cascade order (defaults → bases → style → direct). */
|
|
1249
|
-
readonly paragraphProperties: readonly OoxmlProperty[];
|
|
1250
|
-
/**
|
|
1251
|
-
* The same list WITHOUT the paragraph's own `w:pPr` — everything it inherits.
|
|
1252
|
-
*
|
|
1253
|
-
* Numbering needs the two tiers apart: a level's `w:pPr/w:ind` outranks the style's and is
|
|
1254
|
-
* outranked by the paragraph's own, and a flattened list cannot say which is which.
|
|
1255
|
-
*/
|
|
1256
|
-
readonly inheritedParagraphProperties: readonly OoxmlProperty[];
|
|
1257
|
-
/** Matching `w:pPr` nodes for nested border resolution. */
|
|
1258
|
-
readonly paragraphPropertyNodes: readonly OoxmlNode[];
|
|
1259
|
-
/**
|
|
1260
|
-
* Inherited run properties for CONTENT runs (before direct run `rPr`).
|
|
1261
|
-
*
|
|
1262
|
-
* Does NOT include direct `w:pPr/w:rPr` — that formats the paragraph MARK only
|
|
1263
|
-
* (ECMA-376 §17.3.1.36). Folding mark `w:sz` into content made BodyText runs with no
|
|
1264
|
-
* direct size paint at the mark's size (Selection Notice "or" alternative → 6.5pt).
|
|
1265
|
-
*/
|
|
1266
|
-
readonly runProperties: readonly OoxmlProperty[];
|
|
1267
|
-
/**
|
|
1268
|
-
* Content cascade plus direct `w:pPr/w:rPr` — empty-line metrics and last-line mark height.
|
|
1269
|
-
*/
|
|
1270
|
-
readonly markRunProperties: readonly OoxmlProperty[];
|
|
1271
|
-
/**
|
|
1272
|
-
* The style this paragraph resolved to, or null when it names none and there is no
|
|
1273
|
-
* document default. `w:contextualSpacing` compares neighbours by exactly this.
|
|
1274
|
-
*/
|
|
1275
|
-
readonly styleId: string | null;
|
|
1276
|
-
}
|
|
1277
|
-
/** Accepted style ids only — over-long, control-bearing, or dangerous keys are dropped. */
|
|
1278
|
-
declare function isValidStyleId(raw: string | undefined): raw is string;
|
|
1279
|
-
/**
|
|
1280
|
-
* What a table style contributes to the paragraphs of ONE cell: the style's whole-table
|
|
1281
|
-
* `w:pPr`/`w:rPr` followed by every `w:tblStylePr` the cell is under (17.7.6.6), weakest
|
|
1282
|
-
* first in the caller's condition order (banding, column, row, corner).
|
|
1283
|
-
*
|
|
1284
|
-
* This is how Word makes a header row bold and centred while the document states nothing
|
|
1285
|
-
* but `<w:tblStyle w:val="…"/>` on the table and plain runs in the cells.
|
|
1286
|
-
*/
|
|
1287
|
-
interface TableCellStyleFormatting {
|
|
1288
|
-
readonly paragraphProperties: readonly OoxmlProperty[];
|
|
1289
|
-
/** Matching `w:pPr` nodes, for nested `w:pBdr` / `w:tabs` resolution. */
|
|
1290
|
-
readonly paragraphPropertyNodes: readonly OoxmlElement[];
|
|
1291
|
-
/** Inherited run properties for every run in the cell, before the paragraph style. */
|
|
1292
|
-
readonly runProperties: readonly OoxmlProperty[];
|
|
1293
|
-
}
|
|
1294
|
-
/**
|
|
1295
|
-
* Build a cascade table from a styles part root.
|
|
1296
|
-
*
|
|
1297
|
-
* Only direct `w:style` children of the root participate (bounded count). Duplicate
|
|
1298
|
-
* `styleId` values keep the last definition, matching Word's reader for this fixture class.
|
|
1299
|
-
* Default paragraph/character style ids track `w:default="1"` with the same last-wins rule.
|
|
1300
|
-
*/
|
|
1301
|
-
declare function buildStyleCascadeTable(stylesRoot: OoxmlElement | null, themeFonts?: ThemeFonts): StyleCascadeTable;
|
|
1302
|
-
/**
|
|
1303
|
-
* Cascade paragraph + inherited run properties for one paragraph's direct `w:pPr`.
|
|
1304
|
-
*
|
|
1305
|
-
* Order: `docDefaults` → table style → `basedOn` ancestors → paragraph style → direct
|
|
1306
|
-
* formatting, which is the style hierarchy of 17.7.2: a table style sits above the document
|
|
1307
|
-
* defaults and below the paragraph style a cell paragraph names for itself.
|
|
1308
|
-
* When `w:pStyle` is absent, the document's default paragraph style (`w:default="1"`) is used.
|
|
1309
|
-
* Direct formatting is last so it overrides inherited values inside the existing resolvers.
|
|
1310
|
-
*/
|
|
1311
|
-
declare function cascadeParagraphFormatting(table: StyleCascadeTable, directPPr: OoxmlNode | undefined, tableCellStyle?: TableCellStyleFormatting): CascadedParagraphFormatting;
|
|
1312
|
-
/**
|
|
1313
|
-
* Bottom border after cascade: a later `w:pBdr` replaces an earlier one; absence inherits.
|
|
1314
|
-
* `nil`/`none` clear the edge via `paragraphBorders`.
|
|
1315
|
-
*/
|
|
1316
|
-
declare function cascadedBottomBorder(paragraphPropertyNodes: readonly OoxmlNode[]): ParagraphBorderEdge | undefined;
|
|
1317
|
-
/**
|
|
1318
|
-
* Merge inherited paragraph-style run props with a run's direct `rPr` (direct last).
|
|
1319
|
-
*
|
|
1320
|
-
* When a cascade table is supplied, also resolves `w:rStyle` character styles (basedOn chain,
|
|
1321
|
-
* cycle/depth capped). Runs without an explicit `rStyle` pick up the default character style
|
|
1322
|
-
* (`w:default="1"`). Precedence: inherited → character style chain → direct formatting.
|
|
1323
|
-
*
|
|
1324
|
-
* PASS `inheritedRunProperties` BY IDENTITY. It must be an array
|
|
1325
|
-
* {@link cascadeParagraphFormatting} returned — `runProperties` or `markRunProperties` — and
|
|
1326
|
-
* not a copy of one. A toggle property (ECMA-376 §17.7.3) resolves per level of the style
|
|
1327
|
-
* hierarchy, and the levels below the character style resolve to more than a true or a false:
|
|
1328
|
-
* whether the document defaults' short circuit is still standing decides what the character
|
|
1329
|
-
* style's own toggle does next, and no single `w:b` element can spell that. The paragraph
|
|
1330
|
-
* cascade attaches that state to the array it returns, so spreading, filtering or sorting the
|
|
1331
|
-
* list drops it. (`Object.freeze` returns the same object, so that one is safe.) A list
|
|
1332
|
-
* without it is read as one ordinary level, which is the most a bare property list can say
|
|
1333
|
-
* and is what a caller assembling its own list gets.
|
|
1334
|
-
*/
|
|
1335
|
-
declare function cascadeRunProperties(inheritedRunProperties: readonly OoxmlProperty[], directRunProperties: readonly OoxmlProperty[], table?: StyleCascadeTable): readonly OoxmlProperty[];
|
|
1336
|
-
/** Everything the line breaker needs about one paragraph, already cascaded and converted. */
|
|
1337
|
-
interface ParagraphLayoutInputs {
|
|
1338
|
-
readonly props: OoxmlProperty[];
|
|
1339
|
-
readonly indent: {
|
|
1340
|
-
left: number;
|
|
1341
|
-
right: number;
|
|
1342
|
-
hanging: number;
|
|
1343
|
-
firstLine: number;
|
|
1344
|
-
};
|
|
1345
|
-
readonly available: number;
|
|
1346
|
-
readonly alignment: Alignment;
|
|
1347
|
-
readonly spacing: ParagraphSpacing;
|
|
1348
|
-
/** Resolved `w:line` / `w:lineRule`; single spacing where the cascade says nothing. */
|
|
1349
|
-
readonly lineSpacing: ParagraphLineSpacing;
|
|
1350
|
-
/** `w:contextualSpacing`: drop before/after between same-style neighbours. */
|
|
1351
|
-
readonly contextualSpacing: boolean;
|
|
1352
|
-
/** Resolved paragraph style id, for the `w:contextualSpacing` neighbour comparison. */
|
|
1353
|
-
readonly styleId: string | null;
|
|
1354
|
-
readonly bottomBorder: ParagraphBorderEdge | undefined;
|
|
1355
|
-
/**
|
|
1356
|
-
* Every `CT_PBdr` edge after cascade, not just the bottom one.
|
|
1357
|
-
*
|
|
1358
|
-
* `bottomBorder` stays alongside it because the fragment signature and the table flow
|
|
1359
|
-
* read that field by name; this is the whole box, so a cell paragraph gets the same
|
|
1360
|
-
* frame a body paragraph does.
|
|
1361
|
-
*/
|
|
1362
|
-
readonly borders: ParagraphBorders;
|
|
1363
|
-
/** Validated 6-hex paragraph shading fill from cascaded `w:pPr/w:shd`, absent for none. */
|
|
1364
|
-
readonly shading: string | undefined;
|
|
1365
|
-
readonly inheritedRunProperties: readonly OoxmlProperty[];
|
|
1366
|
-
/**
|
|
1367
|
-
* Paragraph-mark cascade (`inheritedRunProperties` + direct `w:pPr/w:rPr`).
|
|
1368
|
-
* Empty-line sizing and last-line mark height — never content-run face.
|
|
1369
|
-
*/
|
|
1370
|
-
readonly markRunProperties: readonly OoxmlProperty[];
|
|
1371
|
-
/** Cascaded custom tab stops + default interval for paragraph-flow breaking. */
|
|
1372
|
-
readonly tabStops: ResolvedTabStops;
|
|
1373
|
-
/**
|
|
1374
|
-
* Fingerprint folded into the paragraph layout cache key — nested `w:tabs` are absent
|
|
1375
|
-
* from flat property bags, so style-inherited stops must be named explicitly.
|
|
1376
|
-
*/
|
|
1377
|
-
readonly tabStopsCacheToken: string;
|
|
1378
|
-
/** Resolved list marker inputs when the paragraph participates in numbering. */
|
|
1379
|
-
readonly listItem?: ResolvedListItem;
|
|
1380
|
-
}
|
|
1381
|
-
/**
|
|
1382
|
-
* Resolve every paragraph input semantic layout / table cells share: cascaded props when a
|
|
1383
|
-
* style table is present, otherwise direct formatting only.
|
|
1384
|
-
*
|
|
1385
|
-
* When `listItem` is provided, its merged level indent becomes the paragraph indent (list
|
|
1386
|
-
* hanging / left from `numbering.xml`), which is what Word uses for fixture list paragraphs
|
|
1387
|
-
* that author no direct `w:ind`.
|
|
1388
|
-
*
|
|
1389
|
-
* `tableCellStyle` carries what the enclosing table's style says about this cell's
|
|
1390
|
-
* paragraphs; body paragraphs pass nothing.
|
|
1391
|
-
*
|
|
1392
|
-
* `inTableCell` is asked for separately because a cell paragraph may have no table style to
|
|
1393
|
-
* inherit at all, and `w:beforeAutospacing` still needs to know it is in a cell.
|
|
1394
|
-
*/
|
|
1395
|
-
declare function resolveParagraphLayoutInputs(paragraph: OoxmlElement, contentWidth: number, styleCascade: StyleCascadeTable | undefined, listItem?: ResolvedListItem, tableCellStyle?: TableCellStyleFormatting, inTableCell?: boolean): ParagraphLayoutInputs;
|
|
1396
|
-
|
|
1397
|
-
/**
|
|
1398
|
-
* A paragraph's list membership fully resolved: definition, level, marker text and geometry.
|
|
1399
|
-
*
|
|
1400
|
-
* `markerText` is already expanded through the counter state, so it is the string a reader sees
|
|
1401
|
-
* rather than the `w:lvlText` template.
|
|
1402
|
-
*/
|
|
1403
|
-
interface ResolvedListItem {
|
|
1404
|
-
readonly numId: string;
|
|
1405
|
-
readonly ilvl: number;
|
|
1406
|
-
readonly abstractNumId: string;
|
|
1407
|
-
/** `w:numFmt` of the resolved level — `bullet` or a numbering format. */
|
|
1408
|
-
readonly numFmt: string;
|
|
1409
|
-
readonly markerText: string;
|
|
1410
|
-
readonly markerAlign: ListMarkerAlign;
|
|
1411
|
-
readonly suffix: ListSuffix;
|
|
1412
|
-
/** Effective indent after merging level + paragraph indents, in points. */
|
|
1413
|
-
readonly indent: NumberingLevelIndent;
|
|
1414
|
-
readonly markerStyle: ResolvedRunStyle;
|
|
1415
|
-
/** Fingerprint for layout cache keys (indent, marker text, marker face). */
|
|
1416
|
-
readonly cacheToken: string;
|
|
1417
|
-
}
|
|
1418
|
-
/**
|
|
1419
|
-
* Read `w:numPr` from cascaded paragraph-property nodes (lowest precedence first).
|
|
1420
|
-
*
|
|
1421
|
-
* Flat `OoxmlProperty[]` bags drop nested `ilvl`/`numId`, so this walks the tree nodes
|
|
1422
|
-
* the same way borders and tabs do.
|
|
1423
|
-
*
|
|
1424
|
-
* `w:ilvl` and `w:numId` inherit INDEPENDENTLY through the style chain and the direct
|
|
1425
|
-
* `w:pPr` (§17.3.1.19): a tier stating only the level keeps the id it inherits — Word's
|
|
1426
|
-
* standard Heading2–Heading9 shape, where only Heading1 names the `w:num` — and a tier
|
|
1427
|
-
* stating only the id keeps the inherited level. Treating each `w:numPr` node as a full
|
|
1428
|
-
* replacement dropped the id at every level-only tier and unnumbered the paragraph. A
|
|
1429
|
-
* stated `w:numId w:val="0"` (or an invalid value) still switches numbering off at that
|
|
1430
|
-
* tier even when a lower tier set one; a higher tier stating a valid id re-enables. A
|
|
1431
|
-
* level-only tier with no id inherited from below resolves to no numbering.
|
|
1432
|
-
*/
|
|
1433
|
-
declare function readNumPr(paragraphPropertyNodes: readonly OoxmlNode[]): {
|
|
1434
|
-
numId: string;
|
|
1435
|
-
ilvl: number;
|
|
1436
|
-
} | null;
|
|
1437
|
-
/**
|
|
1438
|
-
* Resolve `w:numStyleLink` delegation using the document's styles (§17.9.21).
|
|
1439
|
-
*
|
|
1440
|
-
* Without a style table there is nothing to follow, so the index is returned unchanged —
|
|
1441
|
-
* and so it is when nothing delegates, which keeps layout cache identity.
|
|
1442
|
-
*/
|
|
1443
|
-
declare function withNumberingStyleLinks(index: NumberingIndex, styleCascade: StyleCascadeTable | undefined): NumberingIndex;
|
|
1444
|
-
/**
|
|
1445
|
-
* The effective indent of a list paragraph: STYLE, then the numbering LEVEL, then DIRECT.
|
|
1446
|
-
*
|
|
1447
|
-
* Word applies a level's `w:pPr/w:ind` between the paragraph style and the paragraph's own
|
|
1448
|
-
* formatting, per attribute — and the ordering matters on real documents. A converted
|
|
1449
|
-
* agreement numbers its `(a)` items with a level stating `left=1512 hanging=738` under a
|
|
1450
|
-
* `ListParagraph` style stating `left=775 hanging=624`, and states only `hanging="737"` on
|
|
1451
|
-
* the paragraph itself. Reading the flattened cascade as "the paragraph's indent" gave the
|
|
1452
|
-
* STYLE's 775 to a level that had overridden it, so every lettered sub-item hung a full
|
|
1453
|
-
* indent step to the left of where Word puts it.
|
|
1454
|
-
*
|
|
1455
|
-
* `inherited` is the cascade WITHOUT the paragraph's own `w:pPr` (defaults, table cell style,
|
|
1456
|
-
* style chain); `direct` is that `w:pPr` alone.
|
|
1457
|
-
*/
|
|
1458
|
-
declare function mergeListIndent(levelIndent: NumberingLevelIndent, inherited: readonly OoxmlProperty[], direct?: readonly OoxmlProperty[]): NumberingLevelIndent;
|
|
1459
|
-
/**
|
|
1460
|
-
* Collect paragraphs of a block list in document order, descending into tables.
|
|
1461
|
-
*
|
|
1462
|
-
* Caps nesting so a hostile nested-table document cannot recurse without bound.
|
|
1463
|
-
*/
|
|
1464
|
-
declare function walkStoryParagraphs(blocks: readonly OoxmlElement[], maxTableDepth?: number): OoxmlElement[];
|
|
1465
|
-
/**
|
|
1466
|
-
* Resolve every list paragraph in a story to a {@link ResolvedListItem}, keyed by node id.
|
|
1467
|
-
*
|
|
1468
|
-
* Non-list paragraphs are absent from the map. Hostile / missing numbering resolves inertly
|
|
1469
|
-
* (paragraph omitted — laid out as ordinary text).
|
|
1470
|
-
*/
|
|
1471
|
-
declare function resolveStoryListItems(blocks: readonly OoxmlElement[], index: NumberingIndex, styleCascade: StyleCascadeTable | undefined, isFontAvailable?: (family: string) => boolean): ReadonlyMap<string, ResolvedListItem>;
|
|
1472
|
-
/**
|
|
1473
|
-
* Attach a full-story list-item map to layout options.
|
|
1474
|
-
*
|
|
1475
|
-
* Resolves once over `blocks` (body story including table cells) so counters continue across
|
|
1476
|
-
* section boundaries. No-ops when numbering is absent.
|
|
1477
|
-
*/
|
|
1478
|
-
declare function withResolvedListItems<T extends {
|
|
1479
|
-
readonly numberingIndex?: NumberingIndex;
|
|
1480
|
-
readonly listItems?: ReadonlyMap<string, ResolvedListItem>;
|
|
1481
|
-
readonly styleCascade?: StyleCascadeTable;
|
|
1482
|
-
readonly isFontAvailable?: (family: string) => boolean;
|
|
1483
|
-
}>(options: T, blocks: readonly OoxmlElement[]): T & {
|
|
1484
|
-
readonly numberingIndex: NumberingIndex;
|
|
1485
|
-
readonly listItems?: ReadonlyMap<string, ResolvedListItem>;
|
|
1486
|
-
};
|
|
1487
|
-
/**
|
|
1488
|
-
* Horizontal marker box inside the first-line indent slot.
|
|
1489
|
-
*
|
|
1490
|
-
* Coordinates are relative to the same origin as paragraph content (`indent.left` is the
|
|
1491
|
-
* text start). Returns null when there is nothing to paint.
|
|
1492
|
-
*
|
|
1493
|
-
* `w:hanging` and a positive `w:firstLine` are one mutually exclusive slot
|
|
1494
|
-
* (§17.3.1.10, §17.3.1.12), so the marker has two placements, not an interaction:
|
|
1495
|
-
* a hanging level puts the marker BEFORE the text start (`left - hanging`); a
|
|
1496
|
-
* positive-firstLine level puts it AFTER (`left + firstLine`) — the standard legal
|
|
1497
|
-
* shape `w:ind w:left="0" w:firstLine="720"` numbers at 0.5" while continuation
|
|
1498
|
-
* lines return to the margin. Reading only the hanging model painted every such
|
|
1499
|
-
* marker at the left margin.
|
|
1500
|
-
*/
|
|
1501
|
-
declare function listMarkerBox(item: ResolvedListItem, markerWidth: number, lineY: number, lineHeight: number): {
|
|
1502
|
-
x: number;
|
|
1503
|
-
y: number;
|
|
1504
|
-
width: number;
|
|
1505
|
-
height: number;
|
|
1506
|
-
} | null;
|
|
1507
|
-
|
|
1508
|
-
/**
|
|
1509
|
-
* The story's resolved REF inputs for one layout pass.
|
|
1510
|
-
*
|
|
1511
|
-
* Threaded as a runtime rider on the layout options (see `layoutSemanticDocument`) rather
|
|
1512
|
-
* than a `SemanticLayoutOptions` member, so the public options surface stays put. Absent
|
|
1513
|
-
* means every REF field paints its cached result — the pre-existing degradation, and the one
|
|
1514
|
-
* header/footer and text-box stories still take. Note stories receive the body's context
|
|
1515
|
-
* through `NotesLayoutInput.refFields`.
|
|
1516
|
-
*/
|
|
1517
|
-
interface RefFieldContext {
|
|
1518
|
-
/**
|
|
1519
|
-
* Content token over every PAINTED REF output in the story, for the section prepass memo.
|
|
1520
|
-
* A renumbering edit can move a REF value in a section whose own blocks and list map are
|
|
1521
|
-
* identity-unchanged, and this token is the only validator that sees it. A field that
|
|
1522
|
-
* failed calibration contributes its (session-constant) cached text, so the token still
|
|
1523
|
-
* moves exactly when painted output moves.
|
|
1524
|
-
*/
|
|
1525
|
-
readonly valuesToken: string;
|
|
1526
|
-
/** The paragraph's REF outputs folded for its block cache key; `''` when it holds none. */
|
|
1527
|
-
tokenForParagraph(paragraphId: string): string;
|
|
1528
|
-
/**
|
|
1529
|
-
* The live value ONE field paints, keyed by its begin / `w:fldSimple` node id, or null to
|
|
1530
|
-
* keep the cached result (failed calibration, unresolvable, or an anchor this scan never
|
|
1531
|
-
* saw). Anchor-keyed so the projection's paint and this context's token fold read the SAME
|
|
1532
|
-
* calibration verdict, however each walk collected the field's cached text.
|
|
1533
|
-
*/
|
|
1534
|
-
liveValueOf(anchorId: string, spec: RefFieldSpec): string | null;
|
|
1535
|
-
/**
|
|
1536
|
-
* The synthesized display of ONE AUTONUM-family field, keyed by its begin / `w:fldSimple`
|
|
1537
|
-
* node id, or null to paint nothing (unsupported switches, or an anchor this scan never
|
|
1538
|
-
* saw — both the field's historical rendering). These fields carry no cached result at
|
|
1539
|
-
* all, so there is no calibration: the sequential value is the only display they have.
|
|
1540
|
-
* Optional so hand-built contexts predating it stay valid.
|
|
1541
|
-
*/
|
|
1542
|
-
autonumValueOf?(anchorId: string): string | null;
|
|
1543
|
-
/**
|
|
1544
|
-
* The deferred projection of ONE `PAGEREF` field, or null to keep the cached result
|
|
1545
|
-
* (missing bookmark, unsupported switches, or an anchor this scan never saw).
|
|
1546
|
-
*
|
|
1547
|
-
* A `PAGEREF` value is a property of pagination, so the scan cannot compute it — it hands
|
|
1548
|
-
* the projection the resolved TARGET and the calibration inputs instead, and document
|
|
1549
|
-
* finalize (`finalizePageFieldProjection`) substitutes the page number the target's first
|
|
1550
|
-
* fragment lands on. Optional so hand-built contexts predating it stay valid.
|
|
1551
|
-
*/
|
|
1552
|
-
pageRefProjectionOf?(anchorId: string, spec: RefFieldSpec): PageRefFieldProjection | null;
|
|
1553
|
-
}
|
|
1554
|
-
/**
|
|
1555
|
-
* Sticky calibration identity for one `PAGEREF` field.
|
|
1556
|
-
*
|
|
1557
|
-
* An opaque frozen object rather than a mutable verdict holder because span markers are
|
|
1558
|
-
* serialized into fragment signatures — a verdict written into the marker would move a
|
|
1559
|
-
* signature that no painted output moved. The verdict itself lives beside the finalize pass
|
|
1560
|
-
* (`field-page-furniture.ts`), keyed weakly on this object; the registry below carries the
|
|
1561
|
-
* object across passes the same way REF verdicts are carried.
|
|
1562
|
-
*/
|
|
1563
|
-
type PageRefCalibrationCell = Readonly<Record<never, never>>;
|
|
1564
|
-
/**
|
|
1565
|
-
* What a `PAGEREF` span carries to document finalize: the resolved target, the normalized
|
|
1566
|
-
* authored cache (the calibration oracle), and the sticky calibration identity.
|
|
1567
|
-
*/
|
|
1568
|
-
interface PageRefFieldProjection {
|
|
1569
|
-
/** Canonical id of the paragraph the bookmark names — first declaration wins. */
|
|
1570
|
-
readonly targetParagraphId: string;
|
|
1571
|
-
/** The authored cached result, whitespace-collapsed — what the computed number must reproduce. */
|
|
1572
|
-
readonly cached: string;
|
|
1573
|
-
readonly calibration: PageRefCalibrationCell;
|
|
1574
|
-
}
|
|
1575
|
-
/**
|
|
1576
|
-
* Note parts whose stories join the context: their REF fields resolve against the body's
|
|
1577
|
-
* bookmarks and numbering (a footnote citing "Section 1.2(c)" targets a body paragraph),
|
|
1578
|
-
* and their bookmark declarations become plain-REF targets. Number switches aimed AT a
|
|
1579
|
-
* note paragraph still fall back to the cached result — the list map is the body's.
|
|
1580
|
-
*/
|
|
1581
|
-
interface RefNoteParts {
|
|
1582
|
-
readonly footnotesPart: OoxmlPart | null;
|
|
1583
|
-
readonly endnotesPart: OoxmlPart | null;
|
|
1584
|
-
}
|
|
1585
|
-
/**
|
|
1586
|
-
* Resolve the document's REF fields for one layout pass, or null when it has none.
|
|
1587
|
-
*
|
|
1588
|
-
* Bookmarks and REF fields resolve across the body story and (when `notes` is given) the
|
|
1589
|
-
* footnote/endnote stories, against ONE shared target index — a footnote REF finds the
|
|
1590
|
-
* body bookmark it cites. Header/footer and text-box stories are not given a context and
|
|
1591
|
-
* keep painting cached results.
|
|
1592
|
-
*/
|
|
1593
|
-
declare function resolveStoryRefFields(blocks: readonly OoxmlElement[], listItems: ReadonlyMap<string, ResolvedListItem> | undefined, notes?: RefNoteParts): RefFieldContext | null;
|
|
1594
|
-
|
|
1595
|
-
/**
|
|
1596
|
-
* Why textbox story layout stopped short.
|
|
1597
|
-
*
|
|
1598
|
-
* Every one is a BOUND rather than a bug: nesting depth, fragment counts and the extent all
|
|
1599
|
-
* come from a file. Falling back with a reason keeps the drawing rendered (clipped) instead
|
|
1600
|
-
* of failing the layout pass.
|
|
1601
|
-
*/
|
|
1602
|
-
type TextboxStoryFallbackReason = 'textbox-nesting-limit' | 'textbox-fragment-limit'
|
|
1603
|
-
/** Flowed content is taller than the extent; trailing fragments were dropped. */
|
|
1604
|
-
| 'textbox-height-clip';
|
|
1605
|
-
/**
|
|
1606
|
-
* One text box's story laid out inside its extent, in content-box-relative coordinates.
|
|
1607
|
-
*
|
|
1608
|
-
* Fragments origin at the content box's top-left; paint places the content box at
|
|
1609
|
-
* `drawing origin + contentOffset` and clips to the extent.
|
|
1610
|
-
*/
|
|
1611
|
-
interface TextboxStoryLayout {
|
|
1612
|
-
/** Content-box-relative fragments (origin at the content box's top-left). */
|
|
1613
|
-
readonly fragments: readonly BlockFragmentRecord[];
|
|
1614
|
-
/** Height the blocks flow to (points), before vertical anchoring. */
|
|
1615
|
-
readonly flowHeight: number;
|
|
1616
|
-
/** Offset of the content box inside the drawing extent: insets plus vertical anchoring. */
|
|
1617
|
-
readonly contentOffset: Readonly<{
|
|
1618
|
-
x: number;
|
|
1619
|
-
y: number;
|
|
1620
|
-
}>;
|
|
1621
|
-
/** Content box width (extent minus horizontal insets). */
|
|
1622
|
-
readonly contentWidth: number;
|
|
1623
|
-
/** Content box height (extent minus vertical insets). */
|
|
1624
|
-
readonly contentHeight: number;
|
|
1625
|
-
/** Solid fill of the hosting shape, painted behind the story; null for no fill. */
|
|
1626
|
-
readonly fillHex: string | null;
|
|
1627
|
-
/** Solid outline of the hosting shape; null for no outline. */
|
|
1628
|
-
readonly strokeHex: string | null;
|
|
1629
|
-
/** Outline width in points; 0 when absent. */
|
|
1630
|
-
readonly strokeWidthPt: number;
|
|
1631
|
-
/** True when layout hit a named bound and returned a truncated / empty story. */
|
|
1632
|
-
readonly fallbackReason?: TextboxStoryFallbackReason;
|
|
1633
|
-
/**
|
|
1634
|
-
* Resource identities of the drawings the clip DROPPED, in flow order.
|
|
1635
|
-
*
|
|
1636
|
-
* The furniture invalidation token walks laid-out records, and a dropped fragment leaves
|
|
1637
|
-
* none — while a `withPageContext` projection of the same story can wrap differently
|
|
1638
|
-
* (PAGE digits) and keep the drawing. Without this a picture clipped out of the baseline
|
|
1639
|
-
* but painted by a projection never reaches the session context, so its decode settling
|
|
1640
|
-
* moves nothing and the unchanged-pass early exit reuses the placeholder pages forever
|
|
1641
|
-
* (#467). Absent when the clip dropped no drawings, so the common story keys byte-for-byte
|
|
1642
|
-
* as before.
|
|
1643
|
-
*/
|
|
1644
|
-
readonly clippedResourceToken?: string;
|
|
1645
|
-
}
|
|
1646
|
-
|
|
1647
|
-
interface InlineDrawingRecord {
|
|
1648
|
-
readonly kind: 'inlineDrawing';
|
|
1649
|
-
readonly drawingNodeId: string;
|
|
1650
|
-
readonly paragraphId: string;
|
|
1651
|
-
readonly ownerPartName: string;
|
|
1652
|
-
readonly start: number;
|
|
1653
|
-
/** Left edge of the extent box (slot + distL). */
|
|
1654
|
-
readonly x: number;
|
|
1655
|
-
readonly y: number;
|
|
1656
|
-
readonly width: number;
|
|
1657
|
-
readonly height: number;
|
|
1658
|
-
readonly distL: number;
|
|
1659
|
-
readonly distR: number;
|
|
1660
|
-
readonly distT: number;
|
|
1661
|
-
readonly distB: number;
|
|
1662
|
-
/** Caret/hit advance start (slot left, before distL). */
|
|
1663
|
-
readonly advanceStart: number;
|
|
1664
|
-
/** Caret/hit advance end (slot + totalWidth). */
|
|
1665
|
-
readonly advanceEnd: number;
|
|
1666
|
-
readonly baselineOffset: number;
|
|
1667
|
-
readonly paintBounds: LayoutBox;
|
|
1668
|
-
readonly hitBounds: LayoutBox;
|
|
1669
|
-
readonly geometry: DrawingGeometry;
|
|
1670
|
-
readonly resource: ImageResourceState;
|
|
1671
|
-
readonly accessibility: DrawingAccessibility;
|
|
1672
|
-
/** Sanitized external hyperlink projection; inert until an explicit gesture activates it. */
|
|
1673
|
-
readonly hyperlinkHref: string | null;
|
|
1674
|
-
readonly effects: Readonly<{
|
|
1675
|
-
readonly grayscale: boolean;
|
|
1676
|
-
readonly brightness: number;
|
|
1677
|
-
readonly contrast: number;
|
|
1678
|
-
}>;
|
|
1679
|
-
readonly crop: SourceCrop;
|
|
1680
|
-
readonly transform: DrawingTransform;
|
|
1681
|
-
/** Fixed non-picture graphic kind for refusal labels (`chart`, `group`, …); null for pictures. */
|
|
1682
|
-
readonly placeholderGraphicKind: string | null;
|
|
1683
|
-
/** Typed solid-geometry payload for a renderable `wps:wsp` shape; null otherwise. */
|
|
1684
|
-
readonly vectorShape: VectorShapeProjection | null;
|
|
1685
|
-
/**
|
|
1686
|
-
* The revision wrappers enclosing the owning run, outermost first — the same stack spans
|
|
1687
|
-
* carry, so paint and review chrome give a tracked picture the same cues as tracked text.
|
|
1688
|
-
* Absent when the drawing is untracked.
|
|
1689
|
-
*/
|
|
1690
|
-
readonly revisions?: readonly RevisionAttribution[];
|
|
1691
|
-
}
|
|
1692
|
-
interface InlineDrawingLayoutContext {
|
|
1693
|
-
readonly ownerPartName: string;
|
|
1694
|
-
/** Precomputed run-level atom id (`w:drawing` or MC wrapper) → projection. */
|
|
1695
|
-
readonly projectionForAtom?: (atomNodeId: string) => DrawingProjection | null;
|
|
1696
|
-
readonly project: (drawing: OoxmlDrawingNode) => DrawingProjection | null;
|
|
1697
|
-
readonly resourceOf: (projection: DrawingProjection) => ImageResourceState;
|
|
1698
|
-
}
|
|
1699
|
-
/** Named fallback when a positioning frame cannot be resolved (OpenSpec 4.6). */
|
|
1700
|
-
type AnchoredDrawingLayoutFallback = 'unresolvable-frame' | 'page-defer-exhausted';
|
|
1701
|
-
interface AnchoredDrawingRecord extends Omit<InlineDrawingRecord, 'kind' | 'baselineOffset' | 'advanceStart' | 'advanceEnd' | 'distL' | 'distR' | 'distT' | 'distB'> {
|
|
1702
|
-
readonly kind: 'anchoredDrawing';
|
|
1703
|
-
readonly anchorParagraphId: string;
|
|
1704
|
-
readonly horizontalFrame: DrawingHorizontalReferenceFrame;
|
|
1705
|
-
readonly verticalFrame: DrawingVerticalReferenceFrame;
|
|
1706
|
-
readonly horizontalFrameOrigin: number;
|
|
1707
|
-
readonly verticalFrameOrigin: number;
|
|
1708
|
-
readonly behindDocument: boolean;
|
|
1709
|
-
readonly allowOverlap: boolean;
|
|
1710
|
-
readonly layoutInCell: boolean;
|
|
1711
|
-
readonly relativeHeight: number;
|
|
1712
|
-
readonly wrap: Exclude<ImageWrapTarget, 'inline'>;
|
|
1713
|
-
readonly layoutFallback?: AnchoredDrawingLayoutFallback;
|
|
1714
|
-
/** Canonical document traversal index within the owner story part. */
|
|
1715
|
-
readonly sourceOrder?: number;
|
|
1716
|
-
/**
|
|
1717
|
-
* Laid-out textbox story for a `wps:txbx` drawing; paint renders it clipped inside the
|
|
1718
|
-
* extent instead of a placeholder. Absent when the drawing carries no story or the host
|
|
1719
|
-
* did not thread story layout (the record then degrades to the placeholder path).
|
|
1720
|
-
*/
|
|
1721
|
-
readonly textboxStory?: TextboxStoryLayout;
|
|
1722
|
-
}
|
|
1723
|
-
|
|
1724
|
-
/**
|
|
1725
|
-
* One parsed `HYPERLINK` instruction: the raw, unsanitized pieces.
|
|
1726
|
-
*
|
|
1727
|
-
* `target` and `anchor` are verbatim from the instruction — the projector at the trust
|
|
1728
|
-
* boundary decides what, if anything, they become in a DOM sink.
|
|
1729
|
-
*/
|
|
1730
|
-
interface HyperlinkFieldSpec {
|
|
1731
|
-
/** The target as authored (first quoted or bare non-switch token), or null. */
|
|
1732
|
-
readonly target: string | null;
|
|
1733
|
-
/** `\l` — a bookmark name in this document, or null. */
|
|
1734
|
-
readonly anchor: string | null;
|
|
1735
|
-
/** `\o` — the hover tooltip, or null. */
|
|
1736
|
-
readonly tooltip: string | null;
|
|
1737
|
-
}
|
|
1738
|
-
|
|
1739
|
-
/**
|
|
1740
|
-
* What a piece says about the FIELD result it came from, for Word's shading.
|
|
1741
|
-
*
|
|
1742
|
-
* Carried from layout rather than decided at paint time because only the walk knows an atom was
|
|
1743
|
-
* a field at all — by paint the result is just text. Whether the shading is actually drawn is a
|
|
1744
|
-
* view decision made downstream, so this states the fact and nothing about the appearance.
|
|
1745
|
-
*/
|
|
1746
|
-
interface FieldAtomMarker {
|
|
1747
|
-
/**
|
|
1748
|
-
* A legacy form field: `w:fldChar/w:ffData` (FORMTEXT, FORMCHECKBOX, FORMDROPDOWN).
|
|
1749
|
-
*
|
|
1750
|
-
* Word shades these on a different rule from ordinary fields — always, unless the document
|
|
1751
|
-
* turns it off — because they mark the blanks somebody is meant to fill in.
|
|
1752
|
-
*/
|
|
1753
|
-
readonly formField: boolean;
|
|
1754
|
-
/**
|
|
1755
|
-
* A BODY PAGE / NUMPAGES / SECTIONPAGES atom whose value depends on pagination.
|
|
1756
|
-
*
|
|
1757
|
-
* The paragraph walk cannot know which page the field lands on — layout runs before the page
|
|
1758
|
-
* count — so it paints a placeholder and records the field's kind here. Document finalize
|
|
1759
|
-
* (`substituteBodyPageFields`) reads this marker and substitutes the real value per page.
|
|
1760
|
-
* Absent in headers/footers, which evaluate live through their own per-page projector.
|
|
1761
|
-
*/
|
|
1762
|
-
readonly pageField?: {
|
|
1763
|
-
readonly kind: AllowlistedPageField;
|
|
1764
|
-
/** The field's `\#` numeric picture, applied when finalize substitutes the value. */
|
|
1765
|
-
readonly picture?: string;
|
|
1766
|
-
};
|
|
1767
|
-
/**
|
|
1768
|
-
* A BODY `PAGEREF` atom whose value is the page number its bookmark target lands on.
|
|
1769
|
-
*
|
|
1770
|
-
* Deferred exactly like {@link pageField}: the paragraph walk paints the field's cached
|
|
1771
|
-
* result (or the placeholder digit when the file cached none) and records the resolved
|
|
1772
|
-
* target here; document finalize substitutes the number of the page hosting the target's
|
|
1773
|
-
* first fragment, gated per field on the calibration verdict.
|
|
1774
|
-
*/
|
|
1775
|
-
readonly pageRef?: PageRefFieldProjection;
|
|
1776
|
-
}
|
|
1777
|
-
/** A half-open model-offset range, in the paragraph's own UTF-16 offset space. */
|
|
1778
|
-
interface ModelRange {
|
|
1779
|
-
readonly start: number;
|
|
1780
|
-
readonly end: number;
|
|
1781
|
-
}
|
|
1782
|
-
/**
|
|
1783
|
-
* How layout turns a typed `w:hyperlink` node into the sanitized record spans carry.
|
|
1784
|
-
*
|
|
1785
|
-
* Injected rather than computed here because resolving `r:id` needs the PACKAGE's
|
|
1786
|
-
* relationships and this module only ever sees one part's tree. `null` means the caller
|
|
1787
|
-
* declined to project — the runs still measure and paint, they simply carry no link, which is
|
|
1788
|
-
* the right degradation: text is never lost for want of a target.
|
|
1789
|
-
*/
|
|
1790
|
-
type HyperlinkProjector = (link: OoxmlNode) => SpanLinkRecord | null;
|
|
1791
|
-
/**
|
|
1792
|
-
* How layout turns a parsed HYPERLINK field instruction into the sanitized record spans carry.
|
|
1793
|
-
*
|
|
1794
|
-
* Injected for the same reason as {@link HyperlinkProjector}: the spec's raw target must cross
|
|
1795
|
-
* the surface's ONE href trust boundary, and layout owns no sanitization policy. `null` means
|
|
1796
|
-
* no link — the cached result still paints as plain text, which is the right degradation.
|
|
1797
|
-
*/
|
|
1798
|
-
type FieldLinkProjector = (spec: HyperlinkFieldSpec) => SpanLinkRecord | null;
|
|
1799
|
-
|
|
1800
|
-
/** Test-only mutable counters; omitted by production call sites. Not package-public. */
|
|
1801
|
-
interface TableBorderGridResolveWork {
|
|
1802
|
-
/** Sparse intervals emitted (not dense column slots). */
|
|
1803
|
-
ownershipSlotsWritten: number;
|
|
1804
|
-
columnLookups: number;
|
|
1805
|
-
}
|
|
1806
|
-
/** Shared remaining interval budget for nested table finalization in one layout. */
|
|
1807
|
-
interface TableBorderOwnershipBudget {
|
|
1808
|
-
intervalsRemaining: number;
|
|
1809
|
-
}
|
|
1810
|
-
|
|
1811
|
-
/** Which physical edge of a box a border sits on. */
|
|
1812
|
-
type TableBorderSideName = 'top' | 'right' | 'bottom' | 'left';
|
|
1813
|
-
/**
|
|
1814
|
-
* One border edge in one of three states.
|
|
1815
|
-
*
|
|
1816
|
-
* `omitted` and `none` are NOT the same: an omitted edge inherits from the table style or the
|
|
1817
|
-
* neighbouring cell, while an explicit `none` wins the conflict and draws nothing. Collapsing
|
|
1818
|
-
* them would let a style's border reappear where the author removed it.
|
|
1819
|
-
*/
|
|
1820
|
-
type TableBorderSide = {
|
|
1821
|
-
readonly state: 'omitted';
|
|
1822
|
-
} | {
|
|
1823
|
-
readonly state: 'none';
|
|
1824
|
-
} | {
|
|
1825
|
-
readonly state: 'edge';
|
|
1826
|
-
readonly style: TableBorderStyle;
|
|
1827
|
-
/** Validated RRGGBB, or null for auto/missing (paint defaults to black). */
|
|
1828
|
-
readonly color: string | null;
|
|
1829
|
-
/** Thickness in points (`w:sz` is eighths of a point). */
|
|
1830
|
-
readonly widthPt: number;
|
|
1831
|
-
};
|
|
1832
|
-
/** A table's six authored border edges: four outer, plus the two interior intervals. */
|
|
1833
|
-
interface TableBorderBox {
|
|
1834
|
-
readonly top: TableBorderSide;
|
|
1835
|
-
readonly left: TableBorderSide;
|
|
1836
|
-
readonly bottom: TableBorderSide;
|
|
1837
|
-
readonly right: TableBorderSide;
|
|
1838
|
-
readonly insideH: TableBorderSide;
|
|
1839
|
-
readonly insideV: TableBorderSide;
|
|
1840
|
-
}
|
|
1841
|
-
/** The four resolved edges of one cell, after conflict resolution against its neighbours. */
|
|
1842
|
-
interface CellBorderBox {
|
|
1843
|
-
readonly top: TableBorderSide;
|
|
1844
|
-
readonly left: TableBorderSide;
|
|
1845
|
-
readonly bottom: TableBorderSide;
|
|
1846
|
-
readonly right: TableBorderSide;
|
|
1847
|
-
}
|
|
1848
|
-
/** Final edge winner; absent means the side/interval is not drawn. */
|
|
1849
|
-
interface ResolvedTableBorderEdge {
|
|
1850
|
-
readonly style: TableBorderStyle;
|
|
1851
|
-
readonly color: string | null;
|
|
1852
|
-
readonly widthPt: number;
|
|
1853
|
-
}
|
|
1854
|
-
/**
|
|
1855
|
-
* Conflict winner over one grid interval of a cell side.
|
|
1856
|
-
*
|
|
1857
|
-
* `gridStart`/`gridEnd` are absolute grid column indices for horizontal sides and absolute
|
|
1858
|
-
* row indices for vertical sides (half-open). `startPt`/`endPt` are cell-local along-axis
|
|
1859
|
-
* positions in layout points.
|
|
1860
|
-
*/
|
|
1861
|
-
interface ResolvedTableBorderEdgeSegment {
|
|
1862
|
-
readonly side: TableBorderSideName;
|
|
1863
|
-
readonly gridStart: number;
|
|
1864
|
-
readonly gridEnd: number;
|
|
1865
|
-
readonly startPt: number;
|
|
1866
|
-
readonly endPt: number;
|
|
1867
|
-
readonly edge: ResolvedTableBorderEdge;
|
|
1868
|
-
}
|
|
1869
|
-
/**
|
|
1870
|
-
* One published stroke rectangle in cell-local layout points.
|
|
1871
|
-
*
|
|
1872
|
-
* Paint multiplies x/y/width/height by scale and draws — no metrics, gaps, or corner math.
|
|
1873
|
-
*/
|
|
1874
|
-
interface TableBorderStrokeRecord {
|
|
1875
|
-
readonly side: TableBorderSideName;
|
|
1876
|
-
readonly role: 'outer' | 'inner' | 'middle' | 'edge';
|
|
1877
|
-
readonly color: string | null;
|
|
1878
|
-
/** CSS keyword for this stroke (compound strokes are always solid). */
|
|
1879
|
-
readonly cssStyle: 'solid' | 'dashed' | 'dotted';
|
|
1880
|
-
readonly x: number;
|
|
1881
|
-
readonly y: number;
|
|
1882
|
-
readonly width: number;
|
|
1883
|
-
readonly height: number;
|
|
1884
|
-
}
|
|
1885
|
-
/**
|
|
1886
|
-
* Layout-owned cell borders after conflict resolution and compound expansion.
|
|
1887
|
-
*
|
|
1888
|
-
* Convenience `top`/`left`/`bottom`/`right` are set when that side has a single uniform
|
|
1889
|
-
* full-span winner (existing consumers / CSS simple edges). Multi-interval winners live
|
|
1890
|
-
* only on `edgeSegments`. Compound geometry is always on `strokes`.
|
|
1891
|
-
*/
|
|
1892
|
-
interface ResolvedCellBorders {
|
|
1893
|
-
readonly top?: ResolvedTableBorderEdge;
|
|
1894
|
-
readonly left?: ResolvedTableBorderEdge;
|
|
1895
|
-
readonly bottom?: ResolvedTableBorderEdge;
|
|
1896
|
-
readonly right?: ResolvedTableBorderEdge;
|
|
1897
|
-
readonly edgeSegments?: readonly ResolvedTableBorderEdgeSegment[];
|
|
1898
|
-
readonly strokes?: readonly TableBorderStrokeRecord[];
|
|
1899
|
-
}
|
|
1900
|
-
/** Soft cap on published stroke rectangles per cell (security / pathological spans). */
|
|
1901
|
-
declare const MAX_TABLE_BORDER_STROKES = 256;
|
|
1902
|
-
/** Read one OOXML border child into the three-state model. */
|
|
1903
|
-
declare function readBorderSide(node: OoxmlElement | undefined): TableBorderSide;
|
|
1904
|
-
/**
|
|
1905
|
-
* Read a table's `w:tblBorders`, dropping or clamping hostile values.
|
|
1906
|
-
*
|
|
1907
|
-
* Widths and colours come from a file: an out-of-range `w:sz` becomes a layout dimension, so it is
|
|
1908
|
-
* bounded here rather than downstream.
|
|
1909
|
-
*/
|
|
1910
|
-
declare function readTableBorders(tblPr: OoxmlElement | undefined): TableBorderBox;
|
|
1911
|
-
/** Read one cell's `w:tcBorders`, under the same bounds {@link readTableBorders} applies. */
|
|
1912
|
-
declare function readCellBorders(tcPr: OoxmlElement | undefined): CellBorderBox;
|
|
1913
|
-
/**
|
|
1914
|
-
* Conflict weight: the authored width in eighths of a point, and nothing else.
|
|
1915
|
-
*
|
|
1916
|
-
* Word-matching, not conformance — §17.4.39 (`w:tblBorders`) and §17.4.66 (`w:tcBorders`)
|
|
1917
|
-
* describe the elements and specify no conflict algorithm. Word picks the heavier RULE, so
|
|
1918
|
-
* a 6pt dashed rule beats a hairline single. Folding the style rank into the weight (an
|
|
1919
|
-
* `sz × border-number` product) made a 0.5pt double outrank a 1pt single and made every
|
|
1920
|
-
* dashed or dotted rule weigh 1 regardless of `w:sz`, which erased its width entirely.
|
|
1921
|
-
*/
|
|
1922
|
-
declare function borderWeight(side: TableBorderSide): number;
|
|
1923
|
-
/**
|
|
1924
|
-
* Pick the winner between two candidates on a shared grid line (zero cell spacing).
|
|
1925
|
-
*
|
|
1926
|
-
* `none` loses to any edge; two `none`/omitted yield omitted (no paint). Width decides;
|
|
1927
|
-
* equal widths rank by style, then prefer the darker color, then `preferFirst`
|
|
1928
|
-
* (reading-order / first candidate).
|
|
1929
|
-
*/
|
|
1930
|
-
declare function resolveBorderConflict(first: TableBorderSide, second: TableBorderSide, preferFirst?: boolean): TableBorderSide;
|
|
1931
|
-
interface BorderGridCell {
|
|
1932
|
-
readonly gridColumn: number;
|
|
1933
|
-
readonly gridSpan: number;
|
|
1934
|
-
readonly vMergeContinue: boolean;
|
|
1935
|
-
readonly borders: CellBorderBox;
|
|
1936
|
-
/** Set on restart cells that visually span into later rows. */
|
|
1937
|
-
readonly mergeRowSpan?: number;
|
|
1938
|
-
}
|
|
1939
|
-
/**
|
|
1940
|
-
* The absolute grid a table's borders are drawn on: column widths, and per-row tops and heights.
|
|
1941
|
-
*
|
|
1942
|
-
* Shared by every edge so adjacent cells resolve to the SAME line, rather than each computing its
|
|
1943
|
-
* own and leaving a hairline gap between them.
|
|
1944
|
-
*/
|
|
1945
|
-
interface BorderGridGeometry {
|
|
1946
|
-
/** Absolute column widths for the whole table (points). */
|
|
1947
|
-
readonly columnWidthsPt: readonly number[];
|
|
1948
|
-
/**
|
|
1949
|
-
* Per laid-out row: absolute top and height in the same coordinate space as cell boxes
|
|
1950
|
-
* (only relative differences matter for vertical edge segmentation).
|
|
1951
|
-
*/
|
|
1952
|
-
readonly rowBands: readonly {
|
|
1953
|
-
readonly y: number;
|
|
1954
|
-
readonly height: number;
|
|
1955
|
-
}[];
|
|
1956
|
-
/** Per laid-out cell: width/height after vMerge expansion (cell-local stroke space). */
|
|
1957
|
-
readonly cellBoxes: readonly (readonly {
|
|
1958
|
-
readonly width: number;
|
|
1959
|
-
readonly height: number;
|
|
1960
|
-
}[])[];
|
|
1961
|
-
}
|
|
1962
|
-
/**
|
|
1963
|
-
* Resolve borders for every cell in a laid-out table fragment.
|
|
1964
|
-
*
|
|
1965
|
-
* Shared vertical edges: conflict(left.right, right.left) → assigned to the left cell,
|
|
1966
|
-
* segmented per row when a vMerge restart faces differing neighbors.
|
|
1967
|
-
* Shared horizontal edges: conflict(above.bottom, below.top) → assigned to the above cell,
|
|
1968
|
-
* segmented per grid column when a gridSpan cell faces differing below neighbors; vMerge
|
|
1969
|
-
* interior seams are suppressed per interval.
|
|
1970
|
-
*
|
|
1971
|
-
* When `geometry` is provided, compound edges expand into explicit stroke records with
|
|
1972
|
-
* corner-adjusted endpoints in cell-local points.
|
|
1973
|
-
*/
|
|
1974
|
-
declare function resolveTableCellBorderGrid(rows: readonly (readonly BorderGridCell[])[], table: TableBorderBox, columnCount: number, geometry?: BorderGridGeometry, work?: TableBorderGridResolveWork, ownershipBudget?: TableBorderOwnershipBudget): ResolvedCellBorders[][];
|
|
1975
|
-
/** Width contribution of a resolved edge for content inset / row sizing. */
|
|
1976
|
-
declare function borderExtentPt(edge: ResolvedTableBorderEdge | TableBorderSide | undefined): number;
|
|
1977
|
-
|
|
1978
|
-
interface EquationGeometryBase {
|
|
1979
|
-
readonly box: LayoutBox;
|
|
1980
|
-
/** Baseline measured from this node's top edge. */
|
|
1981
|
-
readonly baseline: number;
|
|
1982
|
-
}
|
|
1983
|
-
interface EquationTextGeometry extends EquationGeometryBase {
|
|
1984
|
-
readonly kind: 'text' | 'fallback';
|
|
1985
|
-
readonly text: string;
|
|
1986
|
-
readonly fontSizePt: number;
|
|
1987
|
-
}
|
|
1988
|
-
interface EquationRowGeometry extends EquationGeometryBase {
|
|
1989
|
-
readonly kind: 'row';
|
|
1990
|
-
readonly items: readonly EquationGeometry[];
|
|
1991
|
-
}
|
|
1992
|
-
interface EquationFractionGeometry extends EquationGeometryBase {
|
|
1993
|
-
readonly kind: 'fraction';
|
|
1994
|
-
readonly numerator: EquationGeometry;
|
|
1995
|
-
readonly denominator: EquationGeometry;
|
|
1996
|
-
readonly bar: LayoutBox;
|
|
1997
|
-
}
|
|
1998
|
-
interface EquationRadicalGeometry extends EquationGeometryBase {
|
|
1999
|
-
readonly kind: 'radical';
|
|
2000
|
-
readonly sign: EquationTextGeometry;
|
|
2001
|
-
readonly radicand: EquationGeometry;
|
|
2002
|
-
readonly degree?: EquationGeometry;
|
|
2003
|
-
readonly bar: LayoutBox;
|
|
2004
|
-
}
|
|
2005
|
-
interface EquationScriptGeometry extends EquationGeometryBase {
|
|
2006
|
-
readonly kind: 'script';
|
|
2007
|
-
readonly base: EquationGeometry;
|
|
2008
|
-
readonly subscript?: EquationGeometry;
|
|
2009
|
-
readonly superscript?: EquationGeometry;
|
|
2010
|
-
}
|
|
2011
|
-
interface EquationNaryGeometry extends EquationGeometryBase {
|
|
2012
|
-
readonly kind: 'nary';
|
|
2013
|
-
readonly operator: EquationTextGeometry;
|
|
2014
|
-
readonly body: EquationGeometry;
|
|
2015
|
-
readonly lowerLimit?: EquationGeometry;
|
|
2016
|
-
readonly upperLimit?: EquationGeometry;
|
|
2017
|
-
}
|
|
2018
|
-
type EquationGeometry = EquationTextGeometry | EquationRowGeometry | EquationFractionGeometry | EquationRadicalGeometry | EquationScriptGeometry | EquationNaryGeometry;
|
|
2019
|
-
/** Equation metadata carried by one atomic semantic span. */
|
|
2020
|
-
interface EquationSpanRecord {
|
|
2021
|
-
readonly sourceNodeId: string;
|
|
2022
|
-
readonly geometry: EquationGeometry;
|
|
2023
|
-
readonly fallbackText: string;
|
|
2024
|
-
readonly truncated: boolean;
|
|
2025
|
-
}
|
|
2026
|
-
/** Compose one bounded OMML projection into paint-ready point geometry. */
|
|
2027
|
-
declare function layoutEquation(projection: OmmlEquationProjection, measurer: TextMeasurer, style: ResolvedRunStyle): EquationSpanRecord;
|
|
2028
|
-
|
|
2029
|
-
/** A half-open UTF-16 range inside one paragraph, addressed by its canonical node id. */
|
|
2030
|
-
interface SourceRange {
|
|
2031
|
-
readonly paragraphId: string;
|
|
2032
|
-
readonly start: number;
|
|
2033
|
-
readonly end: number;
|
|
2034
|
-
}
|
|
2035
|
-
/**
|
|
2036
|
-
* A rectangle in layout POINTS.
|
|
2037
|
-
*
|
|
2038
|
-
* Points everywhere in this layer — twips convert at property-read boundaries and CSS pixels at
|
|
2039
|
-
* paint. A box carrying either of those would eventually be added to one carrying the other.
|
|
2040
|
-
*/
|
|
2041
|
-
interface LayoutBox {
|
|
2042
|
-
readonly x: number;
|
|
2043
|
-
readonly y: number;
|
|
2044
|
-
readonly width: number;
|
|
2045
|
-
readonly height: number;
|
|
2046
|
-
}
|
|
2047
|
-
/**
|
|
2048
|
-
* A bottom paragraph border as layout published it.
|
|
2049
|
-
*
|
|
2050
|
-
* `box` is the rule's geometry in the same coordinate space as the fragment (page-content
|
|
2051
|
-
* relative). Paint positions from this box and MUST NOT remeasure the border.
|
|
2052
|
-
*/
|
|
2053
|
-
interface ParagraphBottomBorderRecord {
|
|
2054
|
-
readonly edge: ParagraphBorderEdge;
|
|
2055
|
-
readonly box: LayoutBox;
|
|
2056
|
-
}
|
|
2057
|
-
/**
|
|
2058
|
-
* One `w:pBdr` rule as layout published it.
|
|
2059
|
-
*
|
|
2060
|
-
* `box` is the STROKE rectangle in the same coordinate space as the fragment, so paint sets a
|
|
2061
|
-
* position and a colour and nothing else. It matters that paint cannot derive these itself:
|
|
2062
|
-
* Word draws the side rules OUTSIDE the text column, so `box.x` on a `left`/`bar` stroke is
|
|
2063
|
-
* left of the fragment box and a painter reasoning from the fragment alone would put it
|
|
2064
|
-
* inside the text.
|
|
2065
|
-
*/
|
|
2066
|
-
interface ParagraphBorderStrokeRecord {
|
|
2067
|
-
readonly side: ParagraphBorderSide;
|
|
2068
|
-
readonly edge: ParagraphBorderEdge;
|
|
2069
|
-
readonly box: LayoutBox;
|
|
2070
|
-
}
|
|
2071
|
-
/**
|
|
2072
|
-
* The hyperlink a span sits inside, as layout resolved it.
|
|
2073
|
-
*
|
|
2074
|
-
* Already SANITIZED: `href` is the runtime projection produced once at the trust boundary,
|
|
2075
|
-
* and `null` means the link is inert — a refused scheme, or a relationship the package does
|
|
2076
|
-
* not declare. Paint, hit-testing and the popover consume this and never the authored target,
|
|
2077
|
-
* so there is exactly one place a file-derived URL becomes something a browser can follow.
|
|
2078
|
-
*
|
|
2079
|
-
* `id` is the `w:hyperlink` node's canonical id, which is what makes the spans of one link
|
|
2080
|
-
* recognisable as one link across the several lines it wraps onto — and what an unlink or a
|
|
2081
|
-
* retarget addresses.
|
|
2082
|
-
*/
|
|
2083
|
-
interface SpanLinkRecord {
|
|
2084
|
-
readonly id: string;
|
|
2085
|
-
readonly kind: 'external' | 'internal' | 'unresolved';
|
|
2086
|
-
/** Sanitized runtime projection: an absolute URL, `#anchor`, or null when inert. */
|
|
2087
|
-
readonly href: string | null;
|
|
2088
|
-
/** Bookmark name for an internal link, so navigation need not re-parse the fragment. */
|
|
2089
|
-
readonly anchor?: string;
|
|
2090
|
-
/** `w:tooltip` — paint puts it on the anchor's `title`. */
|
|
2091
|
-
readonly tooltip?: string;
|
|
2092
|
-
}
|
|
2093
|
-
/** A run of text on one line sharing identical resolved formatting. */
|
|
2094
|
-
interface StyleSpanRecord {
|
|
2095
|
-
readonly range: SourceRange;
|
|
2096
|
-
readonly text: string;
|
|
2097
|
-
/** The run's authored properties, retained as evidence. */
|
|
2098
|
-
readonly props: readonly OoxmlProperty[];
|
|
2099
|
-
/**
|
|
2100
|
-
* The same properties RESOLVED — one unit system, defaults applied.
|
|
2101
|
-
*
|
|
2102
|
-
* Carried on the span so the measurer, the span and the painter all read one resolution
|
|
2103
|
-
* rather than each deriving its own. Two derivations that disagree by a fraction of a
|
|
2104
|
-
* point put the caret where no glyph is.
|
|
2105
|
-
*/
|
|
2106
|
-
readonly style: ResolvedRunStyle;
|
|
2107
|
-
/**
|
|
2108
|
-
* The `w:rFonts` slot this span's text resolves its face through; absent means the base
|
|
2109
|
-
* (ascii/hAnsi) slots. {@link style} stays the run's full resolution — with both
|
|
2110
|
-
* `fontFamily` and `fontFamilyEastAsia` — so formatting readback and the format painter
|
|
2111
|
-
* see the run as authored; measurement, paint and hit-testing resolve the effective face
|
|
2112
|
-
* with `styleForFontSlot(span.style, span.fontSlot)`.
|
|
2113
|
-
*/
|
|
2114
|
-
readonly fontSlot?: FontSlot;
|
|
2115
|
-
readonly box: LayoutBox;
|
|
2116
|
-
/**
|
|
2117
|
-
* Cumulative advances from {@link box}.x to each UTF-16 caret boundary in {@link text}.
|
|
2118
|
-
*
|
|
2119
|
-
* Length is `text.length + 1` (both endpoints). When PRESENT, these are the interaction
|
|
2120
|
-
* authority: hit-testing and the caret read them instead of re-measuring. Layout does not
|
|
2121
|
-
* publish them eagerly — measuring every character of every laid span dominated page
|
|
2122
|
-
* repagination — so interactions measure prefixes on demand through the same measurer the
|
|
2123
|
-
* span was laid with (memoized per span; see `prefixWidth` in semantic-hit-test.ts), and
|
|
2124
|
-
* only interpolate across {@link box}.width when no measurer is supplied.
|
|
2125
|
-
*/
|
|
2126
|
-
readonly caretEdges?: readonly number[];
|
|
2127
|
-
/**
|
|
2128
|
-
* `w:tab/@w:leader` of the stop a `\t` span advanced to (ECMA-376 §17.3.1.38).
|
|
2129
|
-
*
|
|
2130
|
-
* Only ever set on a tab span, and only for a non-`none` leader. Paint repeats the glyph
|
|
2131
|
-
* across the advance THIS box already reserved — the leader adds no width of its own, so
|
|
2132
|
-
* it can never move the text that follows it.
|
|
2133
|
-
*/
|
|
2134
|
-
readonly tabLeader?: TabLeader;
|
|
2135
|
-
/**
|
|
2136
|
-
* Advance of ONE leader glyph in this run's face, in points, measured by layout.
|
|
2137
|
-
*
|
|
2138
|
-
* Paint cannot ask a font how wide a character is, so without this it had to guess and
|
|
2139
|
-
* deliberately overfill, leaving the dots at whatever spacing an over-long string
|
|
2140
|
-
* happened to produce. Measured, the leader is spaced exactly as the same character
|
|
2141
|
-
* typed there would be — which is what Word draws.
|
|
2142
|
-
*/
|
|
2143
|
-
readonly tabLeaderAdvancePt?: number;
|
|
2144
|
-
/**
|
|
2145
|
-
* The hyperlink this span belongs to, or absent for ordinary text.
|
|
2146
|
-
*
|
|
2147
|
-
* Carried on the SPAN rather than looked up at paint time because a link that wraps
|
|
2148
|
-
* produces one set of spans per line, and paint has no paragraph to walk — only the line
|
|
2149
|
-
* it was handed.
|
|
2150
|
-
*/
|
|
2151
|
-
readonly link?: SpanLinkRecord;
|
|
2152
|
-
/**
|
|
2153
|
-
* Horizontal jump, in points, that a floating object's wrap zone forced before this span.
|
|
2154
|
-
*
|
|
2155
|
-
* A line that resumes on the far side of a float is still ONE line: its spans keep running
|
|
2156
|
-
* model offsets and share a selection band. Only layout knows the jump is an obstacle
|
|
2157
|
-
* rather than justification slack, so it publishes it here. Paint reserves it with an inert
|
|
2158
|
-
* advance and excludes it from the word spacing it reconstructs — inferring the difference
|
|
2159
|
-
* from the gap alone spread the float's whole width across every space on the line.
|
|
2160
|
-
*/
|
|
2161
|
-
readonly wrapAdvanceBefore?: number;
|
|
2162
|
-
/**
|
|
2163
|
-
* The revision wrappers this text sits inside, outermost first, absent when untracked.
|
|
2164
|
-
*
|
|
2165
|
-
* Carried on the span for the same reason `style` is: paint and the review surface must read
|
|
2166
|
-
* ONE attribution. A sidebar that re-derived which revision covers a span by walking the tree
|
|
2167
|
-
* could disagree with what was painted, and the card would point at the wrong text.
|
|
2168
|
-
*/
|
|
2169
|
-
readonly revisions?: readonly RevisionAttribution[];
|
|
2170
|
-
/**
|
|
2171
|
-
* Present when this span is a field's displayed RESULT, for the shading Word draws under one.
|
|
2172
|
-
*
|
|
2173
|
-
* `projected` cannot answer this: it is also set for note marks and inline drawings, so it
|
|
2174
|
-
* says "layout owns these glyphs" rather than "this is a field". Word shades legacy form
|
|
2175
|
-
* fields on a different rule from ordinary ones, which is why the marker distinguishes them.
|
|
2176
|
-
*
|
|
2177
|
-
* States the FACT, never the appearance — whether shading is drawn is a view decision, made
|
|
2178
|
-
* downstream from a host option and the document's own `w:doNotShadeFormData`. Deciding it
|
|
2179
|
-
* here would put the caret into layout's cache key and repaginate on every arrow press.
|
|
2180
|
-
*/
|
|
2181
|
-
readonly fieldAtom?: FieldAtomMarker;
|
|
2182
|
-
/**
|
|
2183
|
-
* Live PAGE/NUMPAGES/SECTIONPAGES projection (layout-time evaluated text).
|
|
2184
|
-
*
|
|
2185
|
-
* Computed substitutions are not model-editable: paint treats these as atomic furniture
|
|
2186
|
-
* and selection mapping refuses them the way it refuses markers.
|
|
2187
|
-
*/
|
|
2188
|
-
readonly projected?: boolean;
|
|
2189
|
-
/** Paint-ready geometry for one atomic Office Math equation. */
|
|
2190
|
-
readonly equation?: EquationSpanRecord;
|
|
2191
|
-
/**
|
|
2192
|
-
* Footnote/endnote navigation metadata for projected note atoms.
|
|
2193
|
-
*
|
|
2194
|
-
* Paint tags body citations (`to-note`) and note-body marks (`to-body`) so React chrome
|
|
2195
|
-
* can jump without owning layout logic.
|
|
2196
|
-
*/
|
|
2197
|
-
readonly noteNav?: {
|
|
2198
|
-
readonly scopeId: string;
|
|
2199
|
-
readonly direction: 'to-note' | 'to-body';
|
|
2200
|
-
};
|
|
2201
|
-
}
|
|
2202
|
-
/**
|
|
2203
|
-
* One laid-out line: its geometry, its baseline, and the styled spans it renders.
|
|
2204
|
-
*
|
|
2205
|
-
* The unit hit-testing and caret placement resolve against. Geometry comes from HERE, never from
|
|
2206
|
-
* the DOM, which is what lets an empty paragraph still get a caret.
|
|
2207
|
-
*/
|
|
2208
|
-
interface LineRecord {
|
|
2209
|
-
readonly id: string;
|
|
2210
|
-
readonly range: SourceRange;
|
|
2211
|
-
readonly spans: readonly StyleSpanRecord[];
|
|
2212
|
-
readonly box: LayoutBox;
|
|
2213
|
-
/**
|
|
2214
|
-
* Where the line's content actually starts, after alignment and the first-line indent.
|
|
2215
|
-
*
|
|
2216
|
-
* {@link box} is the content BAND the line was broken against — its `x` is the indented
|
|
2217
|
-
* column edge and its `width` the available measure, neither of which moves with
|
|
2218
|
-
* `w:jc`. Alignment is otherwise expressed only as x offsets on the span boxes, so a line
|
|
2219
|
-
* with no spans (an empty paragraph) had no aligned origin at all: paint, hit testing and
|
|
2220
|
-
* the caret each fell back to `box.x` and drew a centred empty paragraph's caret hard
|
|
2221
|
-
* against the left margin, where it stayed until the first character was typed.
|
|
2222
|
-
*
|
|
2223
|
-
* Equal to the first span's x whenever there is one, so it is the single origin every
|
|
2224
|
-
* consumer can read without a spans-or-box fallback of its own.
|
|
2225
|
-
*/
|
|
2226
|
-
readonly contentX: number;
|
|
2227
|
-
/** Distance from the line box top to the text baseline. */
|
|
2228
|
-
readonly baseline: number;
|
|
2229
|
-
/**
|
|
2230
|
-
* Space ABOVE the glyph band inside {@link box} (exact centering, not auto/atLeast).
|
|
2231
|
-
*
|
|
2232
|
-
* `auto` / `atLeast` extras grow the box BELOW the glyphs — paint puts that depth in
|
|
2233
|
-
* padding-bottom. {@link baseline} is measured from the line top and already includes
|
|
2234
|
-
* this above-band when present.
|
|
2235
|
-
*
|
|
2236
|
-
* Published by layout rather than recovered by paint: three paint sites each deriving it
|
|
2237
|
-
* separately is how they came to disagree about where a line's text sits.
|
|
2238
|
-
*/
|
|
2239
|
-
readonly leading: number;
|
|
2240
|
-
/**
|
|
2241
|
-
* Auto/atLeast line-spacing depth BELOW the glyph band, inside {@link box}.
|
|
2242
|
-
*
|
|
2243
|
-
* The complement of {@link leading}: exact spacing centres the glyphs and moves the
|
|
2244
|
-
* baseline down, while auto/atLeast leave the band at the top and grow the box beneath it.
|
|
2245
|
-
* So the band a consumer needs is `box.height - trailingSpacing - leading`, and
|
|
2246
|
-
* subtracting `leading` alone is right only under the exact rule.
|
|
2247
|
-
*
|
|
2248
|
-
* A line WITH spans carries its band in the span heights too. An empty paragraph carries
|
|
2249
|
-
* nothing, which is why the caret, paint's `padding-bottom` and the content-control
|
|
2250
|
-
* boundary all need this published rather than recovered from the box.
|
|
2251
|
-
*
|
|
2252
|
-
* Zero under the exact rule and on lines holding drawings, where the box is authored.
|
|
2253
|
-
* Absent on lines published before this was measured; treat as zero.
|
|
2254
|
-
*/
|
|
2255
|
-
readonly trailingSpacing?: number;
|
|
2256
|
-
/**
|
|
2257
|
-
* Model ranges on this line covering DELETED content, absent when there is none.
|
|
2258
|
-
*
|
|
2259
|
-
* The caret steps over these rather than entering them: text typed inside a deletion exists
|
|
2260
|
-
* in neither the original nor the proposal, and there is no valid tree for the result.
|
|
2261
|
-
*
|
|
2262
|
-
* Recorded even in display modes that lay the deletion out invisibly, because the offsets
|
|
2263
|
-
* exist in the model in every mode and an offset-by-offset walk would otherwise stop at
|
|
2264
|
-
* positions with no glyph.
|
|
2265
|
-
*/
|
|
2266
|
-
readonly deletedRanges?: readonly ModelRange[];
|
|
2267
|
-
/**
|
|
2268
|
-
* Inline drawings on this line, absent when there are none.
|
|
2269
|
-
*
|
|
2270
|
-
* Each occupies one UTF-16 model unit at {@link InlineDrawingRecord.start}. Hidden drawings
|
|
2271
|
-
* are omitted — they remain in the tree and projection but publish no geometry.
|
|
2272
|
-
*/
|
|
2273
|
-
readonly drawings?: readonly InlineDrawingRecord[];
|
|
2274
|
-
/**
|
|
2275
|
-
* Revision attributions of tracked ANCHORED drawings whose anchor sits on this line,
|
|
2276
|
-
* absent when there are none.
|
|
2277
|
-
*
|
|
2278
|
-
* An anchored drawing paints from the page layer and leaves no span or line drawing at its
|
|
2279
|
-
* anchor offset, so this is the only carrier the margin change bar can read for it. Only
|
|
2280
|
-
* attributions the display mode lays out are recorded, matching the published records.
|
|
2281
|
-
*/
|
|
2282
|
-
readonly anchorRevisions?: readonly RevisionAttribution[];
|
|
2283
|
-
}
|
|
2284
|
-
/**
|
|
2285
|
-
* A paragraph's resolved indent in points, in the vocabulary `w:ind` uses.
|
|
2286
|
-
*
|
|
2287
|
-
* `left`/`right` are signed; `hanging` is not (`ST_TwipsMeasure`). `firstLine` is signed
|
|
2288
|
-
* even though the schema declares it unsigned, because Word's model keeps one signed
|
|
2289
|
-
* first-line indent and this engine follows it.
|
|
2290
|
-
*/
|
|
2291
|
-
interface ParagraphIndent {
|
|
2292
|
-
readonly left: number;
|
|
2293
|
-
readonly right: number;
|
|
2294
|
-
readonly firstLine: number;
|
|
2295
|
-
readonly hanging: number;
|
|
2296
|
-
}
|
|
2297
|
-
/**
|
|
2298
|
-
* The part of one paragraph that sits on one page.
|
|
2299
|
-
*
|
|
2300
|
-
* A paragraph that crosses a page boundary produces several fragments that all name the SAME
|
|
2301
|
-
* `paragraphId`, which is what lets selection and hit-testing treat it as one paragraph while
|
|
2302
|
-
* pagination treats it as two boxes.
|
|
2303
|
-
*/
|
|
2304
|
-
interface ParagraphFragmentRecord {
|
|
2305
|
-
readonly kind: 'paragraph';
|
|
2306
|
-
readonly id: string;
|
|
2307
|
-
readonly paragraphId: string;
|
|
2308
|
-
/** 0 for the first fragment of the paragraph, 1 for its continuation, and so on. */
|
|
2309
|
-
readonly fragmentIndex: number;
|
|
2310
|
-
readonly range: SourceRange;
|
|
2311
|
-
readonly props: readonly OoxmlProperty[];
|
|
2312
|
-
/**
|
|
2313
|
-
* Before/after spacing applied to THIS fragment, in points.
|
|
2314
|
-
*
|
|
2315
|
-
* Continuations carry `before: 0`; only the final fragment carries `after`. The numbers
|
|
2316
|
-
* already reflect Word's adjacent-collapse against the previous paragraph's after.
|
|
2317
|
-
*/
|
|
2318
|
-
readonly spacing: ParagraphSpacing;
|
|
2319
|
-
/**
|
|
2320
|
-
* The paragraph's EFFECTIVE indent in points, cascade and numbering merge included.
|
|
2321
|
-
*
|
|
2322
|
-
* Published because it is not recoverable from anything else here. `props` carries the
|
|
2323
|
-
* cascaded `w:ind`, but a list paragraph's indent comes from `numbering.xml` and is merged
|
|
2324
|
-
* in after the cascade, so a numbered item that authors no `w:ind` reads zero there while
|
|
2325
|
-
* its text sits indented. The geometry is no better an answer: `box.x` is cell-relative
|
|
2326
|
-
* inside a table and is displaced by float zones.
|
|
2327
|
-
*
|
|
2328
|
-
* `firstLine` and `hanging` are kept as OOXML spells them. A consumer wanting the one
|
|
2329
|
-
* signed first-line offset Word models takes `hanging > 0 ? -hanging : firstLine` —
|
|
2330
|
-
* hanging WINS, it is not summed (ECMA-376 §17.3.1.12).
|
|
2331
|
-
*/
|
|
2332
|
-
readonly indent: ParagraphIndent;
|
|
2333
|
-
/** Bottom rule on the final fragment when `w:pBdr/w:bottom` resolves; absent otherwise. */
|
|
2334
|
-
readonly bottomBorder?: ParagraphBottomBorderRecord;
|
|
2335
|
-
/**
|
|
2336
|
-
* Every `w:pBdr` rule this fragment draws, in paint order.
|
|
2337
|
-
*
|
|
2338
|
-
* A paragraph split across pages opens and closes exactly once: the `top` stroke rides the
|
|
2339
|
-
* first fragment, the closing stroke the last. `bottomBorder` remains the bottom rule alone
|
|
2340
|
-
* — a `between` rule closing a grouped paragraph is not one.
|
|
2341
|
-
*/
|
|
2342
|
-
readonly borders?: readonly ParagraphBorderStrokeRecord[];
|
|
2343
|
-
/**
|
|
2344
|
-
* Validated 6-hex paragraph shading fill (`w:pPr/w:shd`), absent for none/auto.
|
|
2345
|
-
*
|
|
2346
|
-
* Paint fills {@link shadingBox}. Measurement ignores it.
|
|
2347
|
-
*/
|
|
2348
|
-
readonly shading?: string;
|
|
2349
|
-
/**
|
|
2350
|
-
* Geometry of the paragraph shading band when {@link shading} is set. Absent when there
|
|
2351
|
-
* is no fill.
|
|
2352
|
-
*
|
|
2353
|
-
* TWO SHAPES, because Word fills two different things. An UNBORDERED paragraph is filled
|
|
2354
|
-
* across its line boxes (indent-aware width), and before/after spacing stays unfilled. A
|
|
2355
|
-
* paragraph that publishes any {@link borders} stroke is filled across the rectangle those
|
|
2356
|
-
* strokes draw instead — `w:space` padding and rule extent included — so a callout's fill
|
|
2357
|
-
* reaches its frame rather than leaving a pale stripe floating inside an empty box. Paint
|
|
2358
|
-
* draws the strokes after the fill, so the frame is never covered.
|
|
2359
|
-
*/
|
|
2360
|
-
readonly shadingBox?: LayoutBox;
|
|
2361
|
-
/**
|
|
2362
|
-
* The revisions on this paragraph's own MARK (`w:pPr/w:rPr/w:ins|w:del`), absent when there
|
|
2363
|
-
* are none.
|
|
2364
|
-
*
|
|
2365
|
-
* Carried on the fragment rather than on a span because they decorate no characters: the
|
|
2366
|
-
* pilcrow was inserted or deleted, which is how a split or a merge is recorded. Only the
|
|
2367
|
-
* FINAL fragment carries them — the mark lives at the end of the paragraph, so a paragraph
|
|
2368
|
-
* split across pages must not draw two of them.
|
|
2369
|
-
*
|
|
2370
|
-
* A LIST because one mark can hold two decisions at once — an insertion by one author and
|
|
2371
|
-
* a deletion of that insertion by the next. Published only in `all-markup`: the other two
|
|
2372
|
-
* display modes answer what the document WOULD be, and a resolved view draws no
|
|
2373
|
-
* attribution.
|
|
2374
|
-
*
|
|
2375
|
-
* Those two modes are ATTRIBUTION-resolved, not STRUCTURE-resolved. Taking a deleted mark
|
|
2376
|
-
* in `proposed` merges the paragraph into the next one, and taking an inserted mark in
|
|
2377
|
-
* `original` un-splits it, but `revision-visibility.ts` does that only for a paragraph that
|
|
2378
|
-
* renders no text. So a resolved view still shows the break — it just no longer draws a
|
|
2379
|
-
* coloured pilcrow beside it. The merge is the fix for that; suppressing the glyph is not,
|
|
2380
|
-
* and must not be read as it.
|
|
2381
|
-
*/
|
|
2382
|
-
readonly markRevisions?: readonly RevisionAttribution[];
|
|
2383
|
-
/**
|
|
2384
|
-
* The one decision a single-field reader sees, absent when there are none.
|
|
2385
|
-
*
|
|
2386
|
-
* Derived from {@link markRevisions} at publish time, never authored beside it, so the two
|
|
2387
|
-
* cannot disagree: a deletion when the mark carries one, because that is where the pair
|
|
2388
|
-
* lands once every decision is taken, and it is the face paint draws for the same reason.
|
|
2389
|
-
*
|
|
2390
|
-
* @deprecated Shows one of the decisions a mark can carry. Read {@link markRevisions}.
|
|
2391
|
-
*/
|
|
2392
|
-
readonly markRevision?: RevisionAttribution;
|
|
2393
|
-
/**
|
|
2394
|
-
* The tracked FORMAT change on this paragraph's mark (`w:pPr/w:rPr/w:rPrChange`), absent
|
|
2395
|
-
* when there is none. Final fragment only, and `all-markup` only, like the decisions above.
|
|
2396
|
-
*
|
|
2397
|
-
* Published without a glyph of its own on purpose. Word draws no pilcrow for a mark whose
|
|
2398
|
-
* only change is its own formatting — the decision belongs to the review pane, which lists
|
|
2399
|
-
* it either way. What was missing was GEOMETRY: with nothing on the fragment, a card had
|
|
2400
|
-
* no place on the page to point at.
|
|
2401
|
-
*/
|
|
2402
|
-
readonly markFormatRevision?: RevisionAttribution;
|
|
2403
|
-
/**
|
|
2404
|
-
* List marker painted in the hanging-indent slot of the FIRST fragment only.
|
|
2405
|
-
*
|
|
2406
|
-
* Not part of model text: no UTF-16 range, never contributes to caret/selection offsets,
|
|
2407
|
-
* and must not be serialised back into the paragraph.
|
|
2408
|
-
*/
|
|
2409
|
-
readonly marker?: ListMarkerRecord;
|
|
2410
|
-
/**
|
|
2411
|
-
* The paragraph's resolved tab stops — cascade included — and the default interval past
|
|
2412
|
-
* the last of them.
|
|
2413
|
-
*
|
|
2414
|
-
* Published because it is not recoverable from `props`: `w:tabs` carries its meaning in
|
|
2415
|
-
* `w:tab` CHILDREN and the flat property projection has none, so a control reading the
|
|
2416
|
-
* cascade sees the element and not a single stop. A tab-stop editor that showed only what
|
|
2417
|
-
* the paragraph authors would hide a style's stops and then leave them in force.
|
|
2418
|
-
*/
|
|
2419
|
-
readonly tabStops: ResolvedTabStops;
|
|
2420
|
-
readonly lines: readonly LineRecord[];
|
|
2421
|
-
readonly box: LayoutBox;
|
|
2422
|
-
}
|
|
2423
|
-
/**
|
|
2424
|
-
* A numbering marker as layout published it.
|
|
2425
|
-
*
|
|
2426
|
-
* Geometry is in the same coordinate space as the fragment (page-content or cell-content
|
|
2427
|
-
* relative). Paint positions from this box and MUST NOT remeasure the marker.
|
|
2428
|
-
*/
|
|
2429
|
-
interface ListMarkerRecord {
|
|
2430
|
-
readonly text: string;
|
|
2431
|
-
readonly style: ResolvedRunStyle;
|
|
2432
|
-
readonly box: LayoutBox;
|
|
2433
|
-
/**
|
|
2434
|
-
* The `w:ilvl` this marker was resolved at, 0..8.
|
|
2435
|
-
*
|
|
2436
|
-
* Published because the level, not the geometry, is what Increase/Decrease Indent moves
|
|
2437
|
-
* on a list paragraph — demoting an item re-resolves its format from `numbering.xml`,
|
|
2438
|
-
* which is why a bullet becomes a hollow circle and a `1.` becomes an `a.`.
|
|
2439
|
-
*/
|
|
2440
|
-
readonly level: number;
|
|
2441
|
-
/**
|
|
2442
|
-
* The `w:numId` this marker resolved through.
|
|
2443
|
-
*
|
|
2444
|
-
* Published with the level because the two together are what identifies a list: whether
|
|
2445
|
-
* a demote is even possible depends on which levels THIS definition declares, and a
|
|
2446
|
-
* document may hold several lists whose level 0 looks identical.
|
|
2447
|
-
*/
|
|
2448
|
-
readonly numId: string;
|
|
2449
|
-
/** `w:numFmt` of the resolved level — `bullet` or a numbering format. */
|
|
2450
|
-
readonly numFmt: string;
|
|
2451
|
-
}
|
|
2452
|
-
/**
|
|
2453
|
-
* The part of one table that sits on one page.
|
|
2454
|
-
*
|
|
2455
|
-
* A table that crosses a page boundary produces one fragment per page it spans, which is
|
|
2456
|
-
* what lets it checkpoint like a paragraph: the flow loop places whole fragments, and
|
|
2457
|
-
* resuming after a table needs no knowledge of its interior.
|
|
2458
|
-
*/
|
|
2459
|
-
interface TableFragmentRecord {
|
|
2460
|
-
readonly kind: 'table';
|
|
2461
|
-
readonly id: string;
|
|
2462
|
-
/** Canonical node id of the `w:tbl`. */
|
|
2463
|
-
readonly tableId: string;
|
|
2464
|
-
/** 0 for the first page the table touches, 1 for its continuation, and so on. */
|
|
2465
|
-
readonly fragmentIndex: number;
|
|
2466
|
-
/** Nesting depth: 0 for body-level tables, increasing for nested tables. */
|
|
2467
|
-
readonly nestingDepth: number;
|
|
2468
|
-
/**
|
|
2469
|
-
* Resolved column boundary x positions in table-local points, left edge through right edge.
|
|
2470
|
-
* Length is column count + 1.
|
|
2471
|
-
*/
|
|
2472
|
-
readonly columnEdges: readonly number[];
|
|
2473
|
-
readonly rows: readonly TableRowFragmentRecord[];
|
|
2474
|
-
readonly box: LayoutBox;
|
|
2475
|
-
}
|
|
2476
|
-
/**
|
|
2477
|
-
* One table row on one page.
|
|
2478
|
-
*
|
|
2479
|
-
* A FRAGMENT, not the row: a row split across a page break appears once per page it touches, and
|
|
2480
|
-
* a repeated header row appears on every page of its table.
|
|
2481
|
-
*/
|
|
2482
|
-
interface TableRowFragmentRecord {
|
|
2483
|
-
/** Canonical node id of the `w:tr`. */
|
|
2484
|
-
readonly id: string;
|
|
2485
|
-
/** Pending tracked row insertion/deletion, when authored in `w:trPr`. */
|
|
2486
|
-
readonly revisionKind?: 'insert' | 'delete';
|
|
2487
|
-
/**
|
|
2488
|
-
* The `w:trPr/w:ins|w:del` attribution — the `(id, author, date)` triple the review model
|
|
2489
|
-
* addresses this decision by, so painted rows can carry it the way revision spans do.
|
|
2490
|
-
*/
|
|
2491
|
-
readonly revisionId?: string;
|
|
2492
|
-
readonly revisionAuthor?: string;
|
|
2493
|
-
readonly revisionDate?: string;
|
|
2494
|
-
/** Authored row ordinal within the table; repeats share the original row's index. */
|
|
2495
|
-
readonly rowIndex: number;
|
|
2496
|
-
/**
|
|
2497
|
-
* True for a `w:tblHeader` row RE-EMITTED at the top of a continuation page. Painted,
|
|
2498
|
-
* but excluded from interaction walks so each caret stop exists exactly once.
|
|
2499
|
-
*/
|
|
2500
|
-
readonly isHeaderRepeat: boolean;
|
|
2501
|
-
/**
|
|
2502
|
-
* True when this record continues a row that already emitted content on a prior page
|
|
2503
|
-
* (cell content fragmented at a paragraph/line boundary). Same `id` as the lead fragment.
|
|
2504
|
-
*/
|
|
2505
|
-
readonly isContinuation?: boolean;
|
|
2506
|
-
readonly cells: readonly TableCellFragmentRecord[];
|
|
2507
|
-
readonly box: LayoutBox;
|
|
2508
|
-
}
|
|
2509
|
-
/**
|
|
2510
|
-
* One table cell on one page, already resolved against the grid.
|
|
2511
|
-
*
|
|
2512
|
-
* `gridSpan` is clamped at read time, because it comes from a file and an unclamped span is a
|
|
2513
|
-
* loop bound an attacker controls. A vertical-merge continuation paints its box but holds no
|
|
2514
|
-
* blocks — its content belongs to the cell that started the merge.
|
|
2515
|
-
*/
|
|
2516
|
-
interface TableCellFragmentRecord {
|
|
2517
|
-
/** Canonical node id of the `w:tc`. */
|
|
2518
|
-
readonly id: string;
|
|
2519
|
-
/** First grid column this cell occupies. */
|
|
2520
|
-
readonly gridColumn: number;
|
|
2521
|
-
/** Canonical `w:gridCol` node id for this cell's start column, when authored. */
|
|
2522
|
-
readonly gridColumnId?: string;
|
|
2523
|
-
/** Grid columns spanned, already clamped at read time. */
|
|
2524
|
-
readonly gridSpan: number;
|
|
2525
|
-
/** A vertical-merge continuation paints its box but holds no blocks. */
|
|
2526
|
-
readonly vMergeContinue: boolean;
|
|
2527
|
-
/**
|
|
2528
|
-
* When true, paint skips borders/fill/content for this cell (vMerge continue). Grid
|
|
2529
|
-
* bookkeeping and the box remain so selection/geometry walks stay consistent.
|
|
2530
|
-
*/
|
|
2531
|
-
readonly paintInert?: boolean;
|
|
2532
|
-
/** Number of rows this restart cell visually spans (1 when not a vertical merge). */
|
|
2533
|
-
readonly rowSpan?: number;
|
|
2534
|
-
/** Validated 6-hex cell shading fill, absent for none/auto. */
|
|
2535
|
-
readonly shading?: string;
|
|
2536
|
-
/**
|
|
2537
|
-
* Layout-owned resolved borders after collapsed conflict resolution.
|
|
2538
|
-
*
|
|
2539
|
-
* Includes convenience per-side edges, per-grid-interval winners, and explicit compound
|
|
2540
|
-
* stroke rectangles in cell-local points. Paint only scales and draws — it must not
|
|
2541
|
-
* invent stroke/gap/corner geometry.
|
|
2542
|
-
*/
|
|
2543
|
-
readonly borders?: ResolvedCellBorders;
|
|
2544
|
-
/** Nested blocks in reading order; recursion carries nested tables. */
|
|
2545
|
-
readonly blocks: readonly BlockFragmentRecord[];
|
|
2546
|
-
readonly box: LayoutBox;
|
|
2547
|
-
}
|
|
2548
|
-
/** A top-level (or cell-level) block fragment, discriminated by `kind`. */
|
|
2549
|
-
type BlockFragmentRecord = ParagraphFragmentRecord | TableFragmentRecord;
|
|
2550
|
-
/**
|
|
2551
|
-
* One header or footer story as it sits on one page.
|
|
2552
|
-
*
|
|
2553
|
-
* `box` is absolute (sheet coordinates) and sized to the story's FLOW height — never to
|
|
2554
|
-
* any anchored-object extent, which is the rule that keeps a decorated header's hit area
|
|
2555
|
-
* from covering the body. `fragments` are story-relative (origin at the box's top-left).
|
|
2556
|
-
* Baseline furniture may be shared across pages of the same variant when the story has no
|
|
2557
|
-
* allowlisted PAGE/NUMPAGES/SECTIONPAGES fields; after page-field finalize, projections are
|
|
2558
|
-
* per page (or per distinct field values for count-only stories).
|
|
2559
|
-
*/
|
|
2560
|
-
interface HeaderFooterStoryRecord {
|
|
2561
|
-
readonly kind: 'header' | 'footer';
|
|
2562
|
-
readonly variant: 'default' | 'first' | 'even';
|
|
2563
|
-
readonly partName: string;
|
|
2564
|
-
/**
|
|
2565
|
-
* The part this story was laid out from. See {@link HeaderFooterStoryLayout.part}.
|
|
2566
|
-
*
|
|
2567
|
-
* Present when the furniture source supplied it. A pass that needs the story's TREE — the
|
|
2568
|
-
* content-control boundary derivation is the one — reads it here rather than resolving a
|
|
2569
|
-
* name against a package it does not have.
|
|
2570
|
-
*/
|
|
2571
|
-
readonly part?: OoxmlPart;
|
|
2572
|
-
/**
|
|
2573
|
-
* Main-document relationship id that resolves to this part (`EditorScope.rId`).
|
|
2574
|
-
*
|
|
2575
|
-
* Present when the furniture source could name the relationship; scoped editing binds
|
|
2576
|
-
* on this id so shared parts stay one story across pages/sections.
|
|
2577
|
-
*/
|
|
2578
|
-
readonly rId?: string;
|
|
2579
|
-
readonly box: LayoutBox;
|
|
2580
|
-
readonly fragments: readonly BlockFragmentRecord[];
|
|
2581
|
-
/** Anchored drawings owned by this story, in story-relative coordinates. */
|
|
2582
|
-
readonly anchoredDrawings?: readonly AnchoredDrawingRecord[];
|
|
2583
|
-
/**
|
|
2584
|
-
* Transient projector used between furniture attach and document-level page-field
|
|
2585
|
-
* finalize. Absent on published layout records after finalize — but not dead: finalize
|
|
2586
|
-
* retains it (with the context it last ran under) in a side table keyed on the published
|
|
2587
|
-
* record (`strippedStoryProjections` in `field-page-furniture.ts`), so a reused sheet can
|
|
2588
|
-
* re-project when the page count moves (#441). The retained closure keeps its minting
|
|
2589
|
-
* pass's scope alive for as long as the sheet is reused, and anything that clones a
|
|
2590
|
-
* published field-bearing story must carry the entry onto the clone
|
|
2591
|
-
* (`carryStrippedPageFieldProjection`).
|
|
2592
|
-
*/
|
|
2593
|
-
readonly pageFieldProjector?: (context: {
|
|
2594
|
-
readonly pageNumber: number;
|
|
2595
|
-
readonly pageCount: number;
|
|
2596
|
-
readonly sectionPageCount?: number;
|
|
2597
|
-
readonly format?: string;
|
|
2598
|
-
}) => HeaderFooterStoryRecord;
|
|
2599
|
-
}
|
|
2600
|
-
/**
|
|
2601
|
-
* One footnote or endnote story as it sits on one page (or continuation page).
|
|
2602
|
-
*
|
|
2603
|
-
* Notes are ordinary editable stories — NOT `[data-docx-hf]` furniture. `box` is absolute
|
|
2604
|
-
* (sheet coordinates). `fragments` are story-relative. Separators are nonselectable paint
|
|
2605
|
-
* geometry owned by the parent {@link NoteAreaRecord}.
|
|
2606
|
-
*/
|
|
2607
|
-
interface NoteStoryRecord {
|
|
2608
|
-
readonly noteKind: 'footnote' | 'endnote';
|
|
2609
|
-
readonly noteId: number;
|
|
2610
|
-
/** `footnote:N` / `endnote:N` — EditorScope note id. */
|
|
2611
|
-
readonly scopeId: string;
|
|
2612
|
-
/** Derived display mark for this occurrence; null when customMarkFollows / continuation. */
|
|
2613
|
-
readonly mark: string | null;
|
|
2614
|
-
/** True when this is a continuation fragment (no leading mark). */
|
|
2615
|
-
readonly continuation?: boolean;
|
|
2616
|
-
readonly box: LayoutBox;
|
|
2617
|
-
readonly fragments: readonly BlockFragmentRecord[];
|
|
2618
|
-
}
|
|
2619
|
-
/**
|
|
2620
|
-
* Footnote / endnote area on one page: separator + stacked note stories.
|
|
2621
|
-
*
|
|
2622
|
-
* `placement` records how the area was positioned. `fallbackReason` is set when the
|
|
2623
|
-
* bounded reflow loop exhausted and layout kept the reference with its note on a later
|
|
2624
|
-
* page (D12 named fallback).
|
|
2625
|
-
*/
|
|
2626
|
-
interface NoteAreaRecord {
|
|
2627
|
-
readonly kind: 'footnotes' | 'endnotes';
|
|
2628
|
-
readonly placement: 'pageBottom' | 'beneathText' | 'sectEnd' | 'docEnd';
|
|
2629
|
-
readonly box: LayoutBox;
|
|
2630
|
-
/** Separator rule / authored separator story; absent when no notes on this page. */
|
|
2631
|
-
readonly separator?: {
|
|
2632
|
-
readonly kind: 'separator' | 'continuationSeparator';
|
|
2633
|
-
readonly box: LayoutBox;
|
|
2634
|
-
readonly fragments: readonly BlockFragmentRecord[];
|
|
2635
|
-
readonly synthetic: boolean;
|
|
2636
|
-
/** Layout-owned single/double rule when marker-only or synthetic; absent for authored stories. */
|
|
2637
|
-
readonly ruleStyle?: 'single' | 'double';
|
|
2638
|
-
};
|
|
2639
|
-
readonly notes: readonly NoteStoryRecord[];
|
|
2640
|
-
readonly fallbackReason?: string;
|
|
2641
|
-
}
|
|
2642
|
-
/**
|
|
2643
|
-
* Note-stream ownership for overflow sheets created by note pagination.
|
|
2644
|
-
*
|
|
2645
|
-
* - `footnote-drain`: continuation pages that exist only to finish pageBottom footnotes —
|
|
2646
|
-
* not free body hosts for sectEnd/docEnd endnotes.
|
|
2647
|
-
* - `endnote-overflow`: sheets inserted to finish sectEnd/docEnd collections.
|
|
2648
|
-
*/
|
|
2649
|
-
type PageNoteStream = 'footnote-drain' | 'endnote-overflow';
|
|
2650
|
-
/**
|
|
2651
|
-
* Raw `w:lock/@w:val` on one control, or `unlocked` when absent / unrecognised.
|
|
2652
|
-
*
|
|
2653
|
-
* Effective permissions across a nesting chain are the union of every ancestor's lock on two
|
|
2654
|
-
* axes (content edit / removal); see {@link ContentControlBoundaryRecord.effectiveLock}.
|
|
2655
|
-
*/
|
|
2656
|
-
type ContentControlLock = 'unlocked' | 'sdtLocked' | 'contentLocked' | 'sdtContentLocked';
|
|
2657
|
-
/**
|
|
2658
|
-
* Mapped control type for layout / chrome — same members as the shipped public
|
|
2659
|
-
* `ContentControlType`. Untyped and preserved-only kinds report as `richText`.
|
|
2660
|
-
*/
|
|
2661
|
-
type ContentControlMappedType = 'richText' | 'plainText' | 'checkbox' | 'dropdown' | 'comboBox' | 'date' | 'picture' | 'repeatingSection';
|
|
2662
|
-
/** Where the control sits in the tree relative to its content. */
|
|
2663
|
-
type ContentControlLevel = 'block' | 'inline' | 'row' | 'cell';
|
|
2664
|
-
/**
|
|
2665
|
-
* One piece of a control's content geometry.
|
|
2666
|
-
*
|
|
2667
|
-
* A block control that crosses a page break publishes one fragment per page rather than a
|
|
2668
|
-
* single rectangle covering the inter-page gap. An inline control publishes one fragment per
|
|
2669
|
-
* LINE it touches, covering the text's vertical extent (line-spacing leading excluded), so a
|
|
2670
|
-
* wrapped control never claims the words beside it. Coordinates match fragment boxes
|
|
2671
|
-
* (page-content space).
|
|
2672
|
-
*/
|
|
2673
|
-
interface ContentControlGeometryFragment {
|
|
2674
|
-
readonly pageIndex: number;
|
|
2675
|
-
readonly box: LayoutBox;
|
|
2676
|
-
}
|
|
2677
|
-
/**
|
|
2678
|
-
* Layout-published boundary for one content control (`w:sdt` / typed `contentControl`).
|
|
2679
|
-
*
|
|
2680
|
-
* Chrome, lock feedback, and hit resolution read this record — never painted DOM. The wrapper
|
|
2681
|
-
* itself is not a layout box; `fragments` cover the content that already flowed in place.
|
|
2682
|
-
*/
|
|
2683
|
-
interface ContentControlBoundaryRecord {
|
|
2684
|
-
/** Canonical node id of the control wrapper — not `w:id`. */
|
|
2685
|
-
readonly id: string;
|
|
2686
|
-
readonly alias?: string;
|
|
2687
|
-
readonly tag?: string;
|
|
2688
|
-
readonly controlType: ContentControlMappedType;
|
|
2689
|
-
/** This control's own `w:lock`, before ancestor union. */
|
|
2690
|
-
readonly lock: ContentControlLock;
|
|
2691
|
-
/**
|
|
2692
|
-
* Nested lock union with every ancestor control, collapsed back to a single `ST_Lock`
|
|
2693
|
-
* vocabulary value (both axes locked → `sdtContentLocked`).
|
|
2694
|
-
*/
|
|
2695
|
-
readonly effectiveLock: ContentControlLock;
|
|
2696
|
-
/** `w:showingPlcHdr` is present on the control's properties. */
|
|
2697
|
-
readonly placeholder: boolean;
|
|
2698
|
-
/** `w:dataBinding` is present — content edits are refused as bound. */
|
|
2699
|
-
readonly bound: boolean;
|
|
2700
|
-
/** 0 for a top-level control; increments through nested wrappers under the shared nesting bound. */
|
|
2701
|
-
readonly nestingDepth: number;
|
|
2702
|
-
readonly level: ContentControlLevel;
|
|
2703
|
-
readonly fragments: readonly ContentControlGeometryFragment[];
|
|
2704
|
-
}
|
|
2705
|
-
/**
|
|
2706
|
-
* One laid-out page: the sheet, the content area, and everything that landed on it.
|
|
2707
|
-
*
|
|
2708
|
-
* Page identity is REUSED across incremental passes — a pass that changes nothing returns the
|
|
2709
|
-
* previous records by reference, which is what lets paint skip untouched pages entirely.
|
|
2710
|
-
*/
|
|
2711
|
-
interface PageRecord {
|
|
2712
|
-
readonly id: string;
|
|
2713
|
-
readonly index: number;
|
|
2714
|
-
/** The whole sheet. */
|
|
2715
|
-
readonly box: LayoutBox;
|
|
2716
|
-
/** The area inside the margins that content flows into. */
|
|
2717
|
-
readonly contentBox: LayoutBox;
|
|
2718
|
-
readonly fragments: readonly BlockFragmentRecord[];
|
|
2719
|
-
/** Layout-owned vertical rules requested by `w:cols/@w:sep`, content-box relative. */
|
|
2720
|
-
readonly columnSeparators?: readonly LayoutBox[];
|
|
2721
|
-
/** Page-content anchored drawings on this sheet, absent when there are none. */
|
|
2722
|
-
readonly anchoredDrawings?: readonly AnchoredDrawingRecord[];
|
|
2723
|
-
/** Page furniture for this page's variant, absent when the document declares none. */
|
|
2724
|
-
readonly header?: HeaderFooterStoryRecord;
|
|
2725
|
-
readonly footer?: HeaderFooterStoryRecord;
|
|
2726
|
-
/** Footnotes reserved on this page (pageBottom / beneathText / continuations). */
|
|
2727
|
-
readonly footnotes?: NoteAreaRecord;
|
|
2728
|
-
/** Endnotes collected on this page (sectEnd / docEnd). */
|
|
2729
|
-
readonly endnotes?: NoteAreaRecord;
|
|
2730
|
-
/**
|
|
2731
|
-
* Ownership of note-only overflow sheets. Absent on ordinary body pages.
|
|
2732
|
-
* Layout pagination sets this so endnote hosting does not treat footnote drain
|
|
2733
|
-
* pages as free body space.
|
|
2734
|
-
*/
|
|
2735
|
-
readonly noteStream?: PageNoteStream;
|
|
2736
|
-
/**
|
|
2737
|
-
* Section-local PAGE/SECTIONPAGES inputs for finalize. Absent → physical page index and
|
|
2738
|
-
* document-wide section count (empty `w:pgNumType` behaviour).
|
|
2739
|
-
*/
|
|
2740
|
-
readonly pageFieldSource?: {
|
|
2741
|
-
readonly pageNumber: number;
|
|
2742
|
-
readonly sectionPageCount: number;
|
|
2743
|
-
readonly format?: string;
|
|
2744
|
-
};
|
|
2745
|
-
/**
|
|
2746
|
-
* `true` when this page's body flow (or a body table) carries a PAGE/NUMPAGES/SECTIONPAGES
|
|
2747
|
-
* placeholder that document finalize must substitute. Set when the page is assembled, so it
|
|
2748
|
-
* rides the record through incremental reuse. `false` lets `finalizePageFieldProjection` skip
|
|
2749
|
-
* the substitution walk; `undefined` (a page built by a path that does not stamp it) still
|
|
2750
|
-
* walks, which is safe.
|
|
2751
|
-
*/
|
|
2752
|
-
readonly hasBodyPageFields?: boolean;
|
|
2753
|
-
/**
|
|
2754
|
-
* Content-control boundaries whose geometry intersects this page.
|
|
2755
|
-
*
|
|
2756
|
-
* Carried on the page so a consumer that only holds a page record still sees current
|
|
2757
|
-
* metadata; identity reuse of an unchanged page keeps the same array only when the
|
|
2758
|
-
* control-context token matches.
|
|
2759
|
-
*/
|
|
2760
|
-
readonly contentControls?: readonly ContentControlBoundaryRecord[];
|
|
2761
|
-
}
|
|
2762
|
-
/**
|
|
2763
|
-
* A complete layout pass: every page, plus the document-wide indexes derived alongside them.
|
|
2764
|
-
*
|
|
2765
|
-
* Stamped with the store `revision` it was laid out from, so anything holding geometry can tell
|
|
2766
|
-
* whether the document has moved underneath it — which is how stale pointer gestures and
|
|
2767
|
-
* overlays are refused rather than applied to coordinates that no longer describe anything.
|
|
2768
|
-
*/
|
|
2769
|
-
interface SemanticLayout {
|
|
2770
|
-
/** The store revision these records were laid out from. */
|
|
2771
|
-
readonly revision: number;
|
|
2772
|
-
readonly pages: readonly PageRecord[];
|
|
2773
|
-
/**
|
|
2774
|
-
* Every content-control boundary in document order, including multi-page fragment lists.
|
|
2775
|
-
*
|
|
2776
|
-
* Always recomputed when a document layout pass finishes, so incremental page-identity
|
|
2777
|
-
* reuse cannot publish stale alias/tag/lock metadata.
|
|
2778
|
-
*/
|
|
2779
|
-
readonly contentControls?: readonly ContentControlBoundaryRecord[];
|
|
2780
|
-
/**
|
|
2781
|
-
* Fingerprint of wrapper-only control metadata (alias, tag, lock, type, placeholder, binding).
|
|
2782
|
-
*
|
|
2783
|
-
* Folded into the layout producer / session context so a metadata-only edit invalidates
|
|
2784
|
-
* reuse paths that would otherwise return previous pages by identity with stale boundaries.
|
|
2785
|
-
*/
|
|
2786
|
-
readonly controlContextToken?: string;
|
|
2787
|
-
}
|
|
2788
|
-
/** Page geometry, in points. */
|
|
2789
|
-
interface PageGeometry {
|
|
2790
|
-
readonly width: number;
|
|
2791
|
-
readonly height: number;
|
|
2792
|
-
readonly margin: {
|
|
2793
|
-
readonly top: number;
|
|
2794
|
-
readonly right: number;
|
|
2795
|
-
readonly bottom: number;
|
|
2796
|
-
readonly left: number;
|
|
2797
|
-
};
|
|
2798
|
-
/** `w:pgMar/@header` — sheet edge to header top, in points. Defaults to 36 (720 twips). */
|
|
2799
|
-
readonly headerDistance?: number;
|
|
2800
|
-
/** `w:pgMar/@footer` — sheet edge to footer bottom, in points. Defaults to 36. */
|
|
2801
|
-
readonly footerDistance?: number;
|
|
2802
|
-
}
|
|
2803
|
-
/** US Letter with one-inch margins, in points. */
|
|
2804
|
-
declare const DEFAULT_PAGE_GEOMETRY: PageGeometry;
|
|
2805
|
-
/**
|
|
2806
|
-
* Text measurement, injected.
|
|
2807
|
-
*
|
|
2808
|
-
* A real implementation shapes with the resolved font; the tests supply a deterministic one.
|
|
2809
|
-
* Layout never reads the DOM, so this is the only way width and height enter it.
|
|
2810
|
-
*/
|
|
2811
|
-
interface TextMeasurer {
|
|
2812
|
-
/** Advance width of `text` in the resolved style. */
|
|
2813
|
-
measure(text: string, style: ResolvedRunStyle): number;
|
|
2814
|
-
/** Line height and baseline for the resolved style. */
|
|
2815
|
-
lineMetrics(style: ResolvedRunStyle): {
|
|
2816
|
-
height: number;
|
|
2817
|
-
baseline: number;
|
|
2818
|
-
};
|
|
2819
|
-
}
|
|
2820
|
-
|
|
2821
|
-
export { type DeclaredFontSubstitution as $, type AnchoredDrawingRecord as A, type BlockFragmentRecord as B, type ContentControlBoundaryRecord as C, type DrawingPoint as D, AUTO_PARAGRAPH_SPACING_PT as E, type FontResourceSnapshot as F, type AbstractNumDefinition as G, type HyperlinkProjector as H, type InlineDrawingRecord as I, type BidiEmbeddingLevels as J, type BorderGridGeometry as K, type LineRecord as L, type ModelRange as M, type NormalizationPolicy as N, type CascadedParagraphFormatting as O, type PageGeometry as P, type ContentControlGeometryFragment as Q, type ResolvedRunStyle as R, type SemanticLayout as S, type TextMeasurer as T, type ContentControlLevel as U, type VersionedShapingLibrary as V, type ContentControlMappedType as W, DEFAULT_PAGE_GEOMETRY as X, DEFAULT_RUN_STYLE as Y, DEFAULT_TAB_INTERVAL_PT as Z, DEFAULT_TAB_INTERVAL_TWIPS as _, type StyleSpanRecord as a, type ResolvedUnderline as a$, EMPTY_NUMBERING_INDEX as a0, EMPTY_TAB_STOPS as a1, type EquationFractionGeometry as a2, type EquationGeometry as a3, type EquationNaryGeometry as a4, type EquationRadicalGeometry as a5, type EquationRowGeometry as a6, type EquationScriptGeometry as a7, type EquationSpanRecord as a8, type EquationTextGeometry as a9, MAX_PARAGRAPH_SPACING_PT as aA, MAX_STYLE_BASED_ON_DEPTH as aB, MAX_STYLE_DEFINITIONS as aC, MAX_TABLE_BORDER_STROKES as aD, MAX_TAB_POSITION_TWIPS as aE, MAX_TAB_STOPS as aF, type NumDefinition as aG, type NumberingLevelIndent as aH, PARAGRAPH_BORDER_SIDES as aI, type PageRefCalibrationCell as aJ, type PageRefFieldProjection as aK, type ParagraphAutoSpacingContext as aL, type ParagraphBorderEdge as aM, type ParagraphBorderSide as aN, type ParagraphBorderStrokeRecord as aO, type ParagraphBorders as aP, type ParagraphBottomBorderRecord as aQ, type ParagraphIndent as aR, type ParagraphLayoutInputs as aS, type ParagraphLineSpacing as aT, type ParagraphSpacing as aU, type RefFieldSpec as aV, type RefNoteParts as aW, type ResolvedCellBorders as aX, type ResolvedTabStops as aY, type ResolvedTableBorderEdge as aZ, type ResolvedTableBorderEdgeSegment as a_, type FieldAtomMarker as aa, type FontFingerprintInputs as ab, type FontRequest as ac, FontResolutionError as ad, type FontResolutionErrorCode as ae, type FontResourceDefinition as af, type FontResourceInstrumentation as ag, type FontResourceSnapshotOptions as ah, type FontSlot as ai, type FontSubstitution as aj, type FontValidationResult as ak, type GlyphOutline as al, HARD_MAX_AGGREGATE_FONT_BYTES as am, HARD_MAX_FONT_BYTES as an, HARD_MAX_FONT_SOURCES as ao, type HeaderFooterStoryRecord as ap, type HyperlinkFieldSpec as aq, type LevelOverride as ar, type LineSpacingRule as as, type ListMarkerAlign as at, type ListMarkerRecord as au, type ListSuffix as av, MAX_BORDER_SPACE_PT as aw, MAX_BORDER_WIDTH_PT as ax, MAX_LVL_OVERRIDES as ay, MAX_NUMBERING_DEFINITIONS as az, type TextShaper as b, parseRefInstruction as b$, SINGLE_LINE_SPACING as b0, type ScriptItem as b1, type ShapeInput as b2, type ShapedCluster as b3, type ShapedFontSpan as b4, type ShapedGlyph as b5, type ShapedRunComparatorInputs as b6, type ShapedVerticalMetrics as b7, type ShapingEnvironment as b8, type ShapingEnvironmentFingerprintInputs as b9, cascadedBottomBorder as bA, cascadedParagraphBorders as bB, cascadedTabStops as bC, collapsedSpaceBefore as bD, createFontResourceSnapshot as bE, createShapedRun as bF, createShapingEnvironment as bG, defaultTabIntervalFromSettings as bH, displayText as bI, fixedPoint as bJ, fontRequestKey as bK, isValidStyleId as bL, itemizeScriptFontSlots as bM, layoutEquation as bN, listMarkerBox as bO, measureDisplayText as bP, mergeListIndent as bQ, nextTabDestination as bR, paragraphBorderExtentPt as bS, paragraphBorderStrokeWidthPt as bT, paragraphBorders as bU, paragraphBordersFingerprint as bV, paragraphBreaksBefore as bW, paragraphContextualSpacing as bX, paragraphLineSpacing as bY, paragraphSpacing as bZ, paragraphTabStops as b_, type ShapingEnvironmentInput as ba, type SourceRange as bb, type SpanLinkRecord as bc, type StyleDefinition as bd, TAB_LEADER_GLYPH as be, type TabAlignment as bf, type TabDestination as bg, type TabLeader as bh, type TabStop as bi, type TableBorderSideName as bj, type TableBorderStrokeRecord as bk, type TableFragmentRecord as bl, type TextDirection as bm, UnsupportedScriptError as bn, type VerticalAlign as bo, appliedSpaceBefore as bp, applyLineSpacing as bq, baselineShiftPtOf as br, borderExtentPt as bs, borderWeight as bt, bottomBorderExtentPt as bu, boundedStructuralFontValidator as bv, buildNumberingIndex as bw, buildStyleCascadeTable as bx, cascadeParagraphFormatting as by, cascadeRunProperties as bz, type FixedPointRoundingMode as c, readBorderSide as c0, readCellBorders as c1, readNumPr as c2, readTableBorders as c3, resolveBorderConflict as c4, resolveNumberingLevel as c5, resolveParagraphLayoutInputs as c6, resolveRunStyle as c7, resolveStoryListItems as c8, resolveStoryRefFields as c9, resolveTableCellBorderGrid as ca, runStylesEqual as cb, shapedRunComparatorInputs as cc, shapingEnvironmentFingerprint as cd, shapingEnvironmentFingerprintInputs as ce, styleForFontSlot as cf, tabAdvanceWidth as cg, tabStopsFingerprint as ch, walkStoryParagraphs as ci, withDefaultTabInterval as cj, withNumberingStyleLinks as ck, withResolvedListItems as cl, type ResolvedFont as d, type TableRowFragmentRecord as e, type TableCellFragmentRecord as f, type NumberingLevel as g, type NumberingIndex as h, type LayoutBox as i, type DrawingInsets as j, type PageRecord as k, type TableBorderSide as l, type ContentControlLock as m, type ParagraphFragmentRecord as n, type FontByteValidator as o, type FixedPoint as p, type ShapedRun as q, type InlineDrawingLayoutContext as r, type StyleCascadeTable as s, type FieldLinkProjector as t, type RefFieldContext as u, type StoryPageFieldNeeds as v, type ResolvedListItem as w, type CellBorderBox as x, type TableCellStyleFormatting as y, type TableBorderBox as z };
|