@docx-editor.dev/core 2.22.0 → 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/automation.cjs +1 -1
- package/dist/automation.d.ts +13 -12
- package/dist/automation.js +1 -1
- package/dist/binding.cjs +1 -1
- package/dist/binding.d.ts +11 -10
- package/dist/binding.js +1 -1
- package/dist/chunk-4OAXZNBU.js +5 -0
- package/dist/chunk-6745I4XF.cjs +20 -0
- package/dist/chunk-6KA3L3FR.cjs +11 -0
- package/dist/chunk-6QS5WL63.js +1 -0
- package/dist/{chunk-X2LJDR53.cjs → chunk-BUDXZ7T2.cjs} +5 -5
- package/dist/chunk-DYRXA5UJ.cjs +2 -0
- package/dist/chunk-DZOGUV7O.js +1 -0
- package/dist/chunk-EHT4LKKZ.cjs +1 -0
- package/dist/chunk-F5LAOPAD.js +20 -0
- package/dist/chunk-FWX535CS.cjs +1 -0
- package/dist/chunk-GRVRQBKU.js +1 -0
- package/dist/chunk-JN62FLHE.cjs +4 -0
- package/dist/{chunk-5RKCJ5DF.js → chunk-KRBBWATQ.js} +1 -1
- package/dist/chunk-KV5HFE23.cjs +2 -0
- package/dist/{chunk-RLKX7BIP.cjs → chunk-PCPBDYEL.cjs} +1 -1
- package/dist/chunk-Q4RDWB3U.cjs +18 -0
- package/dist/{chunk-P5PWSRNW.cjs → chunk-QK23BSRK.cjs} +1 -1
- package/dist/chunk-QTFAXWVI.cjs +1 -0
- package/dist/chunk-RLO64PHP.cjs +1 -0
- package/dist/chunk-T7RGKBCE.cjs +5 -0
- package/dist/{chunk-IWAUA732.js → chunk-UMBHUW6R.js} +1 -1
- package/dist/chunk-VE6H5EJA.js +5 -0
- package/dist/chunk-WHG23WNI.js +1 -0
- package/dist/chunk-XBYZTDF7.js +4 -0
- package/dist/chunk-XRBPZCNK.js +11 -0
- package/dist/chunk-Y5JCIWTF.js +2 -0
- package/dist/chunk-ZA6HEWUM.js +2 -0
- package/dist/chunk-ZCRSPN4Q.js +18 -0
- package/dist/collaboration/replication.cjs +1 -1
- package/dist/collaboration/replication.d.ts +6 -5
- package/dist/collaboration/replication.js +1 -1
- package/dist/collaboration.d.ts +7 -6
- package/dist/contracts/document.d.ts +4 -3
- package/dist/contracts/editor.d.ts +9 -9
- package/dist/contracts/interaction.d.ts +2 -1
- package/dist/contracts/modules.d.ts +9 -8
- package/dist/contracts/types.d.ts +1 -1
- package/dist/{custom-node-writes-Ck6eOiJ3.d.ts → custom-node-writes-77rvPW2-.d.ts} +4 -3
- package/dist/{document-protection-CMPEonQc.d.ts → document-protection-CYIjO-li.d.ts} +3 -2
- package/dist/{editor-BKDVqXyk.d.ts → editor-DhUQsWWH.d.ts} +132 -26
- package/dist/editor.cjs +1 -1
- package/dist/editor.css +1 -1
- package/dist/editor.d.ts +57 -66
- package/dist/editor.js +1 -1
- package/dist/export.cjs +2 -2
- package/dist/export.d.ts +17 -16
- package/dist/export.js +2 -2
- package/dist/{failure-DNNmwsgD.d.ts → failure-BIPVQbRm.d.ts} +2 -1
- package/dist/{font-resolver-PBc8Vuxs.d.ts → font-resolver-BwoHFBlr.d.ts} +3 -2
- package/dist/{headless-document-view-9wjJT20Y.d.ts → headless-document-view-Cc3fFWhv.d.ts} +4 -3
- package/dist/{image-resources-B0v-XaTM.d.ts → image-resources-DkuzBnTM.d.ts} +3 -2
- package/dist/{index-DQA53aR1.d.ts → index-BYaCkGKO.d.ts} +61 -26
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +18 -18
- package/dist/index.js +1 -1
- package/dist/{layout-shaping-Dyr0ZSOI.d.ts → layout-shaping-DpWQG26a.d.ts} +3 -2
- package/dist/layout.cjs +1 -1
- package/dist/layout.d.ts +116 -50
- package/dist/layout.js +1 -1
- package/dist/{note-properties-D_lmG9xx.d.ts → note-properties-DMfKK3QU.d.ts} +3 -2
- package/dist/{omml-equation-CfTm3jOK.d.ts → omml-equation-BY7OdfGY.d.ts} +3 -2
- package/dist/output.cjs +1 -1
- package/dist/output.d.ts +9 -8
- package/dist/output.js +1 -1
- package/dist/{protocol-CkVDxyQ3.d.ts → protocol-CPAakntQ.d.ts} +4 -3
- package/dist/{review-paragraph-order-BjUs-tDd.d.ts → review-paragraph-order-B0BP_wJP.d.ts} +1 -1
- package/dist/{revision-projection-DDVBYTIG.d.ts → revision-projection-CVJeA2jp.d.ts} +3 -2
- package/dist/{semantic-cell-selection-DW6qsmoC.d.ts → semantic-cell-selection-B8GF_H2e.d.ts} +10 -6
- package/dist/{semantic-interaction-BNiYSBcB.d.ts → semantic-interaction-DQjtIruQ.d.ts} +3 -2
- package/dist/{semantic-paint-DE236npp.d.ts → semantic-paint-DoPl85nR.d.ts} +4 -3
- package/dist/{semantic-records-C5OeXnaL.d.ts → semantic-records-DB0VgWsr.d.ts} +888 -778
- package/dist/store.cjs +1 -1
- package/dist/store.d.ts +17 -16
- package/dist/store.js +1 -1
- package/dist/{tree-package-fragment-DBb97w3F.d.ts → tree-package-fragment-BIyGh6L8.d.ts} +4 -3
- package/dist/{tree-session-contract-BYat3RKx.d.ts → tree-session-contract-CHcCnz3W.d.ts} +7 -6
- package/dist/{types-barrel-ChGvWjkO.d.ts → types-barrel-DN_-gaRX.d.ts} +70 -5
- package/package.json +3 -3
- package/dist/chunk-65GJRSZ5.cjs +0 -18
- package/dist/chunk-6TBRG6SA.cjs +0 -20
- package/dist/chunk-A72MJGY7.cjs +0 -4
- package/dist/chunk-AZ7QSAXH.js +0 -4
- package/dist/chunk-BL57VQ7E.js +0 -1
- package/dist/chunk-CB6RQ3GD.cjs +0 -11
- package/dist/chunk-FGBADUSK.cjs +0 -1
- package/dist/chunk-GG4IAKFI.js +0 -5
- package/dist/chunk-HJYLFMLX.js +0 -2
- package/dist/chunk-HL6NO7IH.cjs +0 -2
- package/dist/chunk-HZQFGB2X.cjs +0 -5
- package/dist/chunk-OZXBAEWW.js +0 -2
- package/dist/chunk-PD5XKBJA.js +0 -1
- package/dist/chunk-REMFTPDL.cjs +0 -2
- package/dist/chunk-UGLO2GA5.cjs +0 -1
- package/dist/chunk-UOQONZVQ.js +0 -11
- package/dist/chunk-VD2MWTR6.js +0 -20
- package/dist/chunk-VIXH2OVP.js +0 -1
- package/dist/chunk-VP7SDFCM.js +0 -1
- package/dist/chunk-W2JIZ5JH.js +0 -18
- package/dist/chunk-W5H62AWM.cjs +0 -1
- package/dist/chunk-YQXY6TQ3.js +0 -5
- package/dist/chunk-YYFBYVW4.cjs +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { c as RevisionAttribution, a as RevisionDisplayMode } from './revision-projection-
|
|
2
|
-
import { a0 as OoxmlProperty, a1 as OoxmlElement,
|
|
3
|
-
import { b as ImageResourceState } from './image-resources-
|
|
4
|
-
import { O as OmmlEquationProjection } from './omml-equation-
|
|
1
|
+
import { c as RevisionAttribution, a as RevisionDisplayMode } from './revision-projection-CVJeA2jp.js';
|
|
2
|
+
import { a0 as OoxmlProperty, a1 as OoxmlElement, N as OoxmlNode, O as OoxmlPart, aG as TableBorderStyle, aH as DrawingAccessibility, aI as DrawingImageEffects, a8 as SourceCrop, aJ as DrawingTransform, aK as VectorShapeProjection, aj as DrawingHorizontalReferenceFrame, ak as DrawingVerticalReferenceFrame, aa as ImageWrapTarget, a4 as DrawingProjection, aL as OoxmlDrawingNode } from './types-barrel-DN_-gaRX.js';
|
|
3
|
+
import { b as ImageResourceState } from './image-resources-DkuzBnTM.js';
|
|
4
|
+
import { O as OmmlEquationProjection } from './omml-equation-BY7OdfGY.js';
|
|
5
5
|
|
|
6
6
|
/** A strikeout stroke at the drawn size, in points. `offsetPt` is the stroke TOP. @public */
|
|
7
7
|
interface StrikeoutStrokePt {
|
|
@@ -96,7 +96,10 @@ type ListMarkerAlign = 'left' | 'center' | 'right';
|
|
|
96
96
|
* must not overwrite an inherited `hanging` with a synthesized zero.
|
|
97
97
|
*/
|
|
98
98
|
interface NumberingLevelIndent {
|
|
99
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* The sides as the level spells them, in points. `left` and `start` both name the leading
|
|
101
|
+
* indent, and `right` and `end` the trailing one; `left`/`right` below hold those two.
|
|
102
|
+
*/
|
|
100
103
|
readonly authored?: {
|
|
101
104
|
readonly left?: number;
|
|
102
105
|
readonly right?: number;
|
|
@@ -110,9 +113,9 @@ interface NumberingLevelIndent {
|
|
|
110
113
|
/**
|
|
111
114
|
* Which of these the LEVEL actually authored.
|
|
112
115
|
*
|
|
113
|
-
* A level's `w:pPr/w:ind` sits between the
|
|
114
|
-
* merge has to tell "the level says left = 0" from
|
|
115
|
-
* the style's value stands". Absent (the default) reads as "says nothing", which is what a
|
|
116
|
+
* A level's `w:pPr/w:ind` sits between the formatting it outranks and the formatting that
|
|
117
|
+
* outranks it (`mergeListIndent`), so the merge has to tell "the level says left = 0" from
|
|
118
|
+
* "the level says nothing about left and the style's value stands". Absent (the default) reads as "says nothing", which is what a
|
|
116
119
|
* hand-built level in a test means.
|
|
117
120
|
*/
|
|
118
121
|
readonly stated?: {
|
|
@@ -239,894 +242,947 @@ declare function resolveNumberingLevel(index: NumberingIndex, numId: string, ilv
|
|
|
239
242
|
declare const EMPTY_NUMBERING_INDEX: NumberingIndex;
|
|
240
243
|
|
|
241
244
|
/**
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
* LAST WINS, like every other toggle read off the cascade (`paragraphKeeps` does the same
|
|
245
|
-
* for `w:keepNext`). An any-wins `.some()` cannot be switched off: a Chapter or Heading style
|
|
246
|
-
* carries `w:pageBreakBefore`, and Word writes `w:val="0"` on the one instance whose author
|
|
247
|
-
* unchecked the box — that paragraph still broke, so the document grew a blank page and every
|
|
248
|
-
* page number after it was wrong.
|
|
245
|
+
* A face, as something asks for it: family plus the two axes this engine admits.
|
|
249
246
|
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
247
|
+
* Only static weights and slants. Variable-font axes are deliberately outside this vocabulary —
|
|
248
|
+
* the shaper refuses variation axes, and a variable file admitted here would render bold at
|
|
249
|
+
* regular weight.
|
|
252
250
|
*/
|
|
253
|
-
|
|
251
|
+
interface FontRequest {
|
|
252
|
+
readonly family: string;
|
|
253
|
+
readonly weight: number;
|
|
254
|
+
readonly style: 'normal' | 'italic';
|
|
255
|
+
}
|
|
254
256
|
/**
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
+
* A request that was answered by a DIFFERENT face than the one asked for.
|
|
258
|
+
*
|
|
259
|
+
* Recorded rather than silently applied, because a substitution changes measurement: it is part
|
|
260
|
+
* of the shaping fingerprint, so a cached run shaped against a substitute is never reused for the
|
|
261
|
+
* real face.
|
|
257
262
|
*/
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
+
interface FontSubstitution {
|
|
264
|
+
readonly requested: FontRequest;
|
|
265
|
+
readonly resolved: FontRequest;
|
|
266
|
+
readonly lineMetrics?: {
|
|
267
|
+
readonly heightEm: number;
|
|
268
|
+
readonly baselineEm: number;
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
declare const RESOLVED_FONT_BRAND: unique symbol;
|
|
263
272
|
/**
|
|
264
|
-
* A
|
|
273
|
+
* A face that passed admission: the bytes are present, within limits, hash-verified, and parse as
|
|
274
|
+
* a font.
|
|
265
275
|
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
276
|
+
* Branded, so a `ResolvedFont` cannot be constructed by an object literal. Holding one is proof
|
|
277
|
+
* the checks ran — which is what lets shaping skip re-validating on every call.
|
|
268
278
|
*/
|
|
269
|
-
interface
|
|
270
|
-
|
|
271
|
-
readonly
|
|
272
|
-
|
|
273
|
-
readonly
|
|
279
|
+
interface ResolvedFont {
|
|
280
|
+
readonly [RESOLVED_FONT_BRAND]: true;
|
|
281
|
+
readonly id: string;
|
|
282
|
+
readonly identity: string;
|
|
283
|
+
readonly request: FontRequest;
|
|
284
|
+
readonly family: string;
|
|
285
|
+
/** Owned byte length, available without creating a defensive byte copy. */
|
|
286
|
+
readonly byteLength: number;
|
|
287
|
+
readonly bytes: Uint8Array;
|
|
288
|
+
readonly hash: string;
|
|
289
|
+
readonly faceIndex: number;
|
|
290
|
+
readonly substitution: FontSubstitution | null;
|
|
274
291
|
}
|
|
275
292
|
/**
|
|
276
|
-
*
|
|
277
|
-
* (ECMA-376 §17.3.1.33, the `w:spacing` clause both attributes belong to).
|
|
293
|
+
* Largest single face this engine will ever admit, whatever a caller configures.
|
|
278
294
|
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
* 14pt, which is what a document round-tripped through Word's HTML filter carries — and this
|
|
282
|
-
* one is everywhere, because Word writes `w:before="100" w:beforeAutospacing="1"` for it. Reading
|
|
283
|
-
* only the literal 100 twips lays every such paragraph out 9pt tight, which moves page breaks.
|
|
295
|
+
* A CEILING, not a default: a host may set a smaller `maxFontBytes`, but nothing can raise it
|
|
296
|
+
* past this. Font bytes come from files, and an unbounded face is a memory-exhaustion vector.
|
|
284
297
|
*/
|
|
285
|
-
declare const
|
|
298
|
+
declare const HARD_MAX_FONT_BYTES: number;
|
|
299
|
+
/** Most faces one snapshot may hold, whatever a caller configures. */
|
|
300
|
+
declare const HARD_MAX_FONT_SOURCES = 256;
|
|
301
|
+
/** Most bytes all admitted faces may total, whatever a caller configures. */
|
|
302
|
+
declare const HARD_MAX_AGGREGATE_FONT_BYTES: number;
|
|
286
303
|
/**
|
|
287
|
-
*
|
|
288
|
-
* instead of {@link AUTO_PARAGRAPH_SPACING_PT}.
|
|
289
|
-
*
|
|
290
|
-
* This resolves the interior list-item value. Body layout restores each outer list margin
|
|
291
|
-
* in `resolveListAutoSpacing`, where neighboring blocks are available. A caller that says
|
|
292
|
-
* nothing gets the body answer.
|
|
304
|
+
* Why a face was not admitted.
|
|
293
305
|
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
* paragraph between them it is 52.32, exactly twice. Reading it as 0 in a cell lays every
|
|
298
|
-
* such paragraph 13.92pt tight, which is enough to pull a signature block back onto the
|
|
299
|
-
* previous page. See `.cache/pdf/claude-autospacing/`.
|
|
306
|
+
* `forbidden` and `hashMismatch` are adversarial signals rather than ordinary failures: the first
|
|
307
|
+
* is a face the host declared off-limits, the second is bytes that are not what their source
|
|
308
|
+
* claimed.
|
|
300
309
|
*/
|
|
301
|
-
|
|
302
|
-
/** The paragraph participates in numbering (`w:numPr`), i.e. it is a list item. */
|
|
303
|
-
readonly inList?: boolean;
|
|
304
|
-
/**
|
|
305
|
-
* The paragraph lives in a table cell. Kept because callers describe position with it and
|
|
306
|
-
* list resolution reads it; it does NOT zero auto spacing.
|
|
307
|
-
*/
|
|
308
|
-
readonly inTableCell?: boolean;
|
|
309
|
-
/** Section grid pitch in points; no grid uses Word's fixed 12pt line unit. */
|
|
310
|
-
readonly lineUnitPt?: number;
|
|
311
|
-
}
|
|
310
|
+
type FontResolutionErrorCode = 'missing' | 'forbidden' | 'overLimit' | 'malformed' | 'hashMismatch';
|
|
312
311
|
/**
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
* `auto` is the interesting one: `@line` is 240ths of a line, so 240 is single, 360 is
|
|
316
|
-
* one-and-a-half, 480 is double — and Word's own Normal style since 2013 is 259, i.e.
|
|
317
|
-
* 1.08. A document laid out at a flat single spacing is ~8% tight on EVERY line, which
|
|
318
|
-
* moves every page break, so this is not a cosmetic detail.
|
|
312
|
+
* A face that could not be admitted, carrying whatever evidence the refusal produced.
|
|
319
313
|
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
314
|
+
* RETURNED rather than thrown by `FontResourceSnapshot.resolve`, because a missing face is an
|
|
315
|
+
* ordinary condition — layout falls back and carries on. It extends `Error` so a caller that
|
|
316
|
+
* would rather throw can.
|
|
322
317
|
*/
|
|
323
|
-
|
|
318
|
+
declare class FontResolutionError extends Error {
|
|
319
|
+
readonly name = "FontResolutionError";
|
|
320
|
+
readonly request: FontRequest;
|
|
321
|
+
readonly code: FontResolutionErrorCode;
|
|
322
|
+
readonly limit?: number;
|
|
323
|
+
readonly actual?: number;
|
|
324
|
+
readonly diagnostic?: string;
|
|
325
|
+
readonly expectedHash?: string;
|
|
326
|
+
readonly actualHash?: string;
|
|
327
|
+
constructor(code: FontResolutionErrorCode, request: FontRequest, details?: {
|
|
328
|
+
readonly limit?: number;
|
|
329
|
+
readonly actual?: number;
|
|
330
|
+
readonly diagnostic?: string;
|
|
331
|
+
readonly expectedHash?: string;
|
|
332
|
+
readonly actualHash?: string;
|
|
333
|
+
});
|
|
334
|
+
}
|
|
324
335
|
/**
|
|
325
|
-
*
|
|
336
|
+
* One face offered to a snapshot, before admission.
|
|
326
337
|
*
|
|
327
|
-
* `
|
|
328
|
-
*
|
|
338
|
+
* `hash` is checked against the bytes, so a source cannot claim a face it did not supply. Setting
|
|
339
|
+
* `availability` to `forbidden` declares a face that exists but must not be used, which resolves
|
|
340
|
+
* as a typed refusal rather than as "missing".
|
|
329
341
|
*/
|
|
330
|
-
interface
|
|
331
|
-
readonly
|
|
332
|
-
|
|
333
|
-
readonly
|
|
334
|
-
|
|
335
|
-
readonly
|
|
342
|
+
interface FontResourceDefinition {
|
|
343
|
+
readonly request: FontRequest;
|
|
344
|
+
readonly id: string;
|
|
345
|
+
readonly bytes: Uint8Array;
|
|
346
|
+
readonly hash: string;
|
|
347
|
+
readonly faceIndex: number;
|
|
348
|
+
readonly availability?: 'available' | 'forbidden';
|
|
336
349
|
}
|
|
337
|
-
/** Single spacing: what a paragraph that says nothing gets. */
|
|
338
|
-
declare const SINGLE_LINE_SPACING: ParagraphLineSpacing;
|
|
339
350
|
/**
|
|
340
|
-
*
|
|
351
|
+
* A host-declared redirect: requests for `from` resolve to `to`.
|
|
341
352
|
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
353
|
+
* How a metric-compatible substitute is wired in — a document naming Calibri resolves to Carlito
|
|
354
|
+
* without the document being rewritten.
|
|
344
355
|
*/
|
|
345
|
-
interface
|
|
346
|
-
|
|
347
|
-
readonly
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
/** Gap from text to the rule, in points (`w:space`). */
|
|
353
|
-
readonly spacePt: number;
|
|
354
|
-
/**
|
|
355
|
-
* `w:shadow` — Word offsets a drop shadow behind the rule.
|
|
356
|
-
*
|
|
357
|
-
* Present only when authored true, so an edge that says nothing keeps the shape earlier
|
|
358
|
-
* fixtures assert. Resolved and carried; drawing it is deferred.
|
|
359
|
-
*/
|
|
360
|
-
readonly shadow?: true;
|
|
356
|
+
interface DeclaredFontSubstitution {
|
|
357
|
+
readonly from: FontRequest;
|
|
358
|
+
readonly to: FontRequest;
|
|
359
|
+
readonly lineMetrics?: {
|
|
360
|
+
readonly heightEm: number;
|
|
361
|
+
readonly baselineEm: number;
|
|
362
|
+
};
|
|
361
363
|
}
|
|
362
|
-
/**
|
|
363
|
-
|
|
364
|
+
/** Whether bytes parse as a usable font, with a diagnostic when they do not. */
|
|
365
|
+
type FontValidationResult = {
|
|
366
|
+
readonly valid: true;
|
|
367
|
+
} | {
|
|
368
|
+
readonly valid: false;
|
|
369
|
+
readonly diagnostic: string;
|
|
370
|
+
};
|
|
364
371
|
/**
|
|
365
|
-
*
|
|
372
|
+
* The injected check that bytes really are a font.
|
|
366
373
|
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
374
|
+
* Injected because it is the shaper that knows — HarfBuzz can open a face and read its tables,
|
|
375
|
+
* and this layer must not duplicate that judgement. Every byte reaching it is file input.
|
|
369
376
|
*/
|
|
370
|
-
type
|
|
377
|
+
type FontByteValidator = (bytes: Uint8Array, faceIndex: number) => FontValidationResult;
|
|
371
378
|
/**
|
|
372
|
-
*
|
|
379
|
+
* An immutable set of admitted faces, and the only way to reach one.
|
|
373
380
|
*
|
|
374
|
-
* `
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
* paragraph, drawn whether or not the paragraph groups with its neighbours.
|
|
381
|
+
* `epoch` identifies the snapshot: fonts change by REPLACING it, never by mutation, so a layout
|
|
382
|
+
* pass holds one snapshot for its whole run and cannot observe a face appearing or vanishing
|
|
383
|
+
* midway.
|
|
378
384
|
*/
|
|
379
|
-
interface
|
|
380
|
-
readonly
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
readonly right?: ParagraphBorderEdge;
|
|
384
|
-
readonly between?: ParagraphBorderEdge;
|
|
385
|
-
readonly bar?: ParagraphBorderEdge;
|
|
385
|
+
interface FontResourceSnapshot {
|
|
386
|
+
readonly epoch: number;
|
|
387
|
+
/** The admitted face, or a typed refusal. Never throws. */
|
|
388
|
+
resolve(request: FontRequest): ResolvedFont | FontResolutionError;
|
|
386
389
|
}
|
|
387
390
|
/**
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
* Line spacing (`w:line` / `w:lineRule`) is a separate concern — it changes measured line
|
|
391
|
-
* height, not the gap between paragraphs — and is not resolved here.
|
|
391
|
+
* How a snapshot is built: which faces, under what limits, validated how.
|
|
392
392
|
*
|
|
393
|
-
* `
|
|
394
|
-
*
|
|
393
|
+
* `maxFontBytes` is clamped to {@link HARD_MAX_FONT_BYTES} — a caller may tighten the budget but
|
|
394
|
+
* never widen it past the engine's own ceiling.
|
|
395
395
|
*/
|
|
396
|
-
|
|
396
|
+
interface FontResourceSnapshotOptions {
|
|
397
|
+
readonly epoch: number;
|
|
398
|
+
readonly maxFontBytes: number;
|
|
399
|
+
readonly resources: readonly FontResourceDefinition[];
|
|
400
|
+
readonly substitutions?: readonly DeclaredFontSubstitution[];
|
|
401
|
+
readonly validateFont: FontByteValidator;
|
|
402
|
+
readonly instrumentation?: FontResourceInstrumentation;
|
|
403
|
+
}
|
|
397
404
|
/**
|
|
398
|
-
*
|
|
405
|
+
* Optional counters for the operations font admission is expected to do RARELY.
|
|
399
406
|
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
407
|
+
* Exists so tests can assert the absence of work: hashing and byte-copying a 64 MB face on every
|
|
408
|
+
* resolve would not be visible in output, only in a stalled document, so the checks assert these
|
|
409
|
+
* fire once rather than per call.
|
|
403
410
|
*/
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
* `atLeast` does the OPPOSITE: the box grows upward and the glyphs sit on its floor. A
|
|
414
|
-
* captured control settles it — Times New Roman 12 pt at `w:line="360" w:lineRule="atLeast"`
|
|
415
|
-
* puts the reference's baseline at 15.36 pt, which is `18 - descent` snapped to the device
|
|
416
|
-
* grid, where treating it like `auto` leaves the baseline at 11.28 and the text 4.08 pt too
|
|
417
|
-
* high. `w:line="240" atLeast` is below the natural line, falls through to the natural
|
|
418
|
-
* height, and is unaffected. See `.cache/pdf/claude-linerule/`.
|
|
411
|
+
interface FontResourceInstrumentation {
|
|
412
|
+
readonly onOwnedByteCopy?: () => void;
|
|
413
|
+
readonly onHash?: () => void;
|
|
414
|
+
readonly onTableScan?: () => void;
|
|
415
|
+
readonly onAdmission?: () => void;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* The canonical string identifying one face request.
|
|
419
419
|
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
420
|
+
* Case- and whitespace-normalized, so `"Times New Roman"` and `"times new roman"` are one key —
|
|
421
|
+
* a document may name a family either way and both must reach the same face.
|
|
422
422
|
*/
|
|
423
|
-
declare
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
};
|
|
423
|
+
declare const fontRequestKey: (request: FontRequest) => string;
|
|
424
|
+
/** Bounded minimum sfnt/TTC check; Task 4 supplies full parser-backed validation. */
|
|
425
|
+
declare const boundedStructuralFontValidator: FontByteValidator;
|
|
427
426
|
/**
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
427
|
+
* Admit a set of faces and return the immutable snapshot layout resolves against.
|
|
428
|
+
*
|
|
429
|
+
* Admission is the trust boundary for font bytes: counts and sizes are checked against the hard
|
|
430
|
+
* ceilings, each face's hash is re-derived and compared, and the bytes are handed to the injected
|
|
431
|
+
* validator. A face failing any of these is recorded as a typed refusal rather than dropped, so
|
|
432
|
+
* `resolve` can explain itself instead of answering "missing".
|
|
431
433
|
*/
|
|
432
|
-
declare
|
|
434
|
+
declare const createFontResourceSnapshot: (options: FontResourceSnapshotOptions) => FontResourceSnapshot;
|
|
435
|
+
|
|
436
|
+
declare const FIXED_POINT: unique symbol;
|
|
437
|
+
/** Fixed-point coordinates are safe integers in units declared by ShapingEnvironment.fixedPointScale. */
|
|
438
|
+
type FixedPoint = number & {
|
|
439
|
+
readonly [FIXED_POINT]: true;
|
|
440
|
+
};
|
|
433
441
|
/**
|
|
434
|
-
*
|
|
442
|
+
* Brand a safe integer as a {@link FixedPoint} coordinate.
|
|
435
443
|
*
|
|
436
|
-
*
|
|
437
|
-
*
|
|
444
|
+
* Fixed point rather than float throughout shaping so that two runs shaped identically compare
|
|
445
|
+
* EQUAL — float accumulation would make the same text measure differently depending on how it was
|
|
446
|
+
* split, and pagination is decided on those measurements.
|
|
447
|
+
*
|
|
448
|
+
* @throws RangeError when the value is not a safe integer.
|
|
438
449
|
*/
|
|
439
|
-
declare
|
|
450
|
+
declare const fixedPoint: (value: number) => FixedPoint;
|
|
451
|
+
/** Which way a run reads. The parity projection of its bidi embedding level. */
|
|
452
|
+
type TextDirection = 'ltr' | 'rtl';
|
|
453
|
+
/** How fixed-point conversion breaks ties. Part of the shaping fingerprint. */
|
|
454
|
+
type FixedPointRoundingMode = 'halfAwayFromZero' | 'halfToEven' | 'towardZero';
|
|
455
|
+
/** Which Unicode normalization is applied before shaping, if any. */
|
|
456
|
+
type NormalizationPolicy = 'none' | 'NFC' | 'NFD' | 'NFKC' | 'NFKD';
|
|
440
457
|
/**
|
|
441
|
-
*
|
|
458
|
+
* The shaping library and its exact version.
|
|
442
459
|
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
* underline surrounded by a box no one authored. Absence inherits; `nil`/`none` clear.
|
|
460
|
+
* Versioned because a library upgrade can change glyph positioning, and a cached measurement
|
|
461
|
+
* taken under the old one must not be reused under the new one.
|
|
446
462
|
*/
|
|
447
|
-
|
|
463
|
+
interface VersionedShapingLibrary {
|
|
464
|
+
readonly name: string;
|
|
465
|
+
readonly version: string;
|
|
466
|
+
}
|
|
448
467
|
/**
|
|
449
|
-
*
|
|
468
|
+
* Everything that determines how text shapes — the complete input to a
|
|
469
|
+
* {@link ShapingEnvironment}.
|
|
450
470
|
*
|
|
451
|
-
*
|
|
452
|
-
*
|
|
471
|
+
* Exhaustive on purpose. Any field that could change a glyph's position belongs here, because the
|
|
472
|
+
* environment's fingerprint is what decides whether a cached shaped run may be reused.
|
|
453
473
|
*/
|
|
454
|
-
|
|
474
|
+
interface ShapingEnvironmentInput {
|
|
475
|
+
readonly font: ResolvedFont;
|
|
476
|
+
readonly variationAxes: Readonly<Record<string, number>>;
|
|
477
|
+
readonly shapingLibrary: VersionedShapingLibrary;
|
|
478
|
+
readonly unicodeDataVersion: string;
|
|
479
|
+
readonly normalization: NormalizationPolicy;
|
|
480
|
+
readonly script: string;
|
|
481
|
+
readonly language: string;
|
|
482
|
+
readonly direction: TextDirection;
|
|
483
|
+
readonly features: Readonly<Record<string, number>>;
|
|
484
|
+
readonly fallbackOrder: readonly ResolvedFont[];
|
|
485
|
+
readonly fixedPointScale: number;
|
|
486
|
+
readonly roundingMode: FixedPointRoundingMode;
|
|
487
|
+
}
|
|
455
488
|
/**
|
|
456
|
-
*
|
|
489
|
+
* A validated {@link ShapingEnvironmentInput} — build one with `createShapingEnvironment`.
|
|
457
490
|
*
|
|
458
|
-
*
|
|
459
|
-
* the
|
|
460
|
-
* publish-only: Word draws left/right paragraph rules OUTSIDE the text column and never
|
|
461
|
-
* re-breaks the lines, which is why adding a box to a paragraph in Word does not reflow it.
|
|
491
|
+
* Structurally identical to its input, but the nominal distinction is the point: holding one
|
|
492
|
+
* means the tags, axes and fonts inside it have already been checked.
|
|
462
493
|
*/
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
494
|
+
interface ShapingEnvironment extends ShapingEnvironmentInput {
|
|
495
|
+
}
|
|
496
|
+
/** One shaping call: the text, its size, its bidi level, and the environment to shape it in. */
|
|
497
|
+
interface ShapeInput {
|
|
498
|
+
readonly text: string;
|
|
499
|
+
readonly fontSizeHalfPoints: number;
|
|
500
|
+
/** Exact UAX #9 embedding/isolate level; direction is its parity projection. */
|
|
501
|
+
readonly bidiLevel: number;
|
|
502
|
+
readonly environment: ShapingEnvironment;
|
|
503
|
+
/**
|
|
504
|
+
* Logical text around `text` that the shaper reads for contextual forms but never
|
|
505
|
+
* shapes: HarfBuzz pre- and post-context. A word split across two formatting runs joins
|
|
506
|
+
* across the split only when each half sees the other's letters. At most
|
|
507
|
+
* {@link MAX_SHAPING_CONTEXT} UTF-16 units each; glyphs and clusters cover `text` alone.
|
|
508
|
+
*/
|
|
509
|
+
readonly context?: ShapingContext;
|
|
510
|
+
}
|
|
511
|
+
/** Pre- and post-context for one shaping call. See {@link ShapeInput.context}. @public */
|
|
512
|
+
interface ShapingContext {
|
|
513
|
+
readonly before: string;
|
|
514
|
+
readonly after: string;
|
|
515
|
+
}
|
|
516
|
+
/** Longest context on either side, in UTF-16 units. Joining needs only the nearest letters. @public */
|
|
517
|
+
declare const MAX_SHAPING_CONTEXT = 16;
|
|
466
518
|
/**
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
* Word treats consecutive paragraphs whose border settings are IDENTICAL as ONE bordered
|
|
470
|
-
* block: the top rule draws above the first, the bottom rule below the last, and each
|
|
471
|
-
* interior boundary gets `w:between` or nothing (§17.3.1.24). That is why applying a box to
|
|
472
|
-
* three selected paragraphs in Word draws one box and not three.
|
|
519
|
+
* One positioned glyph.
|
|
473
520
|
*
|
|
474
|
-
*
|
|
521
|
+
* `id` is a glyph index in its FACE, not a character — a ligature is one glyph spanning several
|
|
522
|
+
* characters, and a single character may produce several glyphs. Use `cluster` to get back to
|
|
523
|
+
* text.
|
|
475
524
|
*/
|
|
476
|
-
|
|
525
|
+
interface ShapedGlyph {
|
|
526
|
+
readonly id: number;
|
|
527
|
+
/** Optional synthetic glyph-size factor; positions and advances already include it. */
|
|
528
|
+
readonly drawScale?: number;
|
|
529
|
+
/** UTF-16 text offset identifying the cluster that produced this glyph. */
|
|
530
|
+
readonly cluster: number;
|
|
531
|
+
/** Pen origin before this glyph's shaping offsets, in fixed-point run coordinates. */
|
|
532
|
+
readonly originX: FixedPoint;
|
|
533
|
+
readonly originY: FixedPoint;
|
|
534
|
+
readonly advanceX: FixedPoint;
|
|
535
|
+
readonly advanceY: FixedPoint;
|
|
536
|
+
readonly offsetX: FixedPoint;
|
|
537
|
+
readonly offsetY: FixedPoint;
|
|
538
|
+
/** Exact monochrome outline returned by the admitted HarfBuzz face. */
|
|
539
|
+
readonly outline: GlyphOutline;
|
|
540
|
+
}
|
|
541
|
+
/** A glyph's outline as SVG path data, in font design units. */
|
|
542
|
+
interface GlyphOutline {
|
|
543
|
+
readonly path: string;
|
|
544
|
+
/** Design units per em — divide by this to scale the path to a point size. */
|
|
545
|
+
readonly unitsPerEm: number;
|
|
546
|
+
}
|
|
477
547
|
/**
|
|
478
|
-
*
|
|
479
|
-
*
|
|
548
|
+
* One cluster: the smallest indivisible text-to-glyph correspondence.
|
|
549
|
+
*
|
|
550
|
+
* The unit the CARET moves by. A cluster may be several characters (a ligature) or several glyphs
|
|
551
|
+
* (a decomposed mark), so neither a character index nor a glyph index is a valid caret position —
|
|
552
|
+
* `caretEdges` is, and it includes both endpoints.
|
|
480
553
|
*/
|
|
481
|
-
|
|
554
|
+
interface ShapedCluster {
|
|
555
|
+
/** Half-open logical UTF-16 range in ShapedRun.text. */
|
|
556
|
+
readonly textStart: number;
|
|
557
|
+
readonly textEnd: number;
|
|
558
|
+
/** Half-open visual glyph range in ShapedRun.glyphs. */
|
|
559
|
+
readonly glyphStart: number;
|
|
560
|
+
readonly glyphEnd: number;
|
|
561
|
+
readonly advance: FixedPoint;
|
|
562
|
+
/** Fixed-point edges from this cluster's visual origin, including both endpoints. */
|
|
563
|
+
readonly caretEdges: readonly FixedPoint[];
|
|
564
|
+
/** Index into ShapedRun.fontSpans, preserving the exact fallback choice. */
|
|
565
|
+
readonly fontSpan: number;
|
|
566
|
+
}
|
|
567
|
+
/** A run's vertical metrics, from the face that shaped it. Drives line height and baseline. */
|
|
568
|
+
interface ShapedVerticalMetrics {
|
|
569
|
+
readonly ascent: FixedPoint;
|
|
570
|
+
readonly descent: FixedPoint;
|
|
571
|
+
readonly lineGap: FixedPoint;
|
|
572
|
+
}
|
|
482
573
|
/**
|
|
483
|
-
*
|
|
574
|
+
* A stretch of glyphs that came from ONE face.
|
|
484
575
|
*
|
|
485
|
-
*
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
* applied value on the fragment so shading, borders,
|
|
489
|
-
* selection, and paint share one geometry.
|
|
576
|
+
* A run whose text needed fallback has several of these. Recording the exact face per span is
|
|
577
|
+
* what lets a re-shape reproduce the same result rather than re-running fallback selection and
|
|
578
|
+
* possibly choosing differently.
|
|
490
579
|
*/
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
/**
|
|
496
|
-
|
|
497
|
-
/** The authored `ST_Underline` variant. */
|
|
498
|
-
readonly variant: string;
|
|
499
|
-
/** RRGGBB, or null when the underline follows the text colour. */
|
|
500
|
-
readonly color: string | null;
|
|
580
|
+
interface ShapedFontSpan {
|
|
581
|
+
readonly glyphStart: number;
|
|
582
|
+
readonly glyphEnd: number;
|
|
583
|
+
readonly font: ResolvedFont;
|
|
584
|
+
/** null denotes the primary font; otherwise this is the environment fallback-order index. */
|
|
585
|
+
readonly fallbackIndex: number | null;
|
|
501
586
|
}
|
|
502
587
|
/**
|
|
503
|
-
*
|
|
588
|
+
* One shaped run: text turned into positioned glyphs, with everything needed to measure it, paint
|
|
589
|
+
* it, and put a caret in it.
|
|
504
590
|
*
|
|
505
|
-
*
|
|
506
|
-
* resolved, so measurement and paint never re-run the cascade per glyph.
|
|
591
|
+
* The engine's measurement unit. Layout never measures characters — it measures these.
|
|
507
592
|
*/
|
|
508
|
-
interface
|
|
509
|
-
readonly
|
|
593
|
+
interface ShapedRun {
|
|
594
|
+
readonly text: string;
|
|
595
|
+
readonly direction: TextDirection;
|
|
596
|
+
readonly bidiLevel: number;
|
|
597
|
+
readonly glyphs: readonly ShapedGlyph[];
|
|
598
|
+
readonly clusters: readonly ShapedCluster[];
|
|
599
|
+
readonly fontSpans: readonly ShapedFontSpan[];
|
|
600
|
+
readonly metrics: ShapedVerticalMetrics;
|
|
510
601
|
/**
|
|
511
|
-
* The
|
|
512
|
-
*
|
|
602
|
+
* The same horizontal advances as `glyphs[i].advanceX`, in the same fixed-point units, but
|
|
603
|
+
* BEFORE the per-glyph rounding to the fixed-point grid. Parallel to `glyphs`.
|
|
513
604
|
*
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
605
|
+
* Measurement and line breaking read `advanceX` and must keep doing so: pagination is decided
|
|
606
|
+
* on those numbers, and two runs shaped identically have to compare equal. A painter that
|
|
607
|
+
* gives every glyph its own absolute position sums the advances instead, and a sum of ROUNDED
|
|
608
|
+
* advances drifts by up to half a fixed-point unit per glyph — an error that only grows along
|
|
609
|
+
* a line. Summing these and rounding once, at the position actually written, does not.
|
|
610
|
+
*
|
|
611
|
+
* Absent on runs an assembly path cannot state exactly; a reader falls back to `originX`.
|
|
518
612
|
*/
|
|
519
|
-
readonly
|
|
520
|
-
/** Script and paragraph-resolved direction for shaping and visual placement. */
|
|
521
|
-
readonly shaping?: {
|
|
522
|
-
readonly script: string;
|
|
523
|
-
readonly direction: 'ltr' | 'rtl';
|
|
524
|
-
readonly level: number;
|
|
525
|
-
readonly baseLevel: number;
|
|
526
|
-
/** Resolved w:rtl context; absent when authored Unicode controls govern the paragraph. */
|
|
527
|
-
readonly runDirection?: 'ltr' | 'rtl';
|
|
528
|
-
readonly wordSpacingPt?: number;
|
|
529
|
-
};
|
|
530
|
-
/** Points. `w:sz` is half-points, so 22 becomes 11. */
|
|
531
|
-
readonly fontSizePt: number;
|
|
532
|
-
/** RRGGBB, or null for the inherited/automatic colour. */
|
|
533
|
-
readonly color: string | null;
|
|
534
|
-
readonly bold: boolean;
|
|
535
|
-
/** Opaque solid `w14:textOutline`, in points; paint only, never a font-weight change. */
|
|
536
|
-
readonly textOutline?: {
|
|
537
|
-
readonly widthPt: number;
|
|
538
|
-
readonly color: string;
|
|
539
|
-
};
|
|
540
|
-
/** Character border; adjacent runs with matching edges share one outline. */
|
|
541
|
-
readonly border?: ParagraphBorderEdge;
|
|
542
|
-
readonly italic: boolean;
|
|
543
|
-
readonly underline: ResolvedUnderline | null;
|
|
544
|
-
readonly strike: boolean;
|
|
545
|
-
readonly doubleStrike: boolean;
|
|
546
|
-
/** An `ST_HighlightColor` name, or null. */
|
|
547
|
-
readonly highlight: string | null;
|
|
548
|
-
/**
|
|
549
|
-
* Character shading fill (`w:rPr/w:shd`), validated RRGGBB, or null.
|
|
550
|
-
*
|
|
551
|
-
* Paint applies this as the glyph-box background; a recognised highlight overrides it.
|
|
552
|
-
* Measurement ignores shading.
|
|
553
|
-
*/
|
|
554
|
-
readonly shading: string | null;
|
|
555
|
-
readonly verticalAlign: VerticalAlign;
|
|
556
|
-
/** `w:position`, in points. Positive raises the baseline. */
|
|
557
|
-
readonly baselineShiftPt: number;
|
|
558
|
-
readonly caps: boolean;
|
|
559
|
-
readonly smallCaps: boolean;
|
|
560
|
-
/** `w:spacing`, in points. Added to every advance. */
|
|
561
|
-
readonly characterSpacingPt: number;
|
|
562
|
-
/** `w:w`, as a percentage. 100 is unscaled. */
|
|
563
|
-
readonly horizontalScalePercent: number;
|
|
564
|
-
/** `w:kern`, in points: the size at or above which kerning applies. */
|
|
565
|
-
readonly kerningMinPt: number;
|
|
566
|
-
/** Explicit kerning selection; a zero threshold disables it. Absent uses a positive threshold. */
|
|
567
|
-
readonly kerningEnabled?: boolean;
|
|
568
|
-
/** Resolved optional OpenType substitutions; required script ligatures are independent. */
|
|
569
|
-
readonly ligatures?: {
|
|
570
|
-
readonly standard: boolean;
|
|
571
|
-
readonly contextual: boolean;
|
|
572
|
-
readonly historical: boolean;
|
|
573
|
-
readonly discretionary: boolean;
|
|
574
|
-
};
|
|
575
|
-
/**
|
|
576
|
-
* `w:vanish` (ECMA-376 §17.3.2.45): the run is hidden text.
|
|
577
|
-
*
|
|
578
|
-
* Word does not draw it AND does not paginate it — hidden index or comment text takes no
|
|
579
|
-
* space at all. So this cannot be a paint-time opacity: a hidden run that is still measured
|
|
580
|
-
* pushes every following line, and every following page break, to the wrong place. Layout
|
|
581
|
-
* drops the content instead (see `piecesOfParagraph`).
|
|
582
|
-
*
|
|
583
|
-
* `w:specVanish` (§17.3.2.36) is a different property — an always-hidden paragraph mark on
|
|
584
|
-
* a heading — and never sets this.
|
|
585
|
-
*/
|
|
586
|
-
readonly hidden: boolean;
|
|
613
|
+
readonly exactAdvancesX?: readonly number[];
|
|
587
614
|
}
|
|
588
|
-
/** The style a run inherits when it authors nothing. */
|
|
589
|
-
declare const DEFAULT_RUN_STYLE: ResolvedRunStyle;
|
|
590
615
|
/**
|
|
591
|
-
*
|
|
616
|
+
* A {@link ShapedRun} reduced to the fields two shaping results must agree on to be considered
|
|
617
|
+
* identical.
|
|
592
618
|
*
|
|
593
|
-
*
|
|
594
|
-
*
|
|
619
|
+
* Fonts appear as {@link FontFingerprintInputs} rather than whole `ResolvedFont` objects, so the
|
|
620
|
+
* comparison is over VALUES and does not depend on object identity — which is what makes it work
|
|
621
|
+
* across a reload or a worker boundary.
|
|
595
622
|
*/
|
|
596
|
-
interface
|
|
597
|
-
|
|
598
|
-
readonly
|
|
599
|
-
|
|
600
|
-
readonly
|
|
601
|
-
|
|
602
|
-
readonly
|
|
603
|
-
|
|
604
|
-
readonly
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
readonly
|
|
623
|
+
interface ShapedRunComparatorInputs {
|
|
624
|
+
readonly text: string;
|
|
625
|
+
readonly direction: TextDirection;
|
|
626
|
+
readonly script: string;
|
|
627
|
+
readonly language: string;
|
|
628
|
+
readonly bidiLevel: number;
|
|
629
|
+
readonly glyphs: readonly ShapedGlyph[];
|
|
630
|
+
readonly clusters: readonly ShapedCluster[];
|
|
631
|
+
readonly fontSpans: readonly {
|
|
632
|
+
readonly glyphStart: number;
|
|
633
|
+
readonly glyphEnd: number;
|
|
634
|
+
readonly fallbackIndex: number | null;
|
|
635
|
+
readonly font: FontFingerprintInputs;
|
|
636
|
+
}[];
|
|
637
|
+
readonly metrics: ShapedVerticalMetrics;
|
|
611
638
|
}
|
|
612
639
|
/**
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
* Unrecognised values are DROPPED rather than guessed: a `w:sz` of `"large"` leaves the
|
|
616
|
-
* default size rather than inventing one, because a wrong measurement moves every glyph
|
|
617
|
-
* after it and a missing one is visible immediately.
|
|
640
|
+
* The one thing layout needs from a shaping backend.
|
|
618
641
|
*
|
|
619
|
-
*
|
|
620
|
-
*
|
|
621
|
-
*
|
|
642
|
+
* Injected rather than imported, which is what keeps layout DOM-free and testable: a fixed-metric
|
|
643
|
+
* shaper measures deterministically in a test, HarfBuzz measures for real in a browser, and
|
|
644
|
+
* layout cannot tell the difference.
|
|
622
645
|
*/
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
/** Measure run text the way layout breaks lines and paints glyphs (caps/small-caps aware). */
|
|
627
|
-
declare function measureDisplayText(text: string, style: ResolvedRunStyle, measurer: TextMeasurer): number;
|
|
628
|
-
/** Whether two resolved styles are identical, for span merging and cache keys. */
|
|
629
|
-
declare function runStylesEqual(a: ResolvedRunStyle, b: ResolvedRunStyle): boolean;
|
|
646
|
+
interface TextShaper {
|
|
647
|
+
shape(input: ShapeInput): ShapedRun;
|
|
648
|
+
}
|
|
630
649
|
/**
|
|
631
|
-
*
|
|
650
|
+
* A font reduced to the values that identify it for fingerprinting.
|
|
632
651
|
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
*
|
|
652
|
+
* Includes the content `hash` and `faceIndex`, so two faces with the same family name but
|
|
653
|
+
* different bytes fingerprint differently — which is what stops a cached measurement being reused
|
|
654
|
+
* against a substituted face.
|
|
636
655
|
*/
|
|
637
|
-
|
|
656
|
+
interface FontFingerprintInputs {
|
|
657
|
+
readonly identity: string;
|
|
658
|
+
readonly id: string;
|
|
659
|
+
readonly family: string;
|
|
660
|
+
readonly request: FontRequest;
|
|
661
|
+
readonly hash: string;
|
|
662
|
+
readonly faceIndex: number;
|
|
663
|
+
readonly byteLength: number;
|
|
664
|
+
readonly substitution: FontSubstitution | null;
|
|
665
|
+
}
|
|
638
666
|
/**
|
|
639
|
-
*
|
|
667
|
+
* A {@link ShapingEnvironment} reduced to comparable values.
|
|
640
668
|
*
|
|
641
|
-
*
|
|
642
|
-
*
|
|
643
|
-
*
|
|
644
|
-
* Layout, surface paint, and exporters must apply the same factor to avoid caret drift.
|
|
645
|
-
* @public
|
|
669
|
+
* Records and axis maps become SORTED entry arrays, because two environments differing only in
|
|
670
|
+
* key insertion order must fingerprint the same — otherwise a cache would miss on a difference
|
|
671
|
+
* that changes no glyph.
|
|
646
672
|
*/
|
|
647
|
-
|
|
648
|
-
|
|
673
|
+
interface ShapingEnvironmentFingerprintInputs {
|
|
674
|
+
readonly font: FontFingerprintInputs;
|
|
675
|
+
readonly variationAxes: readonly (readonly [string, number])[];
|
|
676
|
+
readonly shapingLibrary: VersionedShapingLibrary;
|
|
677
|
+
readonly unicodeDataVersion: string;
|
|
678
|
+
readonly normalization: NormalizationPolicy;
|
|
679
|
+
readonly script: string;
|
|
680
|
+
readonly language: string;
|
|
681
|
+
readonly direction: TextDirection;
|
|
682
|
+
readonly features: readonly (readonly [string, number])[];
|
|
683
|
+
readonly fallbackOrder: readonly FontFingerprintInputs[];
|
|
684
|
+
readonly fixedPointScale: number;
|
|
685
|
+
readonly roundingMode: FixedPointRoundingMode;
|
|
686
|
+
}
|
|
649
687
|
/**
|
|
650
|
-
*
|
|
651
|
-
* within.
|
|
688
|
+
* Validate and freeze a shaping environment.
|
|
652
689
|
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
690
|
+
* Checks every field that could silently corrupt a measurement: OpenType tags must be four ASCII
|
|
691
|
+
* bytes, script and language must be non-blank and control-character free, fonts must already be
|
|
692
|
+
* validated. Throws rather than coercing — a bad tag that shapes anyway produces a document that
|
|
693
|
+
* measures wrong everywhere and looks fine.
|
|
694
|
+
*
|
|
695
|
+
* @throws TypeError on a malformed tag, name, or axis value.
|
|
655
696
|
*/
|
|
656
|
-
|
|
657
|
-
readonly levels: Uint8Array;
|
|
658
|
-
readonly paragraphs: readonly {
|
|
659
|
-
readonly start: number;
|
|
660
|
-
readonly end: number;
|
|
661
|
-
readonly level: number;
|
|
662
|
-
}[];
|
|
663
|
-
}
|
|
664
|
-
|
|
697
|
+
declare const createShapingEnvironment: (input: ShapingEnvironmentInput) => ShapingEnvironment;
|
|
665
698
|
/**
|
|
666
|
-
*
|
|
667
|
-
*
|
|
668
|
-
* Only static weights and slants. Variable-font axes are deliberately outside this vocabulary —
|
|
669
|
-
* the shaper refuses variation axes, and a variable file admitted here would render bold at
|
|
670
|
-
* regular weight.
|
|
699
|
+
* Reduce an environment to its comparable form, with records sorted so key order cannot affect
|
|
700
|
+
* the result.
|
|
671
701
|
*/
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
readonly style: 'normal' | 'italic';
|
|
676
|
-
}
|
|
702
|
+
declare const shapingEnvironmentFingerprintInputs: (input: ShapingEnvironmentInput) => ShapingEnvironmentFingerprintInputs;
|
|
703
|
+
/** Canonical serialization of every shaping variable, including byte hash and provenance. */
|
|
704
|
+
declare const shapingEnvironmentFingerprint: (environment: ShapingEnvironmentInput) => string;
|
|
677
705
|
/**
|
|
678
|
-
*
|
|
706
|
+
* Validate and freeze a shaped run against the environment that produced it.
|
|
679
707
|
*
|
|
680
|
-
*
|
|
681
|
-
*
|
|
682
|
-
*
|
|
708
|
+
* Checks the internal consistency a shaper must satisfy: direction matches the environment,
|
|
709
|
+
* cluster ranges tile the text without gaps or overlap, glyph ranges stay in bounds, font spans
|
|
710
|
+
* cover every glyph, and caret edges are monotonic. A shaper that violates any of these produces
|
|
711
|
+
* a caret that lands in the wrong place, which is far harder to diagnose downstream than here.
|
|
712
|
+
*
|
|
713
|
+
* @throws TypeError when the run and environment disagree, or the run is internally inconsistent.
|
|
683
714
|
*/
|
|
684
|
-
|
|
685
|
-
readonly requested: FontRequest;
|
|
686
|
-
readonly resolved: FontRequest;
|
|
687
|
-
readonly lineMetrics?: {
|
|
688
|
-
readonly heightEm: number;
|
|
689
|
-
readonly baselineEm: number;
|
|
690
|
-
};
|
|
691
|
-
}
|
|
692
|
-
declare const RESOLVED_FONT_BRAND: unique symbol;
|
|
715
|
+
declare const createShapedRun: (input: ShapedRun, environmentInput: ShapingEnvironmentInput) => ShapedRun;
|
|
693
716
|
/**
|
|
694
|
-
*
|
|
695
|
-
* a font.
|
|
717
|
+
* Reduce a shaped run to its comparable form, validating it on the way through.
|
|
696
718
|
*
|
|
697
|
-
*
|
|
698
|
-
*
|
|
719
|
+
* What the D9 determinism oracles compare: two shaping runs of the same text in the same
|
|
720
|
+
* environment must produce byte-identical structures here.
|
|
699
721
|
*/
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
readonly id: string;
|
|
703
|
-
readonly identity: string;
|
|
704
|
-
readonly request: FontRequest;
|
|
705
|
-
readonly family: string;
|
|
706
|
-
/** Owned byte length, available without creating a defensive byte copy. */
|
|
707
|
-
readonly byteLength: number;
|
|
708
|
-
readonly bytes: Uint8Array;
|
|
709
|
-
readonly hash: string;
|
|
710
|
-
readonly faceIndex: number;
|
|
711
|
-
readonly substitution: FontSubstitution | null;
|
|
712
|
-
}
|
|
722
|
+
declare const shapedRunComparatorInputs: (input: ShapedRun, environment: ShapingEnvironmentInput) => ShapedRunComparatorInputs;
|
|
723
|
+
|
|
713
724
|
/**
|
|
714
|
-
*
|
|
725
|
+
* Whether a paragraph must start a new page (`w:pageBreakBefore`).
|
|
715
726
|
*
|
|
716
|
-
*
|
|
717
|
-
*
|
|
727
|
+
* LAST WINS, like every other toggle read off the cascade (`paragraphKeeps` does the same
|
|
728
|
+
* for `w:keepNext`). An any-wins `.some()` cannot be switched off: a Chapter or Heading style
|
|
729
|
+
* carries `w:pageBreakBefore`, and Word writes `w:val="0"` on the one instance whose author
|
|
730
|
+
* unchecked the box — that paragraph still broke, so the document grew a blank page and every
|
|
731
|
+
* page number after it was wrong.
|
|
732
|
+
*
|
|
733
|
+
* An absent `w:val` is on (§17.17.4), and the off vocabulary is the whole of it — `off` is a
|
|
734
|
+
* spelling too, which {@link isOn} beside this already accepts.
|
|
718
735
|
*/
|
|
719
|
-
declare
|
|
720
|
-
/** Most faces one snapshot may hold, whatever a caller configures. */
|
|
721
|
-
declare const HARD_MAX_FONT_SOURCES = 256;
|
|
722
|
-
/** Most bytes all admitted faces may total, whatever a caller configures. */
|
|
723
|
-
declare const HARD_MAX_AGGREGATE_FONT_BYTES: number;
|
|
736
|
+
declare function paragraphBreaksBefore(props: readonly OoxmlProperty[]): boolean;
|
|
724
737
|
/**
|
|
725
|
-
*
|
|
726
|
-
*
|
|
727
|
-
* `forbidden` and `hashMismatch` are adversarial signals rather than ordinary failures: the first
|
|
728
|
-
* is a face the host declared off-limits, the second is bytes that are not what their source
|
|
729
|
-
* claimed.
|
|
738
|
+
* Soft ceiling matching the spike's resolved-style limit (31_680 twips ≈ 22"). Beyond
|
|
739
|
+
* that an attacker-authored spacing would push pagination into pathological page counts.
|
|
730
740
|
*/
|
|
731
|
-
|
|
741
|
+
declare const MAX_PARAGRAPH_SPACING_PT: number;
|
|
742
|
+
/** Soft ceiling on border width (96 eighths = 12pt). Word's UI tops out well below this. */
|
|
743
|
+
declare const MAX_BORDER_WIDTH_PT = 12;
|
|
744
|
+
/** Soft ceiling on border-to-text gap (`w:space`, already in points). */
|
|
745
|
+
declare const MAX_BORDER_SPACE_PT = 3168;
|
|
732
746
|
/**
|
|
733
|
-
* A
|
|
747
|
+
* A paragraph's resolved space before and after, in points.
|
|
734
748
|
*
|
|
735
|
-
*
|
|
736
|
-
*
|
|
737
|
-
* would rather throw can.
|
|
749
|
+
* Already collapsed against `w:contextualSpacing`, so adjacent same-style paragraphs that suppress
|
|
750
|
+
* their gap arrive here with it removed rather than leaving that to whoever stacks them.
|
|
738
751
|
*/
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
readonly
|
|
742
|
-
|
|
743
|
-
readonly
|
|
744
|
-
readonly actual?: number;
|
|
745
|
-
readonly diagnostic?: string;
|
|
746
|
-
readonly expectedHash?: string;
|
|
747
|
-
readonly actualHash?: string;
|
|
748
|
-
constructor(code: FontResolutionErrorCode, request: FontRequest, details?: {
|
|
749
|
-
readonly limit?: number;
|
|
750
|
-
readonly actual?: number;
|
|
751
|
-
readonly diagnostic?: string;
|
|
752
|
-
readonly expectedHash?: string;
|
|
753
|
-
readonly actualHash?: string;
|
|
754
|
-
});
|
|
752
|
+
interface ParagraphSpacing {
|
|
753
|
+
/** `w:spacing/@before`, in points. */
|
|
754
|
+
readonly before: number;
|
|
755
|
+
/** `w:spacing/@after`, in points. */
|
|
756
|
+
readonly after: number;
|
|
755
757
|
}
|
|
756
758
|
/**
|
|
757
|
-
*
|
|
759
|
+
* The gap Word substitutes when `w:beforeAutospacing` / `w:afterAutospacing` is on
|
|
760
|
+
* (ECMA-376 §17.3.1.33, the `w:spacing` clause both attributes belong to).
|
|
758
761
|
*
|
|
759
|
-
*
|
|
760
|
-
*
|
|
761
|
-
*
|
|
762
|
+
* The attribute means "the consumer decides", and the authored `@before` / `@after` beside it
|
|
763
|
+
* is IGNORED rather than used as the value. Word's answer is HTML's default `<p>` margin,
|
|
764
|
+
* 14pt, which is what a document round-tripped through Word's HTML filter carries — and this
|
|
765
|
+
* one is everywhere, because Word writes `w:before="100" w:beforeAutospacing="1"` for it. Reading
|
|
766
|
+
* only the literal 100 twips lays every such paragraph out 9pt tight, which moves page breaks.
|
|
762
767
|
*/
|
|
763
|
-
|
|
764
|
-
readonly request: FontRequest;
|
|
765
|
-
readonly id: string;
|
|
766
|
-
readonly bytes: Uint8Array;
|
|
767
|
-
readonly hash: string;
|
|
768
|
-
readonly faceIndex: number;
|
|
769
|
-
readonly availability?: 'available' | 'forbidden';
|
|
770
|
-
}
|
|
768
|
+
declare const AUTO_PARAGRAPH_SPACING_PT = 14;
|
|
771
769
|
/**
|
|
772
|
-
*
|
|
770
|
+
* Where a paragraph sits, for the contexts in which Word's auto spacing resolves to 0
|
|
771
|
+
* instead of {@link AUTO_PARAGRAPH_SPACING_PT}.
|
|
773
772
|
*
|
|
774
|
-
*
|
|
775
|
-
*
|
|
773
|
+
* This resolves the interior list-item value. Body layout restores each outer list margin
|
|
774
|
+
* in `resolveListAutoSpacing`, where neighboring blocks are available. A caller that says
|
|
775
|
+
* nothing gets the body answer.
|
|
776
|
+
*
|
|
777
|
+
* A TABLE CELL is not such a context. Measured on a captured control at 10pt, where the
|
|
778
|
+
* line pitch is 11.52pt: the reference puts 26.16pt between two paragraphs in the body with
|
|
779
|
+
* auto spacing on, and the SAME 26.16pt between two paragraphs inside a cell. With an empty
|
|
780
|
+
* paragraph between them it is 52.32, exactly twice. Reading it as 0 in a cell lays every
|
|
781
|
+
* such paragraph 13.92pt tight, which is enough to pull a signature block back onto the
|
|
782
|
+
* previous page. See `.cache/pdf/claude-autospacing/`.
|
|
776
783
|
*/
|
|
777
|
-
interface
|
|
778
|
-
|
|
779
|
-
readonly
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
+
interface ParagraphAutoSpacingContext {
|
|
785
|
+
/** The paragraph participates in numbering (`w:numPr`), i.e. it is a list item. */
|
|
786
|
+
readonly inList?: boolean;
|
|
787
|
+
/**
|
|
788
|
+
* The paragraph lives in a table cell. Kept because callers describe position with it and
|
|
789
|
+
* list resolution reads it; it does NOT zero auto spacing.
|
|
790
|
+
*/
|
|
791
|
+
readonly inTableCell?: boolean;
|
|
792
|
+
/** Section grid pitch in points; no grid uses Word's fixed 12pt line unit. */
|
|
793
|
+
readonly lineUnitPt?: number;
|
|
794
|
+
/**
|
|
795
|
+
* `w:doNotUseHTMLParagraphAutoSpacing` is on: automatic spacing outside a list resolves to
|
|
796
|
+
* the fixed 5pt before and 10pt after instead of {@link AUTO_PARAGRAPH_SPACING_PT}.
|
|
797
|
+
*/
|
|
798
|
+
readonly fixedAutoSpacing?: boolean;
|
|
784
799
|
}
|
|
785
|
-
/** Whether bytes parse as a usable font, with a diagnostic when they do not. */
|
|
786
|
-
type FontValidationResult = {
|
|
787
|
-
readonly valid: true;
|
|
788
|
-
} | {
|
|
789
|
-
readonly valid: false;
|
|
790
|
-
readonly diagnostic: string;
|
|
791
|
-
};
|
|
792
800
|
/**
|
|
793
|
-
*
|
|
801
|
+
* Resolved line spacing (`w:spacing/@line` + `@lineRule`, ECMA-376 17.3.1.33).
|
|
794
802
|
*
|
|
795
|
-
*
|
|
796
|
-
* and
|
|
803
|
+
* `auto` is the interesting one: `@line` is 240ths of a line, so 240 is single, 360 is
|
|
804
|
+
* one-and-a-half, 480 is double — and Word's own Normal style since 2013 is 259, i.e.
|
|
805
|
+
* 1.08. A document laid out at a flat single spacing is ~8% tight on EVERY line, which
|
|
806
|
+
* moves every page break, so this is not a cosmetic detail.
|
|
807
|
+
*
|
|
808
|
+
* `exact` fixes the line box at `@line` twips and lets tall glyphs clip, the way Word
|
|
809
|
+
* does. `atLeast` uses it as a floor.
|
|
797
810
|
*/
|
|
798
|
-
type
|
|
811
|
+
type LineSpacingRule = 'auto' | 'exact' | 'atLeast';
|
|
799
812
|
/**
|
|
800
|
-
*
|
|
813
|
+
* Resolved line spacing: the rule, and the value it applies.
|
|
801
814
|
*
|
|
802
|
-
* `
|
|
803
|
-
*
|
|
804
|
-
* midway.
|
|
815
|
+
* `value` means different things per rule — 240ths of a line under `auto`, points under `exact`
|
|
816
|
+
* and `atLeast` — which is why the two travel together and neither is useful alone.
|
|
805
817
|
*/
|
|
806
|
-
interface
|
|
807
|
-
readonly
|
|
808
|
-
/**
|
|
809
|
-
|
|
818
|
+
interface ParagraphLineSpacing {
|
|
819
|
+
readonly rule: LineSpacingRule;
|
|
820
|
+
/** `auto`: the 240ths-of-a-line multiplier numerator. Otherwise points. */
|
|
821
|
+
readonly value: number;
|
|
822
|
+
/** Legacy noExtraLineSpacing: retain the natural baseline within an exact-height box. */
|
|
823
|
+
readonly preserveExactBaseline?: true;
|
|
824
|
+
/**
|
|
825
|
+
* Active section line-grid pitch in points (`w:docGrid/@w:linePitch`). Present only when
|
|
826
|
+
* the paragraph snaps to the grid; only with `auto`. See `line-grid.ts`.
|
|
827
|
+
*/
|
|
828
|
+
readonly gridPitch?: number;
|
|
810
829
|
}
|
|
830
|
+
/** Single spacing: what a paragraph that says nothing gets. */
|
|
831
|
+
declare const SINGLE_LINE_SPACING: ParagraphLineSpacing;
|
|
811
832
|
/**
|
|
812
|
-
*
|
|
833
|
+
* One resolved `w:pBdr` edge: its style, colour, thickness and gap.
|
|
813
834
|
*
|
|
814
|
-
* `
|
|
815
|
-
*
|
|
835
|
+
* `widthPt` and `spacePt` are already converted and CLAMPED — both come from a file, and an
|
|
836
|
+
* unbounded border width becomes a layout dimension.
|
|
816
837
|
*/
|
|
817
|
-
interface
|
|
818
|
-
|
|
819
|
-
readonly
|
|
820
|
-
|
|
821
|
-
readonly
|
|
822
|
-
|
|
823
|
-
readonly
|
|
838
|
+
interface ParagraphBorderEdge {
|
|
839
|
+
/** Authored `ST_Border` value (`single`, `dashed`, …). */
|
|
840
|
+
readonly val: string;
|
|
841
|
+
/** RRGGBB, or null when auto/missing (paint defaults to black). */
|
|
842
|
+
readonly color: string | null;
|
|
843
|
+
/** Border thickness in points (`w:sz` is eighths of a point). */
|
|
844
|
+
readonly widthPt: number;
|
|
845
|
+
/** Gap from text to the rule, in points (`w:space`). */
|
|
846
|
+
readonly spacePt: number;
|
|
847
|
+
/**
|
|
848
|
+
* `w:shadow` — Word offsets a drop shadow behind the rule.
|
|
849
|
+
*
|
|
850
|
+
* Present only when authored true, so an edge that says nothing keeps the shape earlier
|
|
851
|
+
* fixtures assert. Resolved and carried; drawing it is deferred.
|
|
852
|
+
*/
|
|
853
|
+
readonly shadow?: true;
|
|
824
854
|
}
|
|
855
|
+
/** The six `CT_PBdr` children, in schema order (ECMA-376 §17.3.1.24). */
|
|
856
|
+
declare const PARAGRAPH_BORDER_SIDES: readonly ["top", "left", "bottom", "right", "between", "bar"];
|
|
825
857
|
/**
|
|
826
|
-
*
|
|
858
|
+
* Which of the six `CT_PBdr` edges.
|
|
827
859
|
*
|
|
828
|
-
*
|
|
829
|
-
*
|
|
830
|
-
* fire once rather than per call.
|
|
860
|
+
* Four are physical box edges; `between` and `bar` are group-relative, drawn only where
|
|
861
|
+
* consecutive paragraphs share a border definition.
|
|
831
862
|
*/
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
863
|
+
type ParagraphBorderSide = (typeof PARAGRAPH_BORDER_SIDES)[number];
|
|
864
|
+
/**
|
|
865
|
+
* A paragraph's resolved `w:pBdr` (ECMA-376 §17.3.1.24).
|
|
866
|
+
*
|
|
867
|
+
* `top`/`left`/`bottom`/`right` are the four physical edges of the box. The other two are
|
|
868
|
+
* group-relative: `between` draws at a boundary INSIDE a run of consecutive paragraphs whose
|
|
869
|
+
* border settings are identical, and `bar` is the vertical change-bar rule beside the
|
|
870
|
+
* paragraph, drawn whether or not the paragraph groups with its neighbours.
|
|
871
|
+
*/
|
|
872
|
+
interface ParagraphBorders {
|
|
873
|
+
readonly top?: ParagraphBorderEdge;
|
|
874
|
+
readonly left?: ParagraphBorderEdge;
|
|
875
|
+
readonly bottom?: ParagraphBorderEdge;
|
|
876
|
+
readonly right?: ParagraphBorderEdge;
|
|
877
|
+
readonly between?: ParagraphBorderEdge;
|
|
878
|
+
readonly bar?: ParagraphBorderEdge;
|
|
837
879
|
}
|
|
838
880
|
/**
|
|
839
|
-
*
|
|
881
|
+
* Resolve `w:spacing` before/after from flat paragraph properties.
|
|
882
|
+
*
|
|
883
|
+
* Line spacing (`w:line` / `w:lineRule`) is a separate concern — it changes measured line
|
|
884
|
+
* height, not the gap between paragraphs — and is not resolved here.
|
|
885
|
+
*
|
|
886
|
+
* `w:beforeAutospacing` / `w:afterAutospacing` REPLACE the authored measurement on their own
|
|
887
|
+
* side rather than adding to it; see {@link AUTO_PARAGRAPH_SPACING_PT}.
|
|
888
|
+
*/
|
|
889
|
+
declare function paragraphSpacing(props: readonly OoxmlProperty[], context?: ParagraphAutoSpacingContext): ParagraphSpacing;
|
|
890
|
+
/**
|
|
891
|
+
* Resolve `w:line` / `w:lineRule` from flat paragraph properties.
|
|
840
892
|
*
|
|
841
|
-
*
|
|
842
|
-
*
|
|
893
|
+
* Merged per attribute for the same reason as before/after: `w:spacing` is one element
|
|
894
|
+
* carrying independent attributes, and a style that states only `@line` must not reset the
|
|
895
|
+
* rule an earlier entry in the cascade set.
|
|
843
896
|
*/
|
|
844
|
-
declare
|
|
845
|
-
/** Bounded minimum sfnt/TTC check; Task 4 supplies full parser-backed validation. */
|
|
846
|
-
declare const boundedStructuralFontValidator: FontByteValidator;
|
|
897
|
+
declare function paragraphLineSpacing(props: readonly OoxmlProperty[]): ParagraphLineSpacing;
|
|
847
898
|
/**
|
|
848
|
-
*
|
|
899
|
+
* Apply resolved line spacing to a line's natural (glyph-derived) box.
|
|
849
900
|
*
|
|
850
|
-
*
|
|
851
|
-
*
|
|
852
|
-
*
|
|
853
|
-
*
|
|
901
|
+
* `auto` places its extra BELOW the line — the last line's multiple spacing still separates
|
|
902
|
+
* it from the next paragraph. Putting that delta above inverted cover-page rhythm:
|
|
903
|
+
* `w:line="460"` on "between" opened a large gap above the word and almost none before
|
|
904
|
+
* "MERIDIAN".
|
|
905
|
+
*
|
|
906
|
+
* `atLeast` does the OPPOSITE: the box grows upward and the glyphs sit on its floor. A
|
|
907
|
+
* captured control settles it — Times New Roman 12 pt at `w:line="360" w:lineRule="atLeast"`
|
|
908
|
+
* puts the reference's baseline at 15.36 pt, which is `18 - descent` snapped to the device
|
|
909
|
+
* grid, where treating it like `auto` leaves the baseline at 11.28 and the text 4.08 pt too
|
|
910
|
+
* high. `w:line="240" atLeast` is below the natural line, falls through to the natural
|
|
911
|
+
* height, and is unaffected. See `.cache/pdf/claude-linerule/`.
|
|
912
|
+
*
|
|
913
|
+
* Exact-height boxes place their baseline at 80% of the height; the legacy
|
|
914
|
+
* noExtraLineSpacing switch instead preserves the face baseline within the box.
|
|
915
|
+
*
|
|
916
|
+
* An `auto` line of a snapping paragraph under an active line grid takes whole pitches
|
|
917
|
+
* instead ({@link gridLineBox}); `trailing` then names the extra below the grid line.
|
|
854
918
|
*/
|
|
855
|
-
declare
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
type FixedPoint = number & {
|
|
860
|
-
readonly [FIXED_POINT]: true;
|
|
919
|
+
declare function applyLineSpacing(spacing: ParagraphLineSpacing, naturalHeight: number, naturalBaseline: number): {
|
|
920
|
+
height: number;
|
|
921
|
+
baseline: number;
|
|
922
|
+
trailing?: number;
|
|
861
923
|
};
|
|
862
924
|
/**
|
|
863
|
-
*
|
|
864
|
-
*
|
|
865
|
-
*
|
|
866
|
-
* EQUAL — float accumulation would make the same text measure differently depending on how it was
|
|
867
|
-
* split, and pagination is decided on those measurements.
|
|
868
|
-
*
|
|
869
|
-
* @throws RangeError when the value is not a safe integer.
|
|
925
|
+
* `w:contextualSpacing` (17.3.1.9): drop before/after between paragraphs of the SAME
|
|
926
|
+
* style. Word's built-in `ListParagraph` sets it, so every list authored in Word gets a
|
|
927
|
+
* paragraph gap between items without this.
|
|
870
928
|
*/
|
|
871
|
-
declare
|
|
872
|
-
/** Which way a run reads. The parity projection of its bidi embedding level. */
|
|
873
|
-
type TextDirection = 'ltr' | 'rtl';
|
|
874
|
-
/** How fixed-point conversion breaks ties. Part of the shaping fingerprint. */
|
|
875
|
-
type FixedPointRoundingMode = 'halfAwayFromZero' | 'halfToEven' | 'towardZero';
|
|
876
|
-
/** Which Unicode normalization is applied before shaping, if any. */
|
|
877
|
-
type NormalizationPolicy = 'none' | 'NFC' | 'NFD' | 'NFKC' | 'NFKD';
|
|
929
|
+
declare function paragraphContextualSpacing(props: readonly OoxmlProperty[]): boolean;
|
|
878
930
|
/**
|
|
879
|
-
*
|
|
931
|
+
* Resolve `w:pBdr` from the paragraph-properties node.
|
|
880
932
|
*
|
|
881
|
-
*
|
|
882
|
-
*
|
|
933
|
+
* Nested — every edge is a child of `pBdr`, not an attribute — so this reads the typed tree
|
|
934
|
+
* rather than the flattened `OoxmlProperty[]` bag `propertiesOf` builds for leaf props.
|
|
883
935
|
*/
|
|
884
|
-
|
|
885
|
-
readonly name: string;
|
|
886
|
-
readonly version: string;
|
|
887
|
-
}
|
|
936
|
+
declare function paragraphBorders(pPr: OoxmlNode | undefined): ParagraphBorders;
|
|
888
937
|
/**
|
|
889
|
-
*
|
|
890
|
-
* {@link ShapingEnvironment}.
|
|
938
|
+
* `w:pBdr` after the style cascade: a later `w:pBdr` replaces an earlier one WHOLESALE.
|
|
891
939
|
*
|
|
892
|
-
*
|
|
893
|
-
*
|
|
940
|
+
* Word does not merge edges across the cascade. A style that states only `w:bottom` discards
|
|
941
|
+
* the box its `basedOn` ancestor declared, so folding edge by edge would leave a lone
|
|
942
|
+
* underline surrounded by a box no one authored. Absence inherits; `nil`/`none` clear.
|
|
894
943
|
*/
|
|
895
|
-
|
|
896
|
-
readonly font: ResolvedFont;
|
|
897
|
-
readonly variationAxes: Readonly<Record<string, number>>;
|
|
898
|
-
readonly shapingLibrary: VersionedShapingLibrary;
|
|
899
|
-
readonly unicodeDataVersion: string;
|
|
900
|
-
readonly normalization: NormalizationPolicy;
|
|
901
|
-
readonly script: string;
|
|
902
|
-
readonly language: string;
|
|
903
|
-
readonly direction: TextDirection;
|
|
904
|
-
readonly features: Readonly<Record<string, number>>;
|
|
905
|
-
readonly fallbackOrder: readonly ResolvedFont[];
|
|
906
|
-
readonly fixedPointScale: number;
|
|
907
|
-
readonly roundingMode: FixedPointRoundingMode;
|
|
908
|
-
}
|
|
944
|
+
declare function cascadedParagraphBorders(paragraphPropertyNodes: readonly OoxmlNode[]): ParagraphBorders;
|
|
909
945
|
/**
|
|
910
|
-
*
|
|
946
|
+
* Visual stroke thickness layout publishes for one edge (points).
|
|
911
947
|
*
|
|
912
|
-
*
|
|
913
|
-
*
|
|
948
|
+
* Compound `ST_Border` values (`double`, …) use the shared inflated band so a thin
|
|
949
|
+
* `w:sz="3"` double still occupies a visible double-line box — matching table borders.
|
|
914
950
|
*/
|
|
915
|
-
|
|
916
|
-
}
|
|
917
|
-
/** One shaping call: the text, its size, its bidi level, and the environment to shape it in. */
|
|
918
|
-
interface ShapeInput {
|
|
919
|
-
readonly text: string;
|
|
920
|
-
readonly fontSizeHalfPoints: number;
|
|
921
|
-
/** Exact UAX #9 embedding/isolate level; direction is its parity projection. */
|
|
922
|
-
readonly bidiLevel: number;
|
|
923
|
-
readonly environment: ShapingEnvironment;
|
|
924
|
-
}
|
|
951
|
+
declare function paragraphBorderStrokeWidthPt(edge: ParagraphBorderEdge): number;
|
|
925
952
|
/**
|
|
926
|
-
*
|
|
953
|
+
* Extent one border edge occupies away from the text it decorates: gap plus rule, in points.
|
|
927
954
|
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
930
|
-
* text
|
|
955
|
+
* Vertically that is flow height — a top rule pushes the first line down, a bottom rule holds
|
|
956
|
+
* the page open below the last one — so pagination has to see it. Horizontally it is
|
|
957
|
+
* publish-only: Word draws left/right paragraph rules OUTSIDE the text column and never
|
|
958
|
+
* re-breaks the lines, which is why adding a box to a paragraph in Word does not reflow it.
|
|
931
959
|
*/
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
readonly drawScale?: number;
|
|
936
|
-
/** UTF-16 text offset identifying the cluster that produced this glyph. */
|
|
937
|
-
readonly cluster: number;
|
|
938
|
-
/** Pen origin before this glyph's shaping offsets, in fixed-point run coordinates. */
|
|
939
|
-
readonly originX: FixedPoint;
|
|
940
|
-
readonly originY: FixedPoint;
|
|
941
|
-
readonly advanceX: FixedPoint;
|
|
942
|
-
readonly advanceY: FixedPoint;
|
|
943
|
-
readonly offsetX: FixedPoint;
|
|
944
|
-
readonly offsetY: FixedPoint;
|
|
945
|
-
/** Exact monochrome outline returned by the admitted HarfBuzz face. */
|
|
946
|
-
readonly outline: GlyphOutline;
|
|
947
|
-
}
|
|
948
|
-
/** A glyph's outline as SVG path data, in font design units. */
|
|
949
|
-
interface GlyphOutline {
|
|
950
|
-
readonly path: string;
|
|
951
|
-
/** Design units per em — divide by this to scale the path to a point size. */
|
|
952
|
-
readonly unitsPerEm: number;
|
|
953
|
-
}
|
|
960
|
+
declare function paragraphBorderExtentPt(edge: ParagraphBorderEdge | undefined): number;
|
|
961
|
+
/** Vertical extent a bottom border adds below the last line (gap + rule). */
|
|
962
|
+
declare function bottomBorderExtentPt(edge: ParagraphBorderEdge | undefined): number;
|
|
954
963
|
/**
|
|
955
|
-
*
|
|
964
|
+
* Identity of a paragraph's border set, for the `w:between` group rule.
|
|
956
965
|
*
|
|
957
|
-
*
|
|
958
|
-
*
|
|
959
|
-
* `
|
|
966
|
+
* Word treats consecutive paragraphs whose border settings are IDENTICAL as ONE bordered
|
|
967
|
+
* block: the top rule draws above the first, the bottom rule below the last, and each
|
|
968
|
+
* interior boundary gets `w:between` or nothing (§17.3.1.24). That is why applying a box to
|
|
969
|
+
* three selected paragraphs in Word draws one box and not three.
|
|
970
|
+
*
|
|
971
|
+
* Empty string means "no borders", which never groups with anything.
|
|
960
972
|
*/
|
|
961
|
-
|
|
962
|
-
/** Half-open logical UTF-16 range in ShapedRun.text. */
|
|
963
|
-
readonly textStart: number;
|
|
964
|
-
readonly textEnd: number;
|
|
965
|
-
/** Half-open visual glyph range in ShapedRun.glyphs. */
|
|
966
|
-
readonly glyphStart: number;
|
|
967
|
-
readonly glyphEnd: number;
|
|
968
|
-
readonly advance: FixedPoint;
|
|
969
|
-
/** Fixed-point edges from this cluster's visual origin, including both endpoints. */
|
|
970
|
-
readonly caretEdges: readonly FixedPoint[];
|
|
971
|
-
/** Index into ShapedRun.fontSpans, preserving the exact fallback choice. */
|
|
972
|
-
readonly fontSpan: number;
|
|
973
|
-
}
|
|
974
|
-
/** A run's vertical metrics, from the face that shaped it. Drives line height and baseline. */
|
|
975
|
-
interface ShapedVerticalMetrics {
|
|
976
|
-
readonly ascent: FixedPoint;
|
|
977
|
-
readonly descent: FixedPoint;
|
|
978
|
-
readonly lineGap: FixedPoint;
|
|
979
|
-
}
|
|
973
|
+
declare function paragraphBordersFingerprint(borders: ParagraphBorders): string;
|
|
980
974
|
/**
|
|
981
|
-
*
|
|
975
|
+
* Gap to insert before a paragraph once the previous paragraph's `after` is already in the
|
|
976
|
+
* flow cursor — Word takes the larger of the two rather than summing them.
|
|
977
|
+
*/
|
|
978
|
+
declare function collapsedSpaceBefore(before: number, previousAfter: number): number;
|
|
979
|
+
/**
|
|
980
|
+
* Applied before-spacing for placement (Word 2013+ / compat mode 15).
|
|
982
981
|
*
|
|
983
|
-
*
|
|
984
|
-
*
|
|
985
|
-
*
|
|
982
|
+
* Adjacent before/after still collapse to the larger gap, but before is dropped entirely when
|
|
983
|
+
* the paragraph naturally moves to the top of a page mid-section. An explicit page-break-before
|
|
984
|
+
* paragraph, or the first paragraph of a document/section, retains before. Callers publish this
|
|
985
|
+
* applied value on the fragment so shading, borders,
|
|
986
|
+
* selection, and paint share one geometry.
|
|
986
987
|
*/
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
988
|
+
declare function appliedSpaceBefore(before: number, previousAfter: number, atTopOfPage: boolean, preserveAtPageStart: boolean): number;
|
|
989
|
+
|
|
990
|
+
/** `w:vertAlign` — script position, which also scales the run's effective size. */
|
|
991
|
+
type VerticalAlign = 'baseline' | 'superscript' | 'subscript';
|
|
992
|
+
/** A resolved underline: its variant, and its colour when it does not follow the text. */
|
|
993
|
+
interface ResolvedUnderline {
|
|
994
|
+
/** The authored `ST_Underline` variant. */
|
|
995
|
+
readonly variant: string;
|
|
996
|
+
/** RRGGBB, or null when the underline follows the text colour. */
|
|
997
|
+
readonly color: string | null;
|
|
993
998
|
}
|
|
994
999
|
/**
|
|
995
|
-
*
|
|
996
|
-
* it, and put a caret in it.
|
|
1000
|
+
* A run's character properties after the full cascade, in the units layout works in.
|
|
997
1001
|
*
|
|
998
|
-
*
|
|
1002
|
+
* Points rather than half-points, RRGGBB rather than theme references — everything already
|
|
1003
|
+
* resolved, so measurement and paint never re-run the cascade per glyph.
|
|
999
1004
|
*/
|
|
1000
|
-
interface
|
|
1001
|
-
readonly
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1005
|
+
interface ResolvedRunStyle {
|
|
1006
|
+
readonly fontFamily: string | null;
|
|
1007
|
+
/**
|
|
1008
|
+
* The `eastAsia` slot's typeface (`w:rFonts w:eastAsia`/`w:eastAsiaTheme`), or null when
|
|
1009
|
+
* no level authors one.
|
|
1010
|
+
*
|
|
1011
|
+
* OOXML picks a run's face per SCRIPT: `fontFamily` covers the ascii/hAnsi slots, and
|
|
1012
|
+
* ideographic/kana/hangul text resolves through this one instead. Kept beside — not
|
|
1013
|
+
* folded into — `fontFamily`, because a mixed run needs both at once and the split into
|
|
1014
|
+
* slot-homogeneous pieces happens downstream (`piecesOfParagraph`).
|
|
1015
|
+
*/
|
|
1016
|
+
readonly fontFamilyEastAsia: string | null;
|
|
1017
|
+
/**
|
|
1018
|
+
* Present only on a `w:rtl` or `w:cs` run: the LATIN lane that the complex-script values
|
|
1019
|
+
* replaced in `fontFamily`, `fontSizePt`, `bold` and `italic`. Nothing draws with it; it
|
|
1020
|
+
* lets a copy of the formatting (the format painter) write each lane back separately.
|
|
1021
|
+
*/
|
|
1022
|
+
readonly latinLane?: {
|
|
1023
|
+
readonly fontFamily: string | null;
|
|
1024
|
+
readonly fontFamilyEastAsia: string | null;
|
|
1025
|
+
readonly fontSizePt: number;
|
|
1026
|
+
readonly bold: boolean;
|
|
1027
|
+
readonly italic: boolean;
|
|
1028
|
+
};
|
|
1029
|
+
/**
|
|
1030
|
+
* The complex-script lane as the cascade states it, on every resolved run: the values a
|
|
1031
|
+
* `w:rtl` or `w:cs` run draws with, and what a copy of the formatting writes to `w:bCs`,
|
|
1032
|
+
* `w:iCs`, `w:szCs` and `w:rFonts/@w:cs`. `fontFamily` is null when no level names a face.
|
|
1033
|
+
*/
|
|
1034
|
+
readonly complexLane?: {
|
|
1035
|
+
readonly fontFamily: string | null;
|
|
1036
|
+
readonly fontSizePt: number;
|
|
1037
|
+
readonly bold: boolean;
|
|
1038
|
+
readonly italic: boolean;
|
|
1039
|
+
};
|
|
1040
|
+
/** Script and paragraph-resolved direction for shaping and visual placement. */
|
|
1041
|
+
readonly shaping?: {
|
|
1042
|
+
readonly script: string;
|
|
1043
|
+
readonly direction: 'ltr' | 'rtl';
|
|
1044
|
+
readonly level: number;
|
|
1045
|
+
readonly baseLevel: number;
|
|
1046
|
+
/** Resolved w:rtl context; absent when authored Unicode controls govern the paragraph. */
|
|
1047
|
+
readonly runDirection?: 'ltr' | 'rtl';
|
|
1048
|
+
readonly wordSpacingPt?: number;
|
|
1049
|
+
/** Neighbouring text a joining script reads across a formatting-run boundary. */
|
|
1050
|
+
readonly context?: ShapingContext;
|
|
1051
|
+
};
|
|
1052
|
+
/** Points. `w:sz` is half-points, so 22 becomes 11. */
|
|
1053
|
+
readonly fontSizePt: number;
|
|
1054
|
+
/** RRGGBB, or null for the inherited/automatic colour. */
|
|
1055
|
+
readonly color: string | null;
|
|
1056
|
+
readonly bold: boolean;
|
|
1057
|
+
/** Opaque solid `w14:textOutline`, in points; paint only, never a font-weight change. */
|
|
1058
|
+
readonly textOutline?: {
|
|
1059
|
+
readonly widthPt: number;
|
|
1060
|
+
readonly color: string;
|
|
1061
|
+
};
|
|
1062
|
+
/** Character border; adjacent runs with matching edges share one outline. */
|
|
1063
|
+
readonly border?: ParagraphBorderEdge;
|
|
1064
|
+
readonly italic: boolean;
|
|
1065
|
+
readonly underline: ResolvedUnderline | null;
|
|
1066
|
+
readonly strike: boolean;
|
|
1067
|
+
readonly doubleStrike: boolean;
|
|
1068
|
+
/** An `ST_HighlightColor` name, or null. */
|
|
1069
|
+
readonly highlight: string | null;
|
|
1008
1070
|
/**
|
|
1009
|
-
*
|
|
1010
|
-
* BEFORE the per-glyph rounding to the fixed-point grid. Parallel to `glyphs`.
|
|
1071
|
+
* Character shading fill (`w:rPr/w:shd`), validated RRGGBB, or null.
|
|
1011
1072
|
*
|
|
1012
|
-
*
|
|
1013
|
-
*
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1073
|
+
* Paint applies this as the glyph-box background; a recognised highlight overrides it.
|
|
1074
|
+
* Measurement ignores shading.
|
|
1075
|
+
*/
|
|
1076
|
+
readonly shading: string | null;
|
|
1077
|
+
readonly verticalAlign: VerticalAlign;
|
|
1078
|
+
/** `w:position`, in points. Positive raises the baseline. */
|
|
1079
|
+
readonly baselineShiftPt: number;
|
|
1080
|
+
readonly caps: boolean;
|
|
1081
|
+
readonly smallCaps: boolean;
|
|
1082
|
+
/** `w:spacing`, in points. Added to every advance. */
|
|
1083
|
+
readonly characterSpacingPt: number;
|
|
1084
|
+
/** `w:w`, as a percentage. 100 is unscaled. */
|
|
1085
|
+
readonly horizontalScalePercent: number;
|
|
1086
|
+
/** `w:kern`, in points: the size at or above which kerning applies. */
|
|
1087
|
+
readonly kerningMinPt: number;
|
|
1088
|
+
/** Explicit kerning selection; a zero threshold disables it. Absent uses a positive threshold. */
|
|
1089
|
+
readonly kerningEnabled?: boolean;
|
|
1090
|
+
/** Resolved optional OpenType substitutions; required script ligatures are independent. */
|
|
1091
|
+
readonly ligatures?: {
|
|
1092
|
+
readonly standard: boolean;
|
|
1093
|
+
readonly contextual: boolean;
|
|
1094
|
+
readonly historical: boolean;
|
|
1095
|
+
readonly discretionary: boolean;
|
|
1096
|
+
};
|
|
1097
|
+
/**
|
|
1098
|
+
* `w:vanish` (ECMA-376 §17.3.2.45): the run is hidden text.
|
|
1017
1099
|
*
|
|
1018
|
-
*
|
|
1100
|
+
* Word does not draw it AND does not paginate it — hidden index or comment text takes no
|
|
1101
|
+
* space at all. So this cannot be a paint-time opacity: a hidden run that is still measured
|
|
1102
|
+
* pushes every following line, and every following page break, to the wrong place. Layout
|
|
1103
|
+
* drops the content instead (see `piecesOfParagraph`).
|
|
1104
|
+
*
|
|
1105
|
+
* `w:specVanish` (§17.3.2.36) is a different property — an always-hidden paragraph mark on
|
|
1106
|
+
* a heading — and never sets this.
|
|
1019
1107
|
*/
|
|
1020
|
-
readonly
|
|
1021
|
-
}
|
|
1022
|
-
/**
|
|
1023
|
-
* A {@link ShapedRun} reduced to the fields two shaping results must agree on to be considered
|
|
1024
|
-
* identical.
|
|
1025
|
-
*
|
|
1026
|
-
* Fonts appear as {@link FontFingerprintInputs} rather than whole `ResolvedFont` objects, so the
|
|
1027
|
-
* comparison is over VALUES and does not depend on object identity — which is what makes it work
|
|
1028
|
-
* across a reload or a worker boundary.
|
|
1029
|
-
*/
|
|
1030
|
-
interface ShapedRunComparatorInputs {
|
|
1031
|
-
readonly text: string;
|
|
1032
|
-
readonly direction: TextDirection;
|
|
1033
|
-
readonly script: string;
|
|
1034
|
-
readonly language: string;
|
|
1035
|
-
readonly bidiLevel: number;
|
|
1036
|
-
readonly glyphs: readonly ShapedGlyph[];
|
|
1037
|
-
readonly clusters: readonly ShapedCluster[];
|
|
1038
|
-
readonly fontSpans: readonly {
|
|
1039
|
-
readonly glyphStart: number;
|
|
1040
|
-
readonly glyphEnd: number;
|
|
1041
|
-
readonly fallbackIndex: number | null;
|
|
1042
|
-
readonly font: FontFingerprintInputs;
|
|
1043
|
-
}[];
|
|
1044
|
-
readonly metrics: ShapedVerticalMetrics;
|
|
1108
|
+
readonly hidden: boolean;
|
|
1045
1109
|
}
|
|
1110
|
+
/** The style a run inherits when it authors nothing. */
|
|
1111
|
+
declare const DEFAULT_RUN_STYLE: ResolvedRunStyle;
|
|
1046
1112
|
/**
|
|
1047
|
-
* The
|
|
1113
|
+
* The theme part's typefaces, for resolving `w:rFonts` theme attributes.
|
|
1048
1114
|
*
|
|
1049
|
-
*
|
|
1050
|
-
*
|
|
1051
|
-
* layout cannot tell the difference.
|
|
1115
|
+
* Structurally identical to the binding lane's `DocumentThemeFonts` and assignable from it.
|
|
1116
|
+
* Declared here so this lane reads validated strings rather than the theme tree.
|
|
1052
1117
|
*/
|
|
1053
|
-
interface
|
|
1054
|
-
|
|
1118
|
+
interface ThemeFonts {
|
|
1119
|
+
/** `a:majorFont` latin typeface — headings. */
|
|
1120
|
+
readonly major: string | null;
|
|
1121
|
+
/** `a:minorFont` latin typeface — body text. */
|
|
1122
|
+
readonly minor: string | null;
|
|
1123
|
+
/** `a:majorFont` east asian typeface (`a:ea`) — headings. Optional for back-compat. */
|
|
1124
|
+
readonly majorEastAsia?: string | null;
|
|
1125
|
+
/** `a:minorFont` east asian typeface (`a:ea`) — body text. Optional for back-compat. */
|
|
1126
|
+
readonly minorEastAsia?: string | null;
|
|
1127
|
+
/** Complex-script heading and body theme faces. */
|
|
1128
|
+
readonly majorBidi?: string | null;
|
|
1129
|
+
readonly minorBidi?: string | null;
|
|
1130
|
+
/** Language-specific theme faces, keyed by ISO 15924 script. */
|
|
1131
|
+
readonly majorSupplemental?: Readonly<Record<string, string>>;
|
|
1132
|
+
readonly minorSupplemental?: Readonly<Record<string, string>>;
|
|
1055
1133
|
}
|
|
1056
1134
|
/**
|
|
1057
|
-
*
|
|
1135
|
+
* Resolve one run's direct formatting.
|
|
1058
1136
|
*
|
|
1059
|
-
*
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1062
|
-
*/
|
|
1063
|
-
interface FontFingerprintInputs {
|
|
1064
|
-
readonly identity: string;
|
|
1065
|
-
readonly id: string;
|
|
1066
|
-
readonly family: string;
|
|
1067
|
-
readonly request: FontRequest;
|
|
1068
|
-
readonly hash: string;
|
|
1069
|
-
readonly faceIndex: number;
|
|
1070
|
-
readonly byteLength: number;
|
|
1071
|
-
readonly substitution: FontSubstitution | null;
|
|
1072
|
-
}
|
|
1073
|
-
/**
|
|
1074
|
-
* A {@link ShapingEnvironment} reduced to comparable values.
|
|
1137
|
+
* Unrecognised values are DROPPED rather than guessed: a `w:sz` of `"large"` leaves the
|
|
1138
|
+
* default size rather than inventing one, because a wrong measurement moves every glyph
|
|
1139
|
+
* after it and a missing one is visible immediately.
|
|
1075
1140
|
*
|
|
1076
|
-
*
|
|
1077
|
-
*
|
|
1078
|
-
*
|
|
1141
|
+
* `themeFonts` resolves `w:rFonts` theme references. Absent, a theme-only `rFonts` leaves
|
|
1142
|
+
* the family inherited — which is what every run of a theme-fonted document does, so the
|
|
1143
|
+
* whole document falls back to the surface default face.
|
|
1079
1144
|
*/
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
readonly language: string;
|
|
1088
|
-
readonly direction: TextDirection;
|
|
1089
|
-
readonly features: readonly (readonly [string, number])[];
|
|
1090
|
-
readonly fallbackOrder: readonly FontFingerprintInputs[];
|
|
1091
|
-
readonly fixedPointScale: number;
|
|
1092
|
-
readonly roundingMode: FixedPointRoundingMode;
|
|
1093
|
-
}
|
|
1145
|
+
declare function resolveRunStyle(props: readonly OoxmlProperty[], themeFonts?: ThemeFonts): ResolvedRunStyle;
|
|
1146
|
+
/** The text as it is DRAWN, after case transforms. Measurement must use this, not the source. */
|
|
1147
|
+
declare function displayText(text: string, style: ResolvedRunStyle): string;
|
|
1148
|
+
/** Measure run text the way layout breaks lines and paints glyphs (caps/small-caps aware). */
|
|
1149
|
+
declare function measureDisplayText(text: string, style: ResolvedRunStyle, measurer: TextMeasurer): number;
|
|
1150
|
+
/** Whether two resolved styles are identical, for span merging and cache keys. */
|
|
1151
|
+
declare function runStylesEqual(a: ResolvedRunStyle, b: ResolvedRunStyle): boolean;
|
|
1094
1152
|
/**
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
1097
|
-
* Checks every field that could silently corrupt a measurement: OpenType tags must be four ASCII
|
|
1098
|
-
* bytes, script and language must be non-blank and control-character free, fonts must already be
|
|
1099
|
-
* validated. Throws rather than coercing — a bad tag that shapes anyway produces a document that
|
|
1100
|
-
* measures wrong everywhere and looks fine.
|
|
1153
|
+
* How far a run's glyphs are lifted off the line's baseline, in points. Positive is up.
|
|
1101
1154
|
*
|
|
1102
|
-
*
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
/**
|
|
1106
|
-
* Reduce an environment to its comparable form, with records sorted so key order cannot affect
|
|
1107
|
-
* the result.
|
|
1155
|
+
* Super and subscript move the GLYPHS without moving the run's box, so the box keeps tiling
|
|
1156
|
+
* the line and the selection band stays continuous. Anything drawing at the glyphs — the
|
|
1157
|
+
* painter, and the caret — has to apply this itself, and from one place, or the two drift.
|
|
1108
1158
|
*/
|
|
1109
|
-
declare
|
|
1110
|
-
/** Canonical serialization of every shaping variable, including byte hash and provenance. */
|
|
1111
|
-
declare const shapingEnvironmentFingerprint: (environment: ShapingEnvironmentInput) => string;
|
|
1159
|
+
declare function baselineShiftPtOf(style: ResolvedRunStyle): number;
|
|
1112
1160
|
/**
|
|
1113
|
-
*
|
|
1114
|
-
*
|
|
1115
|
-
* Checks the internal consistency a shaper must satisfy: direction matches the environment,
|
|
1116
|
-
* cluster ranges tile the text without gaps or overlap, glyph ranges stay in bounds, font spans
|
|
1117
|
-
* cover every glyph, and caret edges are monotonic. A shaper that violates any of these produces
|
|
1118
|
-
* a caret that lands in the wrong place, which is far harder to diagnose downstream than here.
|
|
1161
|
+
* Shared glyph-size factor for baseline, superscript, and subscript text.
|
|
1119
1162
|
*
|
|
1120
|
-
*
|
|
1163
|
+
* The 65% script scale follows the common Word font metrics (Arial, Calibri, Times New
|
|
1164
|
+
* Roman) and improves the saved Word reference at 10pt and 11pt. It is a uniform policy;
|
|
1165
|
+
* per-face script metrics and Word's output-device rounding are not modeled here.
|
|
1166
|
+
* Layout, surface paint, and exporters must apply the same factor to avoid caret drift.
|
|
1167
|
+
* @public
|
|
1121
1168
|
*/
|
|
1122
|
-
declare
|
|
1169
|
+
declare function glyphSizeFactorOf(style: ResolvedRunStyle): number;
|
|
1170
|
+
|
|
1123
1171
|
/**
|
|
1124
|
-
*
|
|
1172
|
+
* UAX #9 embedding levels, one per UTF-16 code unit, plus the paragraph ranges they were resolved
|
|
1173
|
+
* within.
|
|
1125
1174
|
*
|
|
1126
|
-
*
|
|
1127
|
-
*
|
|
1175
|
+
* The level is EXACT, not a direction: its parity gives direction, but the numeric value is what
|
|
1176
|
+
* reordering needs, and collapsing it early loses nested isolates.
|
|
1128
1177
|
*/
|
|
1129
|
-
|
|
1178
|
+
interface BidiEmbeddingLevels {
|
|
1179
|
+
readonly levels: Uint8Array;
|
|
1180
|
+
readonly paragraphs: readonly {
|
|
1181
|
+
readonly start: number;
|
|
1182
|
+
readonly end: number;
|
|
1183
|
+
readonly level: number;
|
|
1184
|
+
}[];
|
|
1185
|
+
}
|
|
1130
1186
|
|
|
1131
1187
|
/**
|
|
1132
1188
|
* Which `w:rFonts` slot a character resolves its face through.
|
|
@@ -1180,6 +1236,27 @@ declare function itemizeScriptFontSlots(text: string, paragraphOffset: number, e
|
|
|
1180
1236
|
*/
|
|
1181
1237
|
declare function styleForFontSlot(style: ResolvedRunStyle, slot: FontSlot | undefined): ResolvedRunStyle;
|
|
1182
1238
|
|
|
1239
|
+
type AllowlistedPageField = 'PAGE' | 'NUMPAGES' | 'SECTIONPAGES';
|
|
1240
|
+
/**
|
|
1241
|
+
* Which allowlisted page fields a header/footer story actually contains.
|
|
1242
|
+
*
|
|
1243
|
+
* Drives layout reuse: no fields → one baseline; NUMPAGES only → one layout per page count;
|
|
1244
|
+
* SECTIONPAGES only → one layout per section page count; PAGE (alone or combined) → per
|
|
1245
|
+
* distinct evaluated values with a bounded cache. Counts both complex markers and
|
|
1246
|
+
* `w:fldSimple` (including an allowlisted page field nested inside a non-page simple field).
|
|
1247
|
+
*/
|
|
1248
|
+
interface StoryPageFieldNeeds {
|
|
1249
|
+
readonly hasPage: boolean;
|
|
1250
|
+
readonly hasNumPages: boolean;
|
|
1251
|
+
readonly hasSectionPages: boolean;
|
|
1252
|
+
/**
|
|
1253
|
+
* The story places something by the physical sheet's parity: a header frame aligned
|
|
1254
|
+
* `inside` or `outside`. Set by the header/footer layout, never by field detection. The
|
|
1255
|
+
* story then lays out once per sheet parity, with or without a page field.
|
|
1256
|
+
*/
|
|
1257
|
+
readonly hasPageParity?: boolean;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1183
1260
|
/**
|
|
1184
1261
|
* One parsed `HYPERLINK` instruction: the raw, unsanitized pieces.
|
|
1185
1262
|
*
|
|
@@ -1304,21 +1381,6 @@ interface RefNoteParts {
|
|
|
1304
1381
|
*/
|
|
1305
1382
|
declare function resolveStoryRefFields(blocks: readonly OoxmlElement[], listItems: ReadonlyMap<string, ResolvedListItem> | undefined, notes?: RefNoteParts): RefFieldContext | null;
|
|
1306
1383
|
|
|
1307
|
-
type AllowlistedPageField = 'PAGE' | 'NUMPAGES' | 'SECTIONPAGES';
|
|
1308
|
-
/**
|
|
1309
|
-
* Which allowlisted page fields a header/footer story actually contains.
|
|
1310
|
-
*
|
|
1311
|
-
* Drives layout reuse: no fields → one baseline; NUMPAGES only → one layout per page count;
|
|
1312
|
-
* SECTIONPAGES only → one layout per section page count; PAGE (alone or combined) → per
|
|
1313
|
-
* distinct evaluated values with a bounded cache. Counts both complex markers and
|
|
1314
|
-
* `w:fldSimple` (including an allowlisted page field nested inside a non-page simple field).
|
|
1315
|
-
*/
|
|
1316
|
-
interface StoryPageFieldNeeds {
|
|
1317
|
-
readonly hasPage: boolean;
|
|
1318
|
-
readonly hasNumPages: boolean;
|
|
1319
|
-
readonly hasSectionPages: boolean;
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
1384
|
/**
|
|
1323
1385
|
* What a piece says about the FIELD result it came from, for Word's shading.
|
|
1324
1386
|
*
|
|
@@ -1454,6 +1516,11 @@ interface TabStop {
|
|
|
1454
1516
|
readonly alignment: TabAlignment;
|
|
1455
1517
|
/** Legacy `num` stop: positions a numbering suffix, not a tab in ordinary text. */
|
|
1456
1518
|
readonly numberingOnly?: true;
|
|
1519
|
+
/**
|
|
1520
|
+
* Supplied at a hanging paragraph's text indent, not authored. It positions ordinary text
|
|
1521
|
+
* tabs only: the numbering suffix treats the indent by its own rule.
|
|
1522
|
+
*/
|
|
1523
|
+
readonly implied?: true;
|
|
1457
1524
|
/** Absent for `none` — the schema default and the overwhelming majority of stops. */
|
|
1458
1525
|
readonly leader?: TabLeader;
|
|
1459
1526
|
}
|
|
@@ -1466,6 +1533,11 @@ interface ResolvedTabStops {
|
|
|
1466
1533
|
readonly stops: readonly TabStop[];
|
|
1467
1534
|
/** Default-tab interval in points (always positive and bounded). */
|
|
1468
1535
|
readonly defaultIntervalPt: number;
|
|
1536
|
+
/**
|
|
1537
|
+
* `w:doNotUseIndentAsNumberingTabStop` (§17.15.3): a numbering suffix tab goes to the
|
|
1538
|
+
* first authored stop past the marker, wherever it is, before it falls back to the indent.
|
|
1539
|
+
*/
|
|
1540
|
+
readonly ignoreIndentAsNumberingTabStop?: true;
|
|
1469
1541
|
}
|
|
1470
1542
|
/** The frozen "no custom stops" value, so a paragraph without tabs mints no object. */
|
|
1471
1543
|
declare const EMPTY_TAB_STOPS: ResolvedTabStops;
|
|
@@ -1778,6 +1850,15 @@ interface TextboxStoryLayout {
|
|
|
1778
1850
|
readonly clippedResourceToken?: string;
|
|
1779
1851
|
}
|
|
1780
1852
|
|
|
1853
|
+
/** How a drawing record holds the picture member of a shape group. */
|
|
1854
|
+
interface DrawingGroupPictureRecord {
|
|
1855
|
+
/**
|
|
1856
|
+
* Whether the group is the chosen branch of a run-level `mc:AlternateContent`. An output
|
|
1857
|
+
* that cannot draw the picture leaves such a group out, as it leaves out other MC content
|
|
1858
|
+
* it cannot draw. A group without it shows the output's unsupported-drawing result.
|
|
1859
|
+
*/
|
|
1860
|
+
readonly alternateContent: boolean;
|
|
1861
|
+
}
|
|
1781
1862
|
interface InlineDrawingRecord {
|
|
1782
1863
|
readonly kind: 'inlineDrawing';
|
|
1783
1864
|
readonly drawingNodeId: string;
|
|
@@ -1812,6 +1893,15 @@ interface InlineDrawingRecord {
|
|
|
1812
1893
|
readonly placeholderGraphicKind: string | null;
|
|
1813
1894
|
/** Typed solid-geometry payload for a renderable `wps:wsp` shape; null otherwise. */
|
|
1814
1895
|
readonly vectorShape: VectorShapeProjection | null;
|
|
1896
|
+
/**
|
|
1897
|
+
* Present when the image is the picture member of a drawing group. The image then fills
|
|
1898
|
+
* the bounds of `geometry.imageTransformCorners`, not `geometry.contentBounds`, and paints
|
|
1899
|
+
* below `vectorShape`, which holds the group's other members. `placeholderGraphicKind`
|
|
1900
|
+
* stays non-null, as for a vector shape, so image commands do not treat the group as a
|
|
1901
|
+
* picture. The group paints whole or not at all: when the picture cannot paint, an output
|
|
1902
|
+
* shows no part of the group.
|
|
1903
|
+
*/
|
|
1904
|
+
readonly groupPicture?: DrawingGroupPictureRecord;
|
|
1815
1905
|
/**
|
|
1816
1906
|
* The revision wrappers enclosing the owning run, outermost first — the same stack spans
|
|
1817
1907
|
* carry, so paint and review chrome give a tracked picture the same cues as tracked text.
|
|
@@ -1930,18 +2020,22 @@ declare function readNumPr(paragraphPropertyNodes: readonly OoxmlNode[]): {
|
|
|
1930
2020
|
*/
|
|
1931
2021
|
declare function withNumberingStyleLinks(index: NumberingIndex, styleCascade: StyleCascadeTable | undefined): NumberingIndex;
|
|
1932
2022
|
/**
|
|
1933
|
-
* The effective indent of a list paragraph:
|
|
2023
|
+
* The effective indent of a list paragraph: `inherited`, then the numbering LEVEL, then
|
|
2024
|
+
* `direct`, per attribute.
|
|
1934
2025
|
*
|
|
1935
|
-
*
|
|
1936
|
-
*
|
|
1937
|
-
*
|
|
1938
|
-
* `
|
|
1939
|
-
* the
|
|
1940
|
-
*
|
|
1941
|
-
*
|
|
2026
|
+
* A level's `w:pPr/w:ind` applies per attribute between the two tiers, and the ordering
|
|
2027
|
+
* matters on real documents. A converted agreement numbers its `(a)` items with a level
|
|
2028
|
+
* stating `left=1512 hanging=738` under a `ListParagraph` style stating
|
|
2029
|
+
* `left=775 hanging=624`, and states only `hanging="737"` on the paragraph itself. Reading
|
|
2030
|
+
* the flattened cascade as "the paragraph's indent" gave the STYLE's 775 to a level that had
|
|
2031
|
+
* overridden it, so every lettered sub-item hung a full indent step to the left of where
|
|
2032
|
+
* Word puts it.
|
|
1942
2033
|
*
|
|
1943
|
-
* `inherited` is the
|
|
1944
|
-
*
|
|
2034
|
+
* `inherited` is what the level outranks and `direct` is what outranks it. When the
|
|
2035
|
+
* paragraph's own `w:pPr` states a `w:numPr`, these are the style chain (after the document
|
|
2036
|
+
* defaults) and that `w:pPr`. Otherwise the level sits directly below the nearest style that
|
|
2037
|
+
* states a `w:numPr`: that style, the styles based on it and the paragraph's own `w:pPr` go
|
|
2038
|
+
* in `direct`, and the defaults and that style's bases go in `inherited`.
|
|
1945
2039
|
*/
|
|
1946
2040
|
declare function mergeListIndent(levelIndent: NumberingLevelIndent, inherited: readonly OoxmlProperty[], direct?: readonly OoxmlProperty[]): NumberingLevelIndent;
|
|
1947
2041
|
/**
|
|
@@ -1976,6 +2070,7 @@ declare function withResolvedListItems<T extends {
|
|
|
1976
2070
|
|
|
1977
2071
|
interface StyleDefinition {
|
|
1978
2072
|
readonly styleId: string;
|
|
2073
|
+
readonly name?: string;
|
|
1979
2074
|
readonly type: string;
|
|
1980
2075
|
readonly basedOn: string | null;
|
|
1981
2076
|
/** `w:next` — the authoring style for a following paragraph. */
|
|
@@ -1991,8 +2086,6 @@ interface StyleDefinition {
|
|
|
1991
2086
|
}
|
|
1992
2087
|
declare function isValidStyleId(raw: string | undefined): raw is string;
|
|
1993
2088
|
|
|
1994
|
-
/** Soft ceiling on `basedOn` chain length — enough for real templates, refuses hostile graphs. */
|
|
1995
|
-
declare const MAX_STYLE_BASED_ON_DEPTH = 32;
|
|
1996
2089
|
/** Soft ceiling on style definitions read from one styles part. */
|
|
1997
2090
|
declare const MAX_STYLE_DEFINITIONS = 4096;
|
|
1998
2091
|
/**
|
|
@@ -2002,10 +2095,21 @@ declare const MAX_STYLE_DEFINITIONS = 4096;
|
|
|
2002
2095
|
* styles part are never reused under another.
|
|
2003
2096
|
*/
|
|
2004
2097
|
interface StyleCascadeTable {
|
|
2098
|
+
/** Keep floating tables that fit a full page together under the compatibility flag. */
|
|
2099
|
+
readonly doNotBreakWrappedTables?: true;
|
|
2005
2100
|
/** Legacy or explicitly disabled optional OpenType substitutions. */
|
|
2006
2101
|
readonly disableOptionalLigatures?: true;
|
|
2007
2102
|
/** Legacy noExtraLineSpacing behavior, included in the producer fingerprint. */
|
|
2008
2103
|
readonly preserveExactLineBaseline?: true;
|
|
2104
|
+
/** `w:adjustLineHeightInTable`: cell paragraphs snap to the section line grid too. */
|
|
2105
|
+
readonly adjustLineHeightInTable?: true;
|
|
2106
|
+
/** `w:doNotUseIndentAsNumberingTabStop`, carried onto each paragraph's tab stops. */
|
|
2107
|
+
readonly ignoreIndentAsNumberingTabStop?: true;
|
|
2108
|
+
/**
|
|
2109
|
+
* `w:doNotUseHTMLParagraphAutoSpacing`: adjacent paragraph spacing adds up, and automatic
|
|
2110
|
+
* spacing is a fixed 5pt before and 10pt after.
|
|
2111
|
+
*/
|
|
2112
|
+
readonly fixedParagraphSpacing?: true;
|
|
2009
2113
|
/** Explicit compatibility opt-in to the unmodified ISO table style hierarchy. */
|
|
2010
2114
|
readonly strictTableStyleHierarchy?: boolean;
|
|
2011
2115
|
readonly typography?: CjkTypographySettings;
|
|
@@ -2048,12 +2152,7 @@ interface StyleCascadeTable {
|
|
|
2048
2152
|
interface CascadedParagraphFormatting {
|
|
2049
2153
|
/** Flat paragraph properties in cascade order (defaults → bases → style → direct). */
|
|
2050
2154
|
readonly paragraphProperties: readonly OoxmlProperty[];
|
|
2051
|
-
/**
|
|
2052
|
-
* The same list WITHOUT the paragraph's own `w:pPr` — everything it inherits.
|
|
2053
|
-
*
|
|
2054
|
-
* Numbering needs the two tiers apart: a level's `w:pPr/w:ind` outranks the style's and is
|
|
2055
|
-
* outranked by the paragraph's own, and a flattened list cannot say which is which.
|
|
2056
|
-
*/
|
|
2155
|
+
/** The same list WITHOUT the paragraph's own `w:pPr` — everything it inherits. */
|
|
2057
2156
|
readonly inheritedParagraphProperties: readonly OoxmlProperty[];
|
|
2058
2157
|
/** Matching `w:pPr` nodes for nested border resolution. */
|
|
2059
2158
|
readonly paragraphPropertyNodes: readonly OoxmlNode[];
|
|
@@ -2066,7 +2165,9 @@ interface CascadedParagraphFormatting {
|
|
|
2066
2165
|
*/
|
|
2067
2166
|
readonly runProperties: readonly OoxmlProperty[];
|
|
2068
2167
|
/**
|
|
2069
|
-
* Content cascade plus
|
|
2168
|
+
* Content cascade plus the mark's `w:pPr/w:rPr`, including its `w:rStyle` character style —
|
|
2169
|
+
* empty-line metrics and the numbering marker. A line with content grows from the mark
|
|
2170
|
+
* without that character style.
|
|
2070
2171
|
*/
|
|
2071
2172
|
readonly markRunProperties: readonly OoxmlProperty[];
|
|
2072
2173
|
/**
|
|
@@ -2165,8 +2266,8 @@ interface ParagraphLayoutInputs {
|
|
|
2165
2266
|
readonly shading: string | undefined;
|
|
2166
2267
|
readonly inheritedRunProperties: readonly OoxmlProperty[];
|
|
2167
2268
|
/**
|
|
2168
|
-
* Paragraph-mark cascade (`inheritedRunProperties` +
|
|
2169
|
-
* Empty-line sizing and last-line mark height — never content
|
|
2269
|
+
* Paragraph-mark cascade (`inheritedRunProperties` + `w:pPr/w:rPr` and its `w:rStyle`).
|
|
2270
|
+
* Empty-line sizing and last-line mark height (without the `w:rStyle`) — never content face.
|
|
2170
2271
|
*/
|
|
2171
2272
|
readonly markRunProperties: readonly OoxmlProperty[];
|
|
2172
2273
|
/** Cascaded custom tab stops + default interval for paragraph-flow breaking. */
|
|
@@ -2192,6 +2293,9 @@ interface ParagraphLayoutInputs {
|
|
|
2192
2293
|
*
|
|
2193
2294
|
* `inTableCell` is asked for separately because a cell paragraph may have no table style to
|
|
2194
2295
|
* inherit at all, and `w:beforeAutospacing` still needs to know it is in a cell.
|
|
2296
|
+
*
|
|
2297
|
+
* `lineUnitPt` is the section's ACTIVE line-grid pitch. It sizes line-unit paragraph margins
|
|
2298
|
+
* and snaps the paragraph's lines to the grid; absent means no grid and the fixed 12pt unit.
|
|
2195
2299
|
*/
|
|
2196
2300
|
declare function resolveParagraphLayoutInputs(paragraph: OoxmlElement, contentWidth: number, styleCascade: StyleCascadeTable | undefined, listItem?: ResolvedListItem, tableCellStyle?: TableCellStyleFormatting, inTableCell?: boolean, lineUnitPt?: number): ParagraphLayoutInputs;
|
|
2197
2301
|
|
|
@@ -2644,9 +2748,9 @@ interface LineRecord {
|
|
|
2644
2748
|
/** Distance from the line box top to the text baseline. */
|
|
2645
2749
|
readonly baseline: number;
|
|
2646
2750
|
/**
|
|
2647
|
-
* Space ABOVE the glyph band inside {@link box} (exact centering,
|
|
2751
|
+
* Space ABOVE the glyph band inside {@link box} (exact centering, atLeast growth).
|
|
2648
2752
|
*
|
|
2649
|
-
* `auto`
|
|
2753
|
+
* `auto` extras grow the box BELOW the glyphs — paint puts that depth in
|
|
2650
2754
|
* padding-bottom. {@link baseline} is measured from the line top and already includes
|
|
2651
2755
|
* this above-band when present.
|
|
2652
2756
|
*
|
|
@@ -2655,18 +2759,18 @@ interface LineRecord {
|
|
|
2655
2759
|
*/
|
|
2656
2760
|
readonly leading: number;
|
|
2657
2761
|
/**
|
|
2658
|
-
* Auto
|
|
2762
|
+
* Auto line-spacing depth BELOW the glyph band, inside {@link box}.
|
|
2659
2763
|
*
|
|
2660
|
-
* The complement of {@link leading}: exact
|
|
2661
|
-
*
|
|
2764
|
+
* The complement of {@link leading}: exact centres the glyphs and atLeast grows the box
|
|
2765
|
+
* above them, while auto leaves the band at the top and grows the box beneath it.
|
|
2662
2766
|
* So the band a consumer needs is `box.height - trailingSpacing - leading`, and
|
|
2663
|
-
* subtracting `leading` alone is right only under
|
|
2767
|
+
* subtracting `leading` alone is right only under exact and atLeast.
|
|
2664
2768
|
*
|
|
2665
2769
|
* A line WITH spans carries its band in the span heights too. An empty paragraph carries
|
|
2666
2770
|
* nothing, which is why the caret, paint's `padding-bottom` and the content-control
|
|
2667
2771
|
* boundary all need this published rather than recovered from the box.
|
|
2668
2772
|
*
|
|
2669
|
-
* Zero under
|
|
2773
|
+
* Zero under exact and atLeast, and on lines holding drawings (the box is authored).
|
|
2670
2774
|
* Absent on lines published before this was measured; treat as zero.
|
|
2671
2775
|
*/
|
|
2672
2776
|
readonly trailingSpacing?: number;
|
|
@@ -2742,8 +2846,9 @@ interface ParagraphFragmentRecord {
|
|
|
2742
2846
|
readonly clipToBox?: true;
|
|
2743
2847
|
/**
|
|
2744
2848
|
* The fragment retains its source identity without consuming body flow height: a positioned
|
|
2745
|
-
* text frame (with {@link ParagraphFragmentRecord.positionedFrame}),
|
|
2746
|
-
* paragraph before a continuous section,
|
|
2849
|
+
* text frame (with {@link ParagraphFragmentRecord.positionedFrame}), an empty section-mark
|
|
2850
|
+
* paragraph before a continuous section, or the empty line in front of a paragraph's leading
|
|
2851
|
+
* page break at the bottom of a full page. The last two paint nothing.
|
|
2747
2852
|
*/
|
|
2748
2853
|
readonly outOfFlow?: true;
|
|
2749
2854
|
/** Placement and wrapping of one authored text-frame group, in page-content coordinates. */
|
|
@@ -2903,11 +3008,8 @@ interface ListMarkerRecord {
|
|
|
2903
3008
|
*/
|
|
2904
3009
|
readonly level: number;
|
|
2905
3010
|
/**
|
|
2906
|
-
* The `w:numId` this marker resolved through.
|
|
2907
|
-
*
|
|
2908
|
-
* Published with the level because the two together are what identifies a list: whether
|
|
2909
|
-
* a demote is even possible depends on which levels THIS definition declares, and a
|
|
2910
|
-
* document may hold several lists whose level 0 looks identical.
|
|
3011
|
+
* The `w:numId` this marker resolved through. With the level it identifies a list: whether
|
|
3012
|
+
* a demote is possible depends on which levels THIS definition declares.
|
|
2911
3013
|
*/
|
|
2912
3014
|
readonly numId: string;
|
|
2913
3015
|
/** `w:numFmt` of the resolved level — `bullet` or a numbering format. */
|
|
@@ -2924,6 +3026,11 @@ interface ListMarkerRecord {
|
|
|
2924
3026
|
* why both are published rather than one replacing the other.
|
|
2925
3027
|
*/
|
|
2926
3028
|
readonly picture?: ListMarkerPictureRecord;
|
|
3029
|
+
/**
|
|
3030
|
+
* In a right-to-left paragraph: `text` in VISUAL order, one piece per direction run, each
|
|
3031
|
+
* styled at its bidi level. Paint draws these instead of `text`, which stays logical.
|
|
3032
|
+
*/
|
|
3033
|
+
readonly pieces?: readonly Pick<ListMarkerRecord, 'text' | 'style' | 'box'>[];
|
|
2927
3034
|
}
|
|
2928
3035
|
/**
|
|
2929
3036
|
* The picture a `w:lvlPicBulletId` marker paints, with its geometry already decided.
|
|
@@ -3007,16 +3114,14 @@ interface TableRowFragmentRecord {
|
|
|
3007
3114
|
readonly rowIndex: number;
|
|
3008
3115
|
/** True when the authored row resolves `w:tblHeader`, including its first occurrence. */
|
|
3009
3116
|
readonly isHeaderRow: boolean;
|
|
3010
|
-
/**
|
|
3011
|
-
* True for a `w:tblHeader` row RE-EMITTED at the top of a continuation page. Painted,
|
|
3012
|
-
* but excluded from interaction walks so each caret stop exists exactly once.
|
|
3013
|
-
*/
|
|
3117
|
+
/** True for a `w:tblHeader` row repeated atop a continuation page; not an interaction stop. */
|
|
3014
3118
|
readonly isHeaderRepeat: boolean;
|
|
3015
|
-
/**
|
|
3016
|
-
* True when this record continues a row that already emitted content on a prior page
|
|
3017
|
-
* (cell content fragmented at a paragraph/line boundary). Same `id` as the lead fragment.
|
|
3018
|
-
*/
|
|
3119
|
+
/** True when this record continues a row split at a line boundary; same `id` as its head. */
|
|
3019
3120
|
readonly isContinuation?: boolean;
|
|
3121
|
+
/** True when the rest of this row continues in the next fragment: the head of a split row. */
|
|
3122
|
+
readonly hasContinuation?: boolean;
|
|
3123
|
+
/** True for a `w:cantSplit` or exact-height row: it stays whole where a page holds it. */
|
|
3124
|
+
readonly placesWhole?: boolean;
|
|
3020
3125
|
readonly cells: readonly TableCellFragmentRecord[];
|
|
3021
3126
|
readonly box: LayoutBox;
|
|
3022
3127
|
}
|
|
@@ -3147,7 +3252,7 @@ interface NoteAreaRecord {
|
|
|
3147
3252
|
readonly box: LayoutBox;
|
|
3148
3253
|
/** Separator rule / authored separator story; absent when no notes on this page. */
|
|
3149
3254
|
readonly separator?: {
|
|
3150
|
-
readonly kind: 'separator' | 'continuationSeparator';
|
|
3255
|
+
readonly kind: 'separator' | 'continuationSeparator' | 'continuationNotice';
|
|
3151
3256
|
readonly box: LayoutBox;
|
|
3152
3257
|
readonly fragments: readonly BlockFragmentRecord[];
|
|
3153
3258
|
readonly synthetic: boolean;
|
|
@@ -3156,6 +3261,8 @@ interface NoteAreaRecord {
|
|
|
3156
3261
|
/** Resolved marker-run color; null/absent uses automatic black. */
|
|
3157
3262
|
readonly ruleColor?: string | null;
|
|
3158
3263
|
};
|
|
3264
|
+
/** Authored furniture below a note that continues on the next page. */
|
|
3265
|
+
readonly continuationNotice?: NonNullable<NoteAreaRecord['separator']>;
|
|
3159
3266
|
readonly notes: readonly NoteStoryRecord[];
|
|
3160
3267
|
readonly fallbackReason?: string;
|
|
3161
3268
|
}
|
|
@@ -3255,6 +3362,8 @@ interface PageRecord {
|
|
|
3255
3362
|
* pages as free body space.
|
|
3256
3363
|
*/
|
|
3257
3364
|
readonly noteStream?: PageNoteStream;
|
|
3365
|
+
/** An empty sheet that gives the next section its page parity; SECTIONPAGES skips it. */
|
|
3366
|
+
readonly parityBlank?: true;
|
|
3258
3367
|
/**
|
|
3259
3368
|
* Section-local PAGE/SECTIONPAGES inputs for finalize. Absent → physical page index and
|
|
3260
3369
|
* document-wide section count (empty `w:pgNumType` behaviour).
|
|
@@ -3370,4 +3479,5 @@ interface TextMeasurer {
|
|
|
3370
3479
|
};
|
|
3371
3480
|
}
|
|
3372
3481
|
|
|
3373
|
-
export {
|
|
3482
|
+
export { PARAGRAPH_BORDER_SIDES as a$, AUTO_PARAGRAPH_SPACING_PT as a3, HARD_MAX_AGGREGATE_FONT_BYTES as aF, HARD_MAX_FONT_BYTES as aG, HARD_MAX_FONT_SOURCES as aH, MAX_BORDER_SPACE_PT as aN, MAX_BORDER_WIDTH_PT as aO, MAX_LVL_OVERRIDES as aP, MAX_NUMBERING_DEFINITIONS as aQ, MAX_PARAGRAPH_SPACING_PT as aR, MAX_SHAPING_CONTEXT as aS, MAX_STYLE_DEFINITIONS as aT, MAX_TABLE_BORDER_STROKES as aU, MAX_TAB_POSITION_TWIPS as aV, MAX_TAB_STOPS as aW, PAGE_BORDER_SIDES as a_, DEFAULT_PAGE_GEOMETRY as ad, DEFAULT_RUN_STYLE as ae, DEFAULT_TAB_INTERVAL_PT as af, DEFAULT_TAB_INTERVAL_TWIPS as ag, EMPTY_NUMBERING_INDEX as al, EMPTY_TAB_STOPS as am, FontResolutionError as ax, boundedStructuralFontValidator as b$, TAB_LEADER_GLYPH as bI, UnsupportedScriptError as bT, appliedSpaceBefore as bV, applyLineSpacing as bW, baselineShiftPtOf as bX, borderExtentPt as bY, borderWeight as bZ, bottomBorderExtentPt as b_, SINGLE_LINE_SPACING as bo, buildNumberingIndex as c0, buildStyleCascadeTable as c1, cascadeParagraphFormatting as c2, cascadeRunProperties as c3, cascadedBottomBorder as c4, cascadedParagraphBorders as c5, cascadedTabStops as c6, collapsedSpaceBefore as c7, createFontResourceSnapshot as c8, createShapedRun as c9, readNumPr as cA, readTableBorders as cB, resolveBorderConflict as cC, resolveNumberingLevel as cD, resolveParagraphLayoutInputs as cE, resolveRunStyle as cF, resolveStoryListItems as cG, resolveStoryRefFields as cH, resolveTableCellBorderGrid as cI, runStylesEqual as cJ, shapedRunComparatorInputs as cK, shapingEnvironmentFingerprint as cL, shapingEnvironmentFingerprintInputs as cM, styleForFontSlot as cN, tabAdvanceWidth as cO, tabStopsFingerprint as cP, walkStoryParagraphs as cQ, withDefaultTabInterval as cR, withNumberingStyleLinks as cS, withResolvedListItems as cT, createShapingEnvironment as ca, defaultTabIntervalFromSettings as cb, displayText as cc, fixedPoint as cd, fontRequestKey as ce, glyphSizeFactorOf as cf, isValidStyleId as cg, itemizeScriptFontSlots as ch, layoutEquation as ci, measureDisplayText as cj, mergeListIndent as ck, nextTabDestination as cl, pageBordersFingerprint as cm, paragraphBorderExtentPt as cn, paragraphBorderStrokeWidthPt as co, paragraphBorders as cp, paragraphBordersFingerprint as cq, paragraphBreaksBefore as cr, paragraphContextualSpacing as cs, paragraphLineSpacing as ct, paragraphSpacing as cu, paragraphTabStops as cv, parsePageBorders as cw, parseRefInstruction as cx, readBorderSide as cy, readCellBorders as cz };
|
|
3483
|
+
export type { SpanLinkRecord as $, AnchoredDrawingRecord as A, BlockFragmentRecord as B, ContentControlBoundaryRecord as C, DrawingPoint as D, NoteAreaRecord as E, FontResourceSnapshot as F, NoteStoryRecord as G, HeaderFooterStoryRecord as H, InlineDrawingRecord as I, ContentControlLock as J, FontByteValidator as K, LineRecord as L, ModelRange as M, NormalizationPolicy as N, FixedPoint as O, PageGeometry as P, SourceRange as Q, ResolvedRunStyle as R, SemanticLayout as S, TextMeasurer as T, HyperlinkProjector as U, VersionedShapingLibrary as V, InlineDrawingLayoutContext as W, FieldLinkProjector as X, StoryPageFieldNeeds as Y, RefFieldContext as Z, HyperlinkFieldSpec as _, StyleSpanRecord as a, PageBorderFrameRecord as a0, ParagraphBorderStrokeRecord as a1, StrikeoutStrokePt as a2, AbstractNumDefinition as a4, AnchoredDrawingLayoutFallback as a5, BidiEmbeddingLevels as a6, BorderGridGeometry as a7, CascadedParagraphFormatting as a8, CjkTypographySettings as a9, FontResourceInstrumentation as aA, FontResourceSnapshotOptions as aB, FontSlot as aC, FontValidationResult as aD, GlyphOutline as aE, LevelOverride as aI, LineSpacingRule as aJ, ListMarkerAlign as aK, ListMarkerRecord as aL, ListSuffix as aM, NumDefinition as aX, NumberingLevelIndent as aY, NumberingPictureBullet as aZ, ContentControlGeometryFragment as aa, ContentControlLevel as ab, ContentControlMappedType as ac, DeclaredFontSubstitution as ah, DrawingClipFallback as ai, DrawingGeometry as aj, DrawingGroupPictureRecord as ak, EquationFractionGeometry as an, EquationGeometry as ao, EquationNaryGeometry as ap, EquationRadicalGeometry as aq, EquationRowGeometry as ar, EquationScriptGeometry as as, EquationSpanRecord as at, EquationTextGeometry as au, FieldAtomMarker as av, FontFingerprintInputs as aw, FontResolutionErrorCode as ay, FontResourceDefinition as az, SectionPageBorders as b, PageBorderDisplay as b0, PageBorderOffsetFrom as b1, PageBorderSide as b2, PageBorderStrokeRecord as b3, PageBorderZOrder as b4, PageRefCalibrationCell as b5, PageRefFieldProjection as b6, ParagraphAutoSpacingContext as b7, ParagraphBorderEdge as b8, ParagraphBorderSide as b9, ShapedFontSpan as bA, ShapedGlyph as bB, ShapedRunComparatorInputs as bC, ShapedVerticalMetrics as bD, ShapingContext as bE, ShapingEnvironment as bF, ShapingEnvironmentFingerprintInputs as bG, StyleDefinition as bH, TabAlignment as bJ, TabDestination as bK, TabLeader as bL, TabStop as bM, TableBorderSideName as bN, TableBorderStrokeRecord as bO, TableFragmentRecord as bP, TextDirection as bQ, TextboxStoryFallbackReason as bR, TextboxStoryLayout as bS, VerticalAlign as bU, ParagraphBorders as ba, ParagraphBottomBorderRecord as bb, ParagraphIndent as bc, ParagraphLayoutInputs as bd, ParagraphLineSpacing as be, ParagraphSpacing as bf, RefFieldSpec as bg, RefNoteParts as bh, ResolvedCellBorders as bi, ResolvedPictureBullet as bj, ResolvedTabStops as bk, ResolvedTableBorderEdge as bl, ResolvedTableBorderEdgeSegment as bm, ResolvedUnderline as bn, ScriptItem as bp, SemanticArtifactRootStoryKind as bq, SemanticArtifactStoryKind as br, SemanticCommentArtifactRecord as bs, SemanticReviewArtifactOccurrence as bt, SemanticReviewArtifactOccurrenceGeometry as bu, SemanticReviewArtifactPosition as bv, SemanticReviewArtifactSource as bw, SemanticTrackedChangeArtifactRecord as bx, ShapeInput as by, ShapedCluster as bz, TableRowFragmentRecord as c, TableCellFragmentRecord as d, ShapingEnvironmentInput as e, TextShaper as f, ResolvedFont as g, FixedPointRoundingMode as h, FontRequest as i, SemanticReviewArtifactRecord as j, ListMarkerPictureRecord as k, FontSubstitution as l, ShapedRun as m, NumberingLevel as n, NumberingIndex as o, ParagraphFragmentRecord as p, LayoutBox as q, DrawingInsets as r, TableBorderSide as s, PageRecord as t, ResolvedListItem as u, CellBorderBox as v, TableCellStyleFormatting as w, TableFloatPosition as x, TableBorderBox as y, StyleCascadeTable as z };
|