@docx-editor.dev/core/layout

@docx-editor.dev/core/layout — DOM-free pagination, shaping, and hit testing.

Text is measured through an injected TextMeasurer and shaped through an injected TextShaper, so the same code paginates in a browser and on a server. Points everywhere; twips convert at property-read boundaries.

Incremental by construction: per-block cache keys and flow checkpoints mean a pass that changes nothing returns the previous pages by identity.

Functions (250)

activeReviewItemfunctionSource ↗

The item the caret is in, or null.

A resolved comment never activates: a settled thread must not reopen itself as the reviewer types near it.

A REPLY resolves to the thread it belongs to. A reply is anchored over its parent's range, so both cover the caret — and the reply, being newer, wins the innermost test. It is not a card of its own (it renders inside its parent's), so the thread would have gone active with nothing on screen showing it: the reply box vanished from a comment the moment somebody replied to it.

declare function activeReviewItem(items: readonly ReviewItem[], position: ReviewPosition, order: ReadonlyMap<string, number>): ReviewItem | null;

anchorLineYfunctionSource ↗

The y of the line a position sits on, measured from the anchor's own origin.

An ordinary line answers from its own range, exactly as it always did. On a merged fragment's join line the range names one of the two paragraphs, so an offset compared against it either overshot — putting a card in the absorbed half beside the wrong line — or matched the first line every time.

declare function anchorLineY(anchor: ReviewParagraphAnchor, paragraphId: string, offset: number): number;

appliedSpaceBeforefunctionSource ↗

Applied before-spacing for placement (Word 2013+ / compat mode 15).

Adjacent before/after still collapse to the larger gap, but before is dropped entirely when the paragraph begins at the top of a page mid-section. The first paragraph of a document or section retains before. Callers publish this applied value on the fragment so shading, borders, selection, and paint share one geometry.

declare function appliedSpaceBefore(before: number, previousAfter: number, atTopOfPage: boolean, firstParagraphOfSection: boolean): number;

applyLineSpacingfunctionSource ↗

Apply resolved line spacing to a line's natural (glyph-derived) box.

Word places auto / atLeast extras BELOW the line (the last line's multiple spacing still separates it from the next paragraph). Putting that delta above inverted cover-page rhythm: w:line="460" on "between" opened a large gap above the word and almost none before "MERIDIAN". exact taller than the glyphs centers the text (ECMA-376 17.3.1.33). An exact box smaller than the glyphs keeps the baseline inside so clipped text still sits on it.

declare function applyLineSpacing(spacing: ParagraphLineSpacing, naturalHeight: number, naturalBaseline: number): {
    height: number;
    baseline: number;
};

attachNotesToLayoutfunctionSource ↗

Attach footnote/endnote areas onto a body layout. Does not re-paginate — callers that need reservation must re-run body layout with [pageBottomReserves](pageBottomReserves) first.

declare function attachNotesToLayout(layout: SemanticLayout, allRefs: readonly PageRefHit[], input: NotesLayoutInput, options?: {
    readonly fallbackReasons?: readonly NotePaginationFallbackReason[];
    readonly paragraphSectionIndex?: ReadonlyMap<string, number>;
    readonly memo?: unknown;
}): NotesAttachResult;

baselineShiftPtOffunctionSource ↗

How far a run's glyphs are lifted off the line's baseline, in points. Positive is up.

Super and subscript move the GLYPHS without moving the run's box, so the box keeps tiling the line and the selection band stays continuous. Anything drawing at the glyphs — the painter, and the caret — has to apply this itself, and from one place, or the two drift.

declare function baselineShiftPtOf(style: ResolvedRunStyle): number;

borderExtentPtfunctionSource ↗

Width contribution of a resolved edge for content inset / row sizing.

declare function borderExtentPt(edge: ResolvedTableBorderEdge | TableBorderSide | undefined): number;

borderWeightfunctionSource ↗

Conflict weight: the authored width in eighths of a point, and nothing else.

Word-matching, not conformance — §17.4.39 (w:tblBorders) and §17.4.66 (w:tcBorders) describe the elements and specify no conflict algorithm. Word picks the heavier RULE, so a 6pt dashed rule beats a hairline single. Folding the style rank into the weight (an sz × border-number product) made a 0.5pt double outrank a 1pt single and made every dashed or dotted rule weigh 1 regardless of w:sz, which erased its width entirely.

declare function borderWeight(side: TableBorderSide): number;

bottomBorderExtentPtfunctionSource ↗

Vertical extent a bottom border adds below the last line (gap + rule).

declare function bottomBorderExtentPt(edge: ParagraphBorderEdge | undefined): number;

boundedFallbackWordSegmentsfunctionSource ↗

Bounded deterministic fallback — not full UAX #29 word conformance.

declare function boundedFallbackWordSegments(text: string): readonly WordSegment[];

buildNumberingIndexfunctionSource ↗

Project numbering.xml into the bounded index.

Every ceiling here exists because the input is file-derived: definition counts, override counts, indent magnitudes and style-link hop depth are all capped, and nothing from the file becomes a loop bound or an allocation size.

declare function buildNumberingIndex(root: OoxmlElement | null | undefined): NumberingIndex;

buildPageRefIndexfunctionSource ↗

Build a reusable paragraph-id index (document order preserved per paragraph).

declare function buildPageRefIndex(allRefs: readonly PageRefHit[]): PageRefIndex;

buildStyleCascadeTablefunctionSource ↗

Build a cascade table from a styles part root.

Only direct w:style children of the root participate (bounded count). Duplicate styleId values keep the last definition, matching Word's reader for this fixture class. Default paragraph/character style ids track w:default="1" with the same last-wins rule.

declare function buildStyleCascadeTable(stylesRoot: OoxmlElement | null, themeFonts?: ThemeFonts, settingsRoot?: OoxmlElement | null): StyleCascadeTable;

captureOperationSnapshotfunctionSource ↗

Capture, validate, and freeze the environment used throughout one derived operation.

captureOperationSnapshot: (source: OperationSnapshot) => OperationSnapshot

caretAtfunctionSource ↗

Geometry for one model position, or null when it is not laid out.

declare function caretAt(layout: SemanticLayout, position: SemanticPosition, measurerOrOptions?: TextMeasurer | CaretAtOptions): CaretGeometry | null;

caretBoxOnLinefunctionSource ↗

Where a caret sits on a line: its x, and the box it should be drawn at.

The height comes from the RUN at the insertion point, not from the line. A line is as tall as its largest run, so a caret in 11pt text on a line that also carries 36pt text was drawn three times the height of the text it sits in. Word sizes the insertion point to the run it would type into, which is also how the painter already draws the selection band: every run is its own inline box, and the band steps with the text.

Affinity at a shared model boundary: - after a layout-sized atom (tab / projected field), prefer the DOWNSTREAM span so the caret sits at the aligned destination (e.g. before CONFIDENTIAL after a right tab), matching hit-testing and caretStops; - otherwise the run BEFORE the offset wins — the run a keystroke would continue — except at the start of the line, where there is nothing before it.

declare function caretBoxOnLine(line: LineRecord, offset: number, measurer: TextMeasurer | undefined, segment?: {
    readonly spans: readonly StyleSpanRecord[];
    readonly drawings: readonly InlineDrawingRecord[];
} | null): {
    x: number;
    y: number;
    height: number;
};

caretStopsfunctionSource ↗

declare function caretStops(layout: SemanticLayout, measurer?: TextMeasurer): CaretGeometry[];

caretStopsForBlocksfunctionSource ↗

Caret stops for one story's block fragments (header/footer), in reading order.

Coordinates stay story-relative — the same space hitTestFragments and furniture paint use — so arrow motion follows tab-stop geometry and projected field atoms without mixing body sheet offsets.

declare function caretStopsForBlocks(layout: SemanticLayout, pageIndex: number, fragments: readonly BlockFragmentRecord[], measurer?: TextMeasurer): CaretGeometry[];

cascadedBottomBorderfunctionSource ↗

Bottom border after cascade: a later w:pBdr replaces an earlier one; absence inherits. nil/none clear the edge via paragraphBorders.

declare function cascadedBottomBorder(paragraphPropertyNodes: readonly OoxmlNode[]): ParagraphBorderEdge | undefined;

cascadedParagraphBordersfunctionSource ↗

w:pBdr after the style cascade: a later w:pBdr replaces an earlier one WHOLESALE.

Word does not merge edges across the cascade. A style that states only w:bottom discards the box its basedOn ancestor declared, so folding edge by edge would leave a lone underline surrounded by a box no one authored. Absence inherits; nil/none clear.

declare function cascadedParagraphBorders(paragraphPropertyNodes: readonly OoxmlNode[]): ParagraphBorders;

cascadedTabStopsfunctionSource ↗

Resolve tab stops from cascaded w:pPr nodes (docDefaults → style chain → direct).

Each w:tabs merges with clear support; absence inherits. The leader travels with the stop that declared it — a clear at the same position discards both together.

declare function cascadedTabStops(paragraphPropertyNodes: readonly OoxmlNode[]): ResolvedTabStops;

cascadeParagraphFormattingfunctionSource ↗

Cascade paragraph + inherited run properties for one paragraph's direct w:pPr.

Order: docDefaults → table style → basedOn ancestors → paragraph style → direct formatting, which is the style hierarchy of 17.7.2: a table style sits above the document defaults and below the paragraph style a cell paragraph names for itself. When w:pStyle is absent, the document's default paragraph style (w:default="1") is used. Direct formatting is last so it overrides inherited values inside the existing resolvers.

declare function cascadeParagraphFormatting(table: StyleCascadeTable, directPPr: OoxmlNode | undefined, tableCellStyle?: TableCellStyleFormatting): CascadedParagraphFormatting;

cascadeRunPropertiesfunctionSource ↗

Merge inherited paragraph-style run props with a run's direct rPr (direct last).

When a cascade table is supplied, also resolves w:rStyle character styles (basedOn chain, cycle/depth capped). Runs without an explicit rStyle pick up the default character style (w:default="1"). Precedence: inherited → character style chain → direct formatting.

PASS inheritedRunProperties BY IDENTITY. It must be an array [cascadeParagraphFormatting](cascadeParagraphFormatting) returned — runProperties or markRunProperties — and not a copy of one. A toggle property (ECMA-376 §17.7.3) resolves per level of the style hierarchy, and the levels below the character style resolve to more than a true or a false: whether the document defaults' short circuit is still standing decides what the character style's own toggle does next, and no single w:b element can spell that. The paragraph cascade attaches that state to the array it returns, so spreading, filtering or sorting the list drops it. (Object.freeze returns the same object, so that one is safe.) A list without it is read as one ordinary level, which is the most a bare property list can say and is what a caller assembling its own list gets.

declare function cascadeRunProperties(inheritedRunProperties: readonly OoxmlProperty[], directRunProperties: readonly OoxmlProperty[], table?: StyleCascadeTable): readonly OoxmlProperty[];

cellSelectionBetweenfunctionSource ↗

The rectangle two cells define.

Grown to a fixpoint rather than taken literally: a cell that spans two columns cannot be half selected, and a vertically merged run cannot be selected in the middle. Word grows the rectangle until every cell it touches is wholly inside it, so dragging into a merged cell pulls the selection out to that cell's full extent.

declare function cellSelectionBetween(layout: SemanticLayout, anchor: TableCellAddress, head: TableCellAddress): CellSelection | null;

cellSelectionRectsfunctionSource ↗

One rectangle per painted occurrence of a selected cell, in page-content coordinates.

declare function cellSelectionRects(layout: SemanticLayout, cellIds: readonly string[]): readonly {
    pageIndex: number;
    x: number;
    y: number;
    width: number;
    height: number;
}[];

cellSelectionTextfunctionSource ↗

A cell selection as plain text: tabs between cells, newlines between rows.

What a spreadsheet and every other word processor put on the clipboard for a rectangle, and the only shape that survives the trip: the text range a rectangle stands in for would paste back as one run of characters with the grid gone.

declare function cellSelectionText(layout: SemanticLayout, selection: CellSelection): string;

clampListValuefunctionSource ↗

Clamp a list counter into a safe non-negative integer Word can format.

declare function clampListValue(value: number): number;

collapsedSpaceBeforefunctionSource ↗

Gap to insert before a paragraph once the previous paragraph's after is already in the flow cursor — Word takes the larger of the two rather than summing them.

declare function collapsedSpaceBefore(before: number, previousAfter: number): number;

collectFlowBlocksfunctionSource ↗

Collect paragraph and table blocks from a sibling list, flattening through transparent block wrappers up to [MAX_CONTENT_CONTROL_NESTING](MAX_CONTENT_CONTROL_NESTING).

accept filters which typed blocks are kept (e.g. skip revision-removed paragraphs). When nesting exceeds the bound the wrapper is skipped entirely — same fail-closed rule as the historical storyBlocks walk.

declare function collectFlowBlocks(children: readonly OoxmlNode[], depth?: number, accept?: (block: OoxmlElement) => boolean): OoxmlElement[];

commentBodyTextfunctionSource ↗

Plain text of a comment's body, so a card never re-implements the run walk.

declare function commentBodyText(comment: CommentRecord): string;

commentInitialsfunctionSource ↗

Author initials for an avatar, from @w:initials or the name.

declare function commentInitials(comment: CommentRecord): string;

compositionAnchorfunctionSource ↗

The anchor an IME composition is attached to.

Composition needs a position that survives the intermediate transactions it produces, so it is expressed in model coordinates and re-resolved against each new layout rather than cached as geometry.

declare function compositionAnchor(layout: SemanticLayout, position: SemanticPosition, 
measurer?: TextMeasurer): CaretGeometry | null;

computeDoubleBorderMetricsPtfunctionSource ↗

Deterministic double stroke / gap / extent in layout points (scale-independent).

Thin authored widths inflate to a 1+1+1 point compound so a w:sz="3" double remains visible at paint scale 1 — matching Word's hairline-double floor.

declare function computeDoubleBorderMetricsPt(widthPt: number): CompoundBorderMetrics;

computeFootnoteReservesfunctionSource ↗

Compute per-page bottom reserves (points) needed for footnotes given a provisional layout. Used by the bounded reflow loop before final attach.

Height is measured against a column-derived note budget (not leftover body slack). Measuring from slack makes stable true on the first pass and never shrinks the body — references and notes then compete for the same band. Oversized notes still split/continue within the budget; [MIN_FOOTNOTE_BODY_BAND_PT](MIN_FOOTNOTE_BODY_BAND_PT) keeps a body band so reflow cannot chase blank sheets.

declare function computeFootnoteReserves(layout: SemanticLayout, allRefs: readonly PageRefHit[], input: NotesLayoutInput, noteMarks: NoteMarkContext, 
passMemo?: unknown, 
previousReserves?: ReadonlyMap<number, number>): {
    readonly reserves: ReadonlyMap<number, number>;
    readonly stable: boolean;
    readonly reasons: readonly NotePaginationFallbackReason[];
};

contentControlAtPointfunctionSource ↗

Innermost content control whose published boundary geometry contains point on pageIndex.

Nested controls that share the same content box resolve to the deepest nesting depth.

declare function contentControlAtPoint(layout: SemanticLayout, pageIndex: number, point: HitPoint): ContentControlBoundaryRecord | null;

contentControlAtSemanticfunctionSource ↗

Innermost content-control boundary at a page-content point, or null outside every control.

Prefers the deepest nesting depth when nested boundaries share geometry.

declare function contentControlAtSemantic(layout: SemanticLayout, point: {
    readonly x: number;
    readonly y: number;
    readonly pageIndex?: number;
}): ContentControlBoundaryRecord | null;

contentControlBoundariesfunctionSource ↗

Derive one boundary record per control the part declares, in document order.

A control whose content the layout never placed — one inside a story this layout is not of, or one holding nothing — answers no fragments rather than a zero-sized box at the origin: a rectangle nothing painted is a rectangle a hit test would match.

declare function contentControlBoundaries(part: OoxmlPart, layout: SemanticLayout): readonly ContentControlBoundaryRecord[];

contentControlContentChildrenfunctionSource ↗

Children of every w:sdtContent under a control, in document order.

Does not recurse into nested controls. Block callers use [MAX_CONTENT_CONTROL_NESTING](MAX_CONTENT_CONTROL_NESTING); paragraph callers use [MAX_INLINE_CONTAINER_DEPTH](MAX_INLINE_CONTAINER_DEPTH) across all transparent containers.

declare function contentControlContentChildren(control: OoxmlNode): readonly OoxmlNode[];

contentControlHoldingParagraphfunctionSource ↗

The innermost content control holding paragraphId, in part.

Deepest wins, matching the geometry path's innermost-by-nesting rule: a control inside a control is the one the caret is actually in.

declare function contentControlHoldingParagraph(part: OoxmlPart, paragraphId: string): ContentControlBoundaryRecord$1 | null;

contentControlRecordsInPartfunctionSource ↗

Every content control a part declares, in document order, WITHOUT geometry.

For callers that want the ROSTER rather than the rectangles — the Tab walk through form fields is the one, and it needs story order, not boxes. fragments comes back empty here by design; a caller that needs geometry reads layout.contentControls, which covers every story the layout draws.

declare function contentControlRecordsInPart(part: OoxmlPart, 
withinParagraphs?: ReadonlySet<string>): readonly ContentControlBoundaryRecord$1[];

contentControlsInLayoutfunctionSource ↗

Layout-published content-control boundaries in document order.

declare function contentControlsInLayout(layout: SemanticLayout): readonly ContentControlBoundaryRecord[];

contentControlsOfLayoutfunctionSource ↗

Every content-control boundary on a layout, preferring the layout-level list.

declare function contentControlsOfLayout(layout: SemanticLayout): readonly ContentControlBoundaryRecord$1[];

createBoundedFallbackWordBoundaryfunctionSource ↗

Explicit bounded fallback boundary (grapheme-safe, narrower than Intl).

declare function createBoundedFallbackWordBoundary(): WordBoundary;

createDefaultWordBoundaryfunctionSource ↗

Resolve production word boundary: Intl when available/construction succeeds, else bounded fallback.

declare function createDefaultWordBoundary(deps?: WordBoundaryResolverDeps): WordBoundary;

createDocumentFurnitureSourcefunctionSource ↗

Build section-aware header/footer layout from a neutral document view.

declare function createDocumentFurnitureSource(options: CreateDocumentFurnitureSourceOptions): DocumentFurnitureSource;

createDocumentLinkProjectorsfunctionSource ↗

Sanitized body and per-part link projectors over one neutral document view.

declare function createDocumentLinkProjectors(view: HeadlessDocumentView): DocumentLinkProjectors;

createDocumentNotesInputfunctionSource ↗

Build note layout input from the neutral package view, or undefined when unused.

declare function createDocumentNotesInput(options: CreateDocumentNotesInputOptions): NotesLayoutInput | undefined;

createDocumentStyleDependenciesfunctionSource ↗

Build the cascade and numbering projections layout consumes.

declare function createDocumentStyleDependencies(view: HeadlessDocumentView): DocumentStyleDependencies;

createFieldLinkRegistryfunctionSource ↗

Create a bounded, content-keyed field-link registry.

declare function createFieldLinkRegistry(): FieldLinkRegistry;

createFixedMeasurerfunctionSource ↗

A deterministic measurer for tests and headless use.

Monospace by construction: every character is the same width and every line the same height, scaled by w:sz when present. Real shaping is the HarfBuzz path; this exists so layout behaviour can be asserted without a font stack deciding the answer.

declare function createFixedMeasurer(charWidth?: number, lineHeight?: number): TextMeasurer;

createFontResourceSnapshotfunctionSource ↗

Admit a set of faces and return the immutable snapshot layout resolves against.

Admission is the trust boundary for font bytes: counts and sizes are checked against the hard ceilings, each face's hash is re-derived and compared, and the bytes are handed to the injected validator. A face failing any of these is recorded as a typed refusal rather than dropped, so resolve can explain itself instead of answering "missing".

createFontResourceSnapshot: (options: FontResourceSnapshotOptions) => FontResourceSnapshot

createHarfBuzzTextShaperfunctionSource ↗

Build a HarfBuzz-backed shaper.

Requires initializeHarfBuzz() to have resolved — shaping is synchronous, so the WASM runtime must already be loaded. Dispose the result when the editor goes away, or its cached faces leak.

createHarfBuzzTextShaper: (options?: HarfBuzzTextShaperOptions) => HarfBuzzTextShaper

createIntlWordBoundaryfunctionSource ↗

Intl.Segmenter word boundary for the invariant locale.

declare function createIntlWordBoundary(): WordBoundary;

createLayoutSchedulerfunctionSource ↗

Build the scheduler that turns a stream of commits into coalesced layout passes.

Keystrokes arrive faster than a document can be laid out, so changes accumulate into one scope and are laid out together rather than once per commit.

declare function createLayoutScheduler(options: LayoutSchedulerOptions): LayoutScheduler;

createLayoutSessionfunctionSource ↗

A layout session, retained across revisions by the caller.

declare function createLayoutSession(): LayoutSession;

createLayoutShapedMeasurerfunctionSource ↗

Bind measurement directly to the environment whose operation identity keys layout caches. Production browser/server hosts use this adapter so fingerprinted and executed shaping cannot drift through independently forwarded fields.

declare function createLayoutShapedMeasurer(shaping: LayoutShapingOptions, options: Pick<ShapedMeasurerOptions, 'resolveFont' | 'fallback'>): TextMeasurer;

createLayoutShapingfunctionSource ↗

Build one shaped-layout environment without importing an editor or DOM lane.

declare function createLayoutShaping(configuration: LayoutFontConfiguration | PreparedLayoutFontConfiguration, instrumentation?: LayoutShapingInstrumentation): Promise<LayoutShapingOptions>;

createListCounterStatefunctionSource ↗

Create a fresh counter bag for one story (body, or one header/footer part).

declare function createListCounterState(index: NumberingIndex): ListCounterState;

createParagraphLayoutCachefunctionSource ↗

A bounded least-recently-used cache with generation-scoped retention.

Bounded because a long editing session touches far more paragraph states than a document contains — every keystroke mints a new key for the paragraph being typed in — and an unbounded cache would hold every intermediate state of the session.

The bound never evicts the CURRENT working set: entries stamped by this generation's retain or touched since it began are skipped, and the map grows past maxEntries when a document is larger than the configured cap — evicting live entries made every full pass on a 500-page document re-measure the whole document.

declare function createParagraphLayoutCache<T>(options?: ParagraphLayoutCacheOptions): ParagraphLayoutCache<T>;

createShapedMeasurerfunctionSource ↗

A [TextMeasurer](TextMeasurer) that measures through the shaper rather than through a canvas.

The accurate path: advances come from the same shaping run that will position the glyphs, so measurement and paint cannot disagree. Falls back per-run when a font is unavailable rather than throwing, because a document naming a font nobody has must still lay out.

declare function createShapedMeasurer(options: ShapedMeasurerOptions): TextMeasurer;

createShapedMeasurerfunctionSource ↗

declare function createShapedMeasurer(options: LayoutEnvironmentShapedMeasurerOptions): TextMeasurer;

createShapedRunfunctionSource ↗

Validate and freeze a shaped run against the environment that produced it.

Checks the internal consistency a shaper must satisfy: direction matches the environment, cluster ranges tile the text without gaps or overlap, glyph ranges stay in bounds, font spans cover every glyph, and caret edges are monotonic. A shaper that violates any of these produces a caret that lands in the wrong place, which is far harder to diagnose downstream than here.

createShapedRun: (input: ShapedRun, environmentInput: ShapingEnvironmentInput) => ShapedRun

createShapingEnvironmentfunctionSource ↗

Validate and freeze a shaping environment.

Checks every field that could silently corrupt a measurement: OpenType tags must be four ASCII bytes, script and language must be non-blank and control-character free, fonts must already be validated. Throws rather than coercing — a bad tag that shapes anyway produces a document that measures wrong everywhere and looks fine.

createShapingEnvironment: (input: ShapingEnvironmentInput) => ShapingEnvironment

defaultNoteSeparatorRuleStylefunctionSource ↗

Word-default paint style for a separator marker.

Footnote and endnote separators both use a short single rule. A full-width double border on a body heading (e.g. the comprehensive fixture’s end banner) is ordinary paragraph w:pBdr ownership and must not transfer onto the note separator record. Authored separator stories with real paragraph/run/border content bypass this via fragment paint.

declare function defaultNoteSeparatorRuleStyle(_noteKind: NoteKind, _kind: 'separator' | 'continuationSeparator'): NoteSeparatorRuleStyle;

defaultTabIntervalFromSettingsfunctionSource ↗

Read w:settings/w:defaultTabStop (ECMA-376 §17.15.1.25), in points.

Word's own interval, not a constant: a metric-locale template writes w:val="1134" (2cm) and every default-interval tab in the document lands on that grid instead of the 0.5" one. The value is FILE-DERIVED, so a non-integer, non-positive or out-of-range val falls back to the schema default rather than being trusted into layout arithmetic.

ST_TwipsMeasure also admits a universal measure ("2cm"); Word writes plain twips, and the spelled form falls back to the default rather than being parsed here.

declare function defaultTabIntervalFromSettings(settings: OoxmlNode | null | undefined): number;

deletedTextBoundariesfunctionSource ↗

Visible deletion boundaries split words without changing canonical text offsets.

declare function deletedTextBoundaries(layout: SemanticLayout, paragraphId: string): ReadonlySet<number>;

deriveNoteDisplayMarksfunctionSource ↗

Derive display marks for references of one note kind in document order.

Restart rules: - continuous — single sequence across the document from numStart - eachSect — restart at numStart when sectionIndex changes - eachPage — restart when pageIndex changes (falls back to continuous if unknown)

IDs are stable; only display numbers change. Non-mutating.

declare function deriveNoteDisplayMarks(noteKind: NoteKind, references: readonly NoteReferenceSite[], properties: ResolvedNoteProperties): readonly NoteDisplayMark[];

deriveNoteDisplayMarksResolvedfunctionSource ↗

Derive marks using per-reference-section resolved properties (numFmt / numStart / numRestart). Restart rules consult each site's own section props.

declare function deriveNoteDisplayMarksResolved(_noteKind: NoteKind, references: readonly NoteReferenceSite[], resolveProps: (sectionIndex: number) => ResolvedNoteProperties): readonly NoteDisplayMark[];

displayTextfunctionSource ↗

The text as it is DRAWN, after case transforms. Measurement must use this, not the source.

declare function displayText(text: string, style: ResolvedRunStyle): string;

disposeLayoutShapingfunctionSource ↗

Release native resources held by a shaping environment.

declare function disposeLayoutShaping(shaping: LayoutShapingOptions): void;

documentOrderfunctionSource ↗

Paragraph ids in document order, deduplicated across fragments.

declare function documentOrder(layout: SemanticLayout): string[];

documentRelationshipTargetInfunctionSource ↗

Resolve a relationship in a non-body story for shared link projection.

declare function documentRelationshipTargetIn(view: HeadlessDocumentView, partName: string, relationshipId: string): ReturnType<typeof relationshipTargetIn>;

effectiveBorderSidefunctionSource ↗

What one cell side is before any ADJACENT cell has its say.

- omitted → the table's own rule for that position (tblBorders, insideH/insideV) - edge → the cell wins outright; no weight fight with the table - none → an explicit w:val="nil". Suppresses a matching table border on interior and perimeter sides alike, so a table whose cells all declare none paints borderless like Word even when tblBorders still carry single rules.

declare function effectiveBorderSide(authored: TableBorderSide, tableSide: TableBorderSide, _options?: {
    readonly interior?: boolean;
}): TableBorderSide;

effectiveContentControlLockfunctionSource ↗

Collapse raw + ancestor locks into one ST_Lock vocabulary value.

declare function effectiveContentControlLock(locks: readonly ContentControlLock[]): ContentControlLock;

emptyTocPlaceholderParagraphIdsfunctionSource ↗

Begin-paragraph ids of TOCs that have no visible cached result rows.

Layout keeps a single caret-height line on these ids so paint can host an identifiable empty-TOC furniture placeholder; ordinary field chrome on the same ids stays suppressed.

declare function emptyTocPlaceholderParagraphIds(part: OoxmlPart): ReadonlySet<string>;

emptyTocSuppressedResultParagraphIdsfunctionSource ↗

Empty result-paragraph ids inside an empty TOC.

Suppressed like field chrome so blank cached rows do not stack under the empty placeholder.

declare function emptyTocSuppressedResultParagraphIds(part: OoxmlPart): ReadonlySet<string>;

enumerateDocumentSectionsfunctionSource ↗

Split the body story into sections.

A paragraph carrying w:pPr/w:sectPr ends the current section (that paragraph is IN the section being ended). The body-level w:sectPr ends the final section. A document with neither yields one section of Word defaults covering every block.

Enumeration is capped at [MAX_DOCUMENT_SECTIONS](MAX_DOCUMENT_SECTIONS). Further paragraph-level section breaks are ignored and remaining blocks fold into the last accepted section (fail closed).

displayMode MUST match the one the caller passes to storyBlocks. blockStart / blockEndExclusive are indices into that list, and the list changes shape with the mode: the proposed view drops a paragraph whose mark and content a revision both removed. Slicing a filtered list with indices counted over an unfiltered one puts body text under another section's page geometry — the wrong paper size, the wrong margins, the wrong header.

declare function enumerateDocumentSections(part: OoxmlPart, displayMode?: RevisionDisplayMode, authorFilter?: RevisionAuthorFilter): DocumentSection[];

enumerateDocumentSectionsBoundedfunctionSource ↗

Like [enumerateDocumentSections](enumerateDocumentSections), but reports whether the section bound clipped hostile input. Prefer the plain enumerator for normal layout; use this when a caller needs a named fail-closed diagnostic.

declare function enumerateDocumentSectionsBounded(part: OoxmlPart, displayMode?: RevisionDisplayMode, authorFilter?: RevisionAuthorFilter): DocumentSectionsEnumeration;

everyStoryOrderfunctionSource ↗

Paragraph ids of EVERY story the layout paints, in the order they sit on the page.

Body, then each page's header and footer, then its note areas — per page, so a story's own paragraphs stay adjacent and in reading order. That is all any caller needs: a selection cannot span two stories (the engine refuses one), so only the order WITHIN a story is ever compared, and this gets that right for all of them at once.

What a caller passes when it has no story in hand — selectionRects and spansInSelection both REQUIRE an order rather than defaulting to one, deliberately. [documentOrder](documentOrder) is the body alone, and using it as a default is what let selection reads silently answer about the wrong story — two paragraphs selected in a header both ranked -1, the walk gave up, and the run properties came back short. A caller that DOES know its story should still pass that story's order: it is smaller, and it cannot match a paragraph the caret is not among.

declare function everyStoryOrder(layout: SemanticLayout): string[];

expandLvlTextfunctionSource ↗

Expand w:lvlText placeholders %1%9 using per-level counters and formats.

formats[i] / counters[i] correspond to ilvl i. Missing slots use decimal / 1. Literal percent signs that are not %1%9 are kept. Output is hard-capped.

declare function expandLvlText(lvlText: string, counters: readonly number[], formats: readonly string[]): string;

exportSourceRangeOffunctionSource ↗

Return the model address exporters may use, excluding layout-projected atoms.

declare function exportSourceRangeOf(span: StyleSpanRecord): SourceRange | null;

filterRefsOnPagefunctionSource ↗

Collect note references that appear in laid-out body fragments on a page. Matches [ParagraphFragmentRecord.range](ParagraphFragmentRecord.range) ownership (half-open + boundary affinity).

Pass [buildPageRefIndex](buildPageRefIndex) result as refIndex for O(fragments + matching refs) instead of scanning every document ref against every page fragment.

declare function filterRefsOnPage(page: PageRecord, allRefs: readonly PageRefHit[], refIndex?: PageRefIndex): readonly PageRefHit[];

findDrawingOverlayFrameInLayoutfunctionSource ↗

Locate a drawing's painted extent on the published layout.

Coordinates are page-content relative — the same space [hitTestPage](hitTestPage) uses — so an overlay can position from records without reading painted DOM geometry.

declare function findDrawingOverlayFrameInLayout(layout: SemanticLayout, drawingNodeId: string): DrawingOverlayFrame | null;

findSeparatorNotefunctionSource ↗

Find separator / continuationSeparator note body in a notes part.

declare function findSeparatorNote(part: OoxmlPart | null | undefined, kind: 'separator' | 'continuationSeparator'): OoxmlElement | undefined;

firstReviewRangefunctionSource ↗

The first range of an item, in authored order, or null when it has none.

declare function firstReviewRange(item: ReviewItem): ReviewRange | null;

fixedPointfunctionSource ↗

Brand a safe integer as a [FixedPoint](FixedPoint) coordinate.

Fixed point rather than float throughout shaping so that two runs shaped identically compare EQUAL — float accumulation would make the same text measure differently depending on how it was split, and pagination is decided on those measurements.

fixedPoint: (value: number) => FixedPoint

fontRequestKeyfunctionSource ↗

The canonical string identifying one face request.

Case- and whitespace-normalized, so "Times New Roman" and "times new roman" are one key — a document may name a family either way and both must reach the same face.

fontRequestKey: (request: FontRequest) => string

forEachSemanticDrawingfunctionSource ↗

Visit every drawing through the canonical root-story and recursive textbox walks.

declare function forEachSemanticDrawing(layout: SemanticLayout, visit: (drawing: SemanticDrawingVisit) => void): void;

forEachSemanticSpanfunctionSource ↗

Visit every published span in page/story order without consulting the source package.

declare function forEachSemanticSpan(layout: SemanticLayout, visitor: (visit: SemanticSpanVisit) => void): void;

forEachSemanticStoryfunctionSource ↗

Visit every root story in a semantic layout, preserving page/story order.

declare function forEachSemanticStory(layout: SemanticLayout, visit: (story: SemanticStoryVisit) => void): void;

forEachStoryParagraphFragmentfunctionSource ↗

Visit every paragraph fragment one story paints — its own (table interiors flattened, header repeats included) and the fragments inside each anchored drawing's text-box story, recursively.

The fragment sibling of [forEachStoryDrawing](forEachStoryDrawing), sharing its depth bound, for consumers that read per-paragraph published fields (list markers) rather than drawings. The furniture list-marker token walks with this; a fragment it misses leaves a reused page showing a stale marker.

declare function forEachStoryParagraphFragment(story: StoryDrawingHost, visit: (fragment: ParagraphFragmentRecord, context: StoryParagraphFragmentContext) => void, rootOrigin?: Readonly<{
    x: number;
    y: number;
}>, rootDrawingOrigin?: RootDrawingOrigin): void;

formatDecimalfunctionSource ↗

decimal (§17.18.59). Clamped, because the counter derives from file-declared restarts.

declare function formatDecimal(value: number): string;

formatDecimalZerofunctionSource ↗

decimalZero (§17.18.59): single digits zero-padded to two.

declare function formatDecimalZero(value: number): string;

formatLowerLetterfunctionSource ↗

lowerLetter (§17.18.59): the [formatUpperLetter](formatUpperLetter) sequence, lower-cased.

declare function formatLowerLetter(value: number): string;

formatLowerRomanfunctionSource ↗

lowerRoman (§17.18.59).

declare function formatLowerRoman(value: number): string;

formatNumFmtfunctionSource ↗

Format one counter for a w:numFmt value (ST_NumberFormat, §17.18.59).

none prints NOTHING — it is the format Word uses for a level that contributes only literal text, and formatting it as decimal invents a number the document never had. bullet is not formatted here — callers use the literal lvlText.

The remaining enumerants (japaneseCounting, hebrew1, thaiNumbers, ganada, …) are per-script numeral sequences we do not carry glyph tables for. They fall back to decimal deliberately: the ORDINAL is still the authored one, only the script differs, which reads as a number in the wrong alphabet rather than as a missing or wrong marker.

declare function formatNumFmt(numFmt: string, value: number): string;

formatPageNumberfunctionSource ↗

Format a displayed PAGE value through the shared ST_NumberFormat resolver.

Unknown / script-specific formats fall back to decimal (same convention as list markers). none / bullet are meaningless for page numbers and also fall back to decimal so a hostile fmt cannot blank the furniture.

declare function formatPageNumber(value: number, format: string | undefined): string;

formatRevisionOffunctionSource ↗

The tracked FORMAT change on a property list, from w:rPrChange or w:pPrChange.

A property change alters no characters, so it has no span of its own to strike or underline. Word marks the affected text and says what changed; the minimum a reader needs is to see that this text's formatting is itself a pending decision.

Read from the flattened property list because that is what layout already carries — the change wrapper is a w:rPr/w:pPr child like any other.

declare function formatRevisionOf(properties: readonly {
    readonly localName: string;
    readonly attributes?: Readonly<Record<string, string>>;
}[]): RevisionAttribution | null;

formatUpperLetterfunctionSource ↗

Excel-style letter sequence: 1→A … 26→Z, 27→AA. Caps length so a hostile counter cannot grow without bound.

declare function formatUpperLetter(value: number): string;

formatUpperRomanfunctionSource ↗

upperRoman (§17.18.59). Saturates at 3999, the largest value classical Roman numerals express — beyond it there is nothing correct to emit, so it stops rather than inventing notation.

declare function formatUpperRoman(value: number): string;

fragmentOwnsAtomOffsetfunctionSource ↗

Whether a paragraph fragment owns a note atom at atomOffset.

Fragment ranges are half-open for content ownership: [start, end). The shared boundary offset belongs to the later fragment (downstream affinity), matching line splits where fragmentStart = previous.range.end.

declare function fragmentOwnsAtomOffset(fragment: ParagraphFragmentRecord, atomOffset: number): boolean;

fragmentsOfParagraphfunctionSource ↗

Every fragment belonging to one paragraph, in order, across page boundaries.

declare function fragmentsOfParagraph(layout: SemanticLayout, paragraphId: string): ParagraphFragmentRecord[];

geometryOfSectionfunctionSource ↗

Section properties as the geometry layout paginates against.

The gutter is added to the LEFT margin: it is binding allowance, extra space on the inner edge, and folding it into the content width instead would silently narrow every line.

declare function geometryOfSection(section: SectionProperties): PageGeometry;

graphemeBoundaryEpochfunctionSource ↗

Current boundary generation, for callers that cache segmentation-derived answers.

declare function graphemeBoundaryEpoch(): number;

graphemeCountfunctionSource ↗

How many user-perceived characters the text holds.

declare function graphemeCount(text: string): number;

graphemeOffsetToUtf16functionSource ↗

The UTF-16 offset a grapheme index starts at. Clamps rather than throwing.

declare function graphemeOffsetToUtf16(text: string, graphemeOffset: number): number;

guardOperationSnapshotfunctionSource ↗

Compare the current environment against the one an operation captured, naming what changed.

guardOperationSnapshot: (captured: OperationSnapshot, current: OperationSnapshot) => OperationSnapshotGuard

hitTestPagefunctionSource ↗

Hit test a point given in PAGE-CONTENT coordinates, the space the fragment boxes use.

declare function hitTestPage(layout: SemanticLayout, pageIndex: number, point: HitPoint, options?: HitTestOptions): SemanticHit | null;

hitTestSemanticfunctionSource ↗

The caret position nearest a point, in PAGE-CONTENT coordinates.

Never returns null for a point inside the document: a click in the margin, past the end of a line, or below the last line still has an obvious intended caret, and refusing to answer would make those clicks do nothing.

The rules live in semantic-hit-test.ts, which answers with the cell address and the on-glyphs flag a pointer controller needs too; this keeps the geometry-only shape for callers that want nothing else.

declare function hitTestSemantic(layout: SemanticLayout, point: {
    readonly x: number;
    readonly y: number;
    readonly pageIndex?: number;
}): CaretGeometry | null;

hitTestSheetfunctionSource ↗

Hit test a point given in SHEET coordinates — the space page.box lives in, and the space a surface's own pixel offsets convert into.

declare function hitTestSheet(layout: SemanticLayout, point: HitPoint, options?: HitTestOptions): SemanticHit | null;

initializeHarfBuzzfunctionSource ↗

Load and verify the HarfBuzz WASM runtime without adding top-level await to import graphs.

declare function initializeHarfBuzz(): Promise<void>;

isCanvasMeasurementAvailablefunctionSource ↗

Whether an injected canvas text context is usable for measurement.

Availability is decided by the editor seam (which alone may create a canvas). Layout never probes document — a missing context is simply "unavailable".

declare function isCanvasMeasurementAvailable(context?: CanvasTextContext | null | undefined): boolean;

isContentControlfunctionSource ↗

Block or inline structured-document-tag wrapper — typed or generic during migration.

Generic fallback requires the WordprocessingML namespace so foreign-namespace <x:sdt> elements stay opaque wrappers and are never treated as Word controls.

declare function isContentControl(node: OoxmlNode): node is ContentControlLike;

isContentControlContentfunctionSource ↗

True when node is the control's content container (w:sdtContent).

Generic sdtContent requires the WML namespace — same foreign-namespace rule as [isContentControl](isContentControl).

declare function isContentControlContent(node: OoxmlNode): node is ContentControlContentLike;

isCumulativeGeometryTrustedFromLineOriginfunctionSource ↗

Whether the distance from a line's start to an offset can be trusted as exact.

Requires BOTH ends to be shaped boundaries: accumulating advances across an offset the shaper cannot place would produce a caret x that drifts further along the line.

declare function isCumulativeGeometryTrustedFromLineOrigin(run: ShapedRun, lineStartUtf16Offset: number, utf16Offset: number): boolean;

isFurniturePointfunctionSource ↗

True when a sheet-space point falls inside a page's header or footer box.

declare function isFurniturePoint(layout: SemanticLayout, point: HitPoint): boolean;

isGeometryTrustedCaretOffsetfunctionSource ↗

Every published shaped boundary has exact geometry from the shaping result.

declare function isGeometryTrustedCaretOffset(run: ShapedRun, utf16Offset: number): boolean;

isHarfBuzzInitializedfunctionSource ↗

Whether the WASM runtime is loaded and shaping can proceed synchronously.

declare function isHarfBuzzInitialized(): boolean;

isIntlSegmenterAvailablefunctionSource ↗

Whether this runtime provides Intl.Segmenter, which the default boundary requires.

declare function isIntlSegmenterAvailable(): boolean;

isIntlWordSegmenterAvailablefunctionSource ↗

Whether this runtime provides word-granularity Intl.Segmenter.

declare function isIntlWordSegmenterAvailable(): boolean;

isMarkerOnlySeparatorNotefunctionSource ↗

True when a separator note contains only OOXML separator markers (and empty noteRef atoms Word often authors beside them) — no measurable text or paragraph borders.

declare function isMarkerOnlySeparatorNote(note: OoxmlNode, displayMode?: RevisionDisplayMode, revisionAuthorFilter?: RevisionAuthorFilter): boolean;

isValidStyleIdfunctionSource ↗

declare function isValidStyleId(raw: string | undefined): raw is string;

isWholeGraphemeHorizontalBoundaryfunctionSource ↗

Whether an offset is a real caret position: both a grapheme boundary and a shaped cluster edge.

Both conditions, because they disagree. A ligature is one cluster spanning two graphemes, and an offset inside it has no geometry the shaper can answer for — placing a caret there would mean inventing an x coordinate.

declare function isWholeGraphemeHorizontalBoundary(run: ShapedRun, utf16Offset: number): boolean;

itemizeScriptFontSlotsfunctionSource ↗

Split text into shapeable runs by script, bidi level and font slot.

Consumes the bidi levels rather than re-deriving direction, so itemization and reordering agree by construction instead of by two implementations happening to match.

declare function itemizeScriptFontSlots(text: string, paragraphOffset: number, embedding: BidiEmbeddingLevels): readonly ScriptItem[];

keyedRangeRectsfunctionSource ↗

Rectangles for MANY ranges in ONE pass over the lines.

Not selectionRects in a loop. That walks every page, fragment and line per range, and a contract with two hundred comments would re-walk the whole document two hundred times on every layout — the highlight would cost more than the layout it decorates. One pass tests each line against every range instead, which is the same work a single selection does.

declare function keyedRangeRects(layout: SemanticLayout, ranges: readonly KeyedRange[], 
pages?: ReadonlySet<number>, 
measurer?: TextMeasurer): Map<string, SelectionRect[]>;

layoutEquationfunctionSource ↗

Compose one bounded OMML projection into paint-ready point geometry.

declare function layoutEquation(projection: OmmlEquationProjection, measurer: TextMeasurer, style: ResolvedRunStyle): EquationSpanRecord;

layoutFontConfigurationFingerprintfunctionSource ↗

Stable identity for every layout-affecting font configuration input.

declare function layoutFontConfigurationFingerprint(configuration: LayoutFontConfiguration): string;

layoutHeaderFooterStoryfunctionSource ↗

Lay one header/footer part out at contentWidth.

Line ids are namespaced by part so the body's line-N counter — which incremental convergence compares — never moves because a header changed.

When pageContext is set, allowlisted PAGE/NUMPAGES/SECTIONPAGES instructions project live values; otherwise those fields contribute only cached result text (often empty). Field-free stories ignore pageContext and share one baseline layout.

defaultTabStopPt is the document's w:settings/w:defaultTabStop (ECMA-376 §17.15.1.25) in points; absent keeps the 0.5" schema default. Furniture tabs on the SAME grid as the body — a page-number tab in a metric-locale footer belongs on the document's interval, not on a constant. It sits at the tail because the parameters ahead of it are already positional; new callers should keep passing undefined for what they do not set.

NEW inputs belong in [HeaderFooterStoryInputs](HeaderFooterStoryInputs), the trailing bag, rather than as a sixteenth position. Fifteen is what stopped numberingIndex being threaded here at all.

declare function layoutHeaderFooterStory(part: OoxmlPart, contentWidth: number, measurer: TextMeasurer, producer: string, cache?: ParagraphLayoutCache<readonly PendingLine[]>, styleCascade?: StyleCascadeTable, pageContext?: FieldPageContext, maxPageContextEntries?: number, defaultTabStopPt?: number, displayMode?: RevisionDisplayMode, inlineDrawingLayout?: InlineDrawingLayoutContext, drawingTokenForParagraph?: (paragraph: OoxmlNode) => string, drawingLayoutToken?: string, hfPageContext?: HeaderFooterPageContext, documentProperties?: DocumentProperties, inputs?: HeaderFooterStoryInputs): HeaderFooterStoryLayout;

layoutNoteByIdfunctionSource ↗

Layout a note by id from a notes part; null when missing.

declare function layoutNoteById(part: OoxmlPart | null | undefined, noteId: number, contentWidth: number, options: LayoutNoteStoryOptions): NoteStoryLayout | null;

layoutNoteSeparatorfunctionSource ↗

Layout the document's separator note, or synthesize a short horizontal rule.

Marker-only / missing separators emit no paragraph fragments — paint draws the rule from [NoteSeparatorLayout.ruleStyle](NoteSeparatorLayout.ruleStyle) + box geometry. Authored separators with real paragraph/run/border content keep their fragment story (including w:pBdr).

When maxFlowHeightPt is set and an authored separator exceeds it, the engine fails closed to a short synthetic rule ({@link note-separator-height-cap}) so note pagination cannot burn the overflow budget on zero-progress separator-only pages.

declare function layoutNoteSeparator(part: OoxmlPart | null | undefined, kind: 'separator' | 'continuationSeparator', contentWidth: number, options: LayoutNoteStoryOptions, noteKind: NoteKind, maxFlowHeightPt?: number): NoteSeparatorLayout;

layoutNoteStoryfunctionSource ↗

Lay one note node out at contentWidth.

Does not paginate. Callers that need splits ask for fragments and cut at paragraph/line boundaries in the note-pagination layer.

declare function layoutNoteStory(note: OoxmlNode, contentWidth: number, options: LayoutNoteStoryOptions): NoteStoryLayout | null;

layoutSemanticDocumentfunctionSource ↗

Lay one story part out into pages.

The engine's layout entry point. Walks body, header, footer and note roots, flattens block SDTs, paginates tables with header-row repeats and vertical merges, and resolves every paragraph through the style cascade.

Incremental when given a [LayoutSession](LayoutSession): per-block cache keys plus flow checkpoints mean a pass that changes nothing returns the previous pages by identity.

declare function layoutSemanticDocument(part: OoxmlPart, revision: number, options: SemanticLayoutOptions): SemanticLayout;

lineAtPositionfunctionSource ↗

The line containing a model position, or null when the position is not laid out.

declare function lineAtPosition(layout: SemanticLayout, paragraphId: string, offset: number, 
candidates?: Iterable<LineRecord>): LineRecord | null;

lineEndOffsetfunctionSource ↗

Logical line end, excluding the wrap space or hard break whose following position belongs to the next line. Page breaks are excluded even on the paragraph's last line.

declare function lineEndOffset(layout: SemanticLayout, line: LineRecord): number;

lineSegmentsfunctionSource ↗

Every paragraph a line carries, in visual order. One entry for an ordinary line.

declare function lineSegments(line: LineRecord): readonly LineSegment[];

linesOffunctionSource ↗

Every line in a layout, in reading order — the order caret navigation walks.

declare function linesOf(layout: SemanticLayout): LineRecord[];

listMarkerBoxfunctionSource ↗

Horizontal marker box inside the first-line indent slot.

Coordinates are relative to the same origin as paragraph content (indent.left is the text start). Returns null when there is nothing to paint.

w:hanging and a positive w:firstLine are one mutually exclusive slot (§17.3.1.10, §17.3.1.12), so the marker has two placements, not an interaction: a hanging level puts the marker BEFORE the text start (left - hanging); a positive-firstLine level puts it AFTER (left + firstLine) — the standard legal shape w:ind w:left="0" w:firstLine="720" numbers at 0.5" while continuation lines return to the margin. Reading only the hanging model painted every such marker at the left margin.

declare function listMarkerBox(item: ResolvedListItem, markerWidth: number, lineY: number, lineHeight: number): {
    x: number;
    y: number;
    width: number;
    height: number;
} | null;

markRevisionRemovesMarkfunctionSource ↗

Does this decision, taken, remove the paragraph mark?

A deletion does, and so does a moveFrom: the copy the paragraph moved OUT of goes away when the move is accepted. insert and moveTo are the other half of each pair, and they keep the break. Paint, the change bar and the resolved views all ask this one question, so a moveFrom cannot end up struck through in the margin and blue on the glyph.

declare function markRevisionRemovesMark(revision: RevisionAttribution): boolean;

measureDisplayTextfunctionSource ↗

Measure run text the way layout breaks lines and paints glyphs (caps/small-caps aware).

declare function measureDisplayText(text: string, style: ResolvedRunStyle, measurer: TextMeasurer): number;

mergeListIndentfunctionSource ↗

The effective indent of a list paragraph: STYLE, then the numbering LEVEL, then DIRECT.

Word applies a level's w:pPr/w:ind between the paragraph style and the paragraph's own formatting, per attribute — and the ordering matters on real documents. A converted agreement numbers its (a) items with a level stating left=1512 hanging=738 under a ListParagraph style stating left=775 hanging=624, and states only hanging="737" on the paragraph itself. Reading the flattened cascade as "the paragraph's indent" gave the STYLE's 775 to a level that had overridden it, so every lettered sub-item hung a full indent step to the left of where Word puts it.

inherited is the cascade WITHOUT the paragraph's own w:pPr (defaults, table cell style, style chain); direct is that w:pPr alone.

declare function mergeListIndent(levelIndent: NumberingLevelIndent, inherited: readonly OoxmlProperty[], direct?: readonly OoxmlProperty[]): NumberingLevelIndent;

moveCaretfunctionSource ↗

Move a caret; vertical movement carries a desired X through shorter lines.

declare function moveCaret(layout: SemanticLayout, position: SemanticPosition, command: NavigationCommand, desiredX?: number | null, options?: MoveCaretOptions): {
    position: SemanticPosition;
    desiredX: number | null;
} | null;

nextTabDestinationfunctionSource ↗

Next tab destination strictly past currentX, preferring custom stops then the default interval. Destination is clamped to rightEdge so stops cannot escape the content box.

declare function nextTabDestination(tabs: ResolvedTabStops, currentX: number, rightEdge: number): TabDestination;

normalNotesOffunctionSource ↗

Collect normal (body) notes from a notes part, bounded.

declare function normalNotesOf(part: OoxmlPart | null | undefined): readonly OoxmlElement[];

noteDisplayMarkMapfunctionSource ↗

Map noteId → formatted mark for quick lookup (last site wins if duplicated).

declare function noteDisplayMarkMap(marks: readonly NoteDisplayMark[]): ReadonlyMap<number, string | null>;

noteLineIdPrefixfunctionSource ↗

Stable line-id namespace for one note. Body line counters compare these as opaque strings and must not collide with line-N / hf-… ids.

declare function noteLineIdPrefix(noteKind: NoteKind, noteId: number): string;

noteMarkKeyfunctionSource ↗

The key one note's mark is stored under — footnote:N / endnote:N.

The same encoding EditorScope uses for note ids, so a mark context and a scope address name the same note without a translation step.

declare function noteMarkKey(noteKind: NoteKind, noteId: number): string;

noteSeparatorAreaBoxfunctionSource ↗

Absolute separator box: short rule for marker/synthetic, full width for authored stories.

declare function noteSeparatorAreaBox(separator: NoteSeparatorLayout, contentX: number, contentWidth: number, areaTop: number): LayoutBox;

noteStoryBlocksfunctionSource ↗

Blocks of one typed footnote/endnote node — a separate semantic story root.

The footnotes/endnotes part root is never a story; each note is laid out independently so line ids and incremental convergence stay namespaced by note identity.

declare function noteStoryBlocks(note: OoxmlNode, displayMode?: RevisionDisplayMode, authorFilter?: RevisionAuthorFilter): OoxmlElement[];

pageAtYfunctionSource ↗

The page a sheet-space y belongs to.

The gutter between page *i* and page *i+1* resolves to page *i*, because the nearest text to a point in that gap is the last line of the page above it. That falls out of searching for the last page whose top is at or above the point, with no special case: the gutter is inside [top(i), top(i+1)) by construction. A point above the first page clamps to it, and a point past the last page clamps to that.

declare function pageAtY(layout: SemanticLayout, sheetY: number): number;

pageBorderFramefunctionSource ↗

The frame for one sheet, or undefined when this page does not carry one.

isFirstPageOfSection is the SECTION's first page, not the document's: w:display is a section property, so in a three-section document a firstPage frame draws three times.

The four rules close a rectangle rather than each spanning its own side. Word draws one box, and horizontal rules that stopped at the text column while the verticals sat outside it read as two rules with two detached bars beside them — the same thing w:pBdr gets right by spanning from the left rule's outer edge to the right rule's.

declare function pageBorderFrame(borders: SectionPageBorders | undefined, geometry: PageGeometry, isFirstPageOfSection: boolean): PageBorderFrameRecord | undefined;

pageBordersFingerprintfunctionSource ↗

Identity of one section's page frame, for incremental-layout context keys.

A w:pgBorders edit changes nothing the flow measures — the frame is drawn beside the text, never through it — so no per-paragraph key moves and every reuse path would hand back the previous sheets with the previous frame. This token goes in the pass context so it does not.

declare function pageBordersFingerprint(borders: SectionPageBorders | undefined): string;

pageRefPageNumbersFromLayoutfunctionSource ↗

A [RefFieldRefreshOptions.pageRefPageNumberOf](RefFieldRefreshOptions.pageRefPageNumberOf) source over one finalized layout.

Builds the target → host-page index once, on first demand, and answers every field from it — the same walk finalize substitution takes, so the saved number is the painted one.

declare function pageRefPageNumbersFromLayout(layout: SemanticLayout): (targetParagraphId: string) => string | null;

pagesToMaterializefunctionSource ↗

The page indices to build in detail.

Returns indices rather than records so a caller can compare cheaply against what it already has mounted, and so the decision can be made without touching the layout.

declare function pagesToMaterialize(input: MaterializationInput): Set<number>;

paragraphBorderExtentPtfunctionSource ↗

Extent one border edge occupies away from the text it decorates: gap plus rule, in points.

Vertically that is flow height — a top rule pushes the first line down, a bottom rule holds the page open below the last one — so pagination has to see it. Horizontally it is publish-only: Word draws left/right paragraph rules OUTSIDE the text column and never re-breaks the lines, which is why adding a box to a paragraph in Word does not reflow it.

declare function paragraphBorderExtentPt(edge: ParagraphBorderEdge | undefined): number;

paragraphBordersfunctionSource ↗

Resolve w:pBdr from the paragraph-properties node.

Nested — every edge is a child of pBdr, not an attribute — so this reads the typed tree rather than the flattened OoxmlProperty[] bag propertiesOf builds for leaf props.

declare function paragraphBorders(pPr: OoxmlNode | undefined): ParagraphBorders;

paragraphBordersFingerprintfunctionSource ↗

Identity of a paragraph's border set, for the w:between group rule.

Word treats consecutive paragraphs whose border settings are IDENTICAL as ONE bordered block: the top rule draws above the first, the bottom rule below the last, and each interior boundary gets w:between or nothing (§17.3.1.24). That is why applying a box to three selected paragraphs in Word draws one box and not three.

Empty string means "no borders", which never groups with anything.

declare function paragraphBordersFingerprint(borders: ParagraphBorders): string;

paragraphBorderStrokeWidthPtfunctionSource ↗

Visual stroke thickness layout publishes for one edge (points).

Compound ST_Border values (double, …) use the shared inflated band so a thin w:sz="3" double still occupies a visible double-line box — matching table borders.

declare function paragraphBorderStrokeWidthPt(edge: ParagraphBorderEdge): number;

paragraphBreaksBeforefunctionSource ↗

Whether a paragraph must start a new page (w:pageBreakBefore).

LAST WINS, like every other toggle read off the cascade (paragraphKeeps does the same for w:keepNext). An any-wins .some() cannot be switched off: a Chapter or Heading style carries w:pageBreakBefore, and Word writes w:val="0" on the one instance whose author unchecked the box — that paragraph still broke, so the document grew a blank page and every page number after it was wrong.

An absent w:val is on (§17.17.4), and the off vocabulary is the whole of it — off is a spelling too, which [isOn](isOn) beside this already accepts.

declare function paragraphBreaksBefore(props: readonly OoxmlProperty[]): boolean;

paragraphContextualSpacingfunctionSource ↗

w:contextualSpacing (17.3.1.9): drop before/after between paragraphs of the SAME style. Word's built-in ListParagraph sets it, so every list authored in Word gets a paragraph gap between items without this.

declare function paragraphContextualSpacing(props: readonly OoxmlProperty[]): boolean;

paragraphFragmentsOffunctionSource ↗

Depth-first paragraph fragments of one page, in reading order.

Table interiors flatten through rows and cells; header-repeat rows are skipped unless asked for, so interaction sees each caret stop exactly once while paint sees everything.

declare function paragraphFragmentsOf(page: PageRecord, includeHeaderRepeats?: boolean): ParagraphFragmentRecord[];

paragraphFragmentsOfBlocksfunctionSource ↗

declare function paragraphFragmentsOfBlocks(blocks: readonly BlockFragmentRecord[], includeHeaderRepeats?: boolean): ParagraphFragmentRecord[];

paragraphLayoutKeyfunctionSource ↗

The cache key for one paragraph's measured break.

Folds in the content, the available width, and the measurement producer. Anything that changes where lines fall must be in here, or the cache serves a break taken under different conditions.

declare function paragraphLayoutKey(inputs: ParagraphKeyInputs): ParagraphLayoutKey;

paragraphLineSpacingfunctionSource ↗

Resolve w:line / w:lineRule from flat paragraph properties.

Merged per attribute for the same reason as before/after: w:spacing is one element carrying independent attributes, and a style that states only @line must not reset the rule an earlier entry in the cascade set.

declare function paragraphLineSpacing(props: readonly OoxmlProperty[]): ParagraphLineSpacing;

paragraphMarkDeletedfunctionSource ↗

w:pPr/w:rPr/w:del or w:moveFrom — a tracked revision REMOVES the paragraph mark.

Both say the break goes away once the decision is taken: a deletion outright, a moveFrom because the paragraph left this place for another. Read from the paragraph-mark run properties only. A w:del anywhere else in the paragraph deletes run content, which is a different statement entirely.

declare function paragraphMarkDeleted(paragraph: OoxmlNode): boolean;

paragraphMarkFormatRevisionOffunctionSource ↗

The tracked FORMAT change on a paragraph's own mark, from w:pPr/w:rPr/w:rPrChange.

CT_ParaRPr ends with it (§17.13.5.32), and Word writes it when a user changes the mark's own run properties with tracking on. It reaches the fragment rather than a span because it decorates no characters, and it is not in props: a fragment's props carry the mark's w:rPr by NAME only, with none of its children.

Note that w:rPrChange/w:rPr is CT_ParaRPrOriginal, which may carry its own revision marks. Those describe the mark as it WAS and must not be read as live ones, which is why this reads the change element's own attributes and never descends into it.

declare function paragraphMarkFormatRevisionOf(paragraph: OoxmlNode): RevisionAttribution | null;

paragraphMarkRevisionOffunctionSource ↗

Deprecated. Reads one of the revisions a mark can carry. Use [paragraphMarkRevisionsOf](paragraphMarkRevisionsOf), which answers with all of them.

The one decision on a paragraph's mark that a single-field reader sees.

declare function paragraphMarkRevisionOf(paragraph: OoxmlNode): RevisionAttribution | null;

paragraphMarkRevisionsOffunctionSource ↗

Every revision on a paragraph's own MARK, from w:pPr/w:rPr/w:ins|w:del|w:moveFrom|w:moveTo.

All four members of EG_ParaRPrTrackChanges. A moved paragraph carries w:moveFrom on the mark of the copy it left and w:moveTo on the mark of the copy it arrived at, so a move that spans whole paragraphs is recorded here and nowhere else.

EG_ParaRPrTrackChanges records that the pilcrow itself was inserted or deleted, which is how Word writes a paragraph split or merge. It is not content — there is no text to decorate — so a surface shows it as a mark of its own beside the paragraph, the way Word draws a struck- through ¶.

A LIST, because the group is ins? del? moveFrom? moveTo? and the first two can both be there: that pair is what Word writes when a second author proposes removing a mark the first proposed adding, and it is what this engine's own writer emits (tree-op-tracked.ts). Answering with the first one hid the second author's decision from the PAGE. The review pane walks the tree itself and always listed both, which is the worse shape of the two: a card offering a decision the reader could see no sign of.

Ordered as the file orders them, which is the order the group declares.

Property-position w:ins/w:del stay generic in the tree deliberately, so this reads them by name rather than by kind.

declare function paragraphMarkRevisionsOf(paragraph: OoxmlNode): readonly RevisionAttribution[];

paragraphOrderOfPartfunctionSource ↗

Paragraph node id → document position, from the tree rather than from layout.

Memoized on the immutable root: a derivation pass can ask repeatedly, and the shared answer stays read-only so a caller cannot poison later readers.

declare function paragraphOrderOfPart(part: OoxmlPart): ReadonlyMap<string, number>;

paragraphSectionNodefunctionSource ↗

w:sectPr nested under a paragraph's w:pPr, if present.

declare function paragraphSectionNode(paragraph: OoxmlElement): OoxmlElement | undefined;

paragraphShadingfunctionSource ↗

Resolve paragraph shading from cascaded flat w:pPr properties.

Later w:shd entries win (defaults → style → direct), matching spacing/border cascade.

declare function paragraphShading(props: readonly OoxmlProperty[]): string | undefined;

paragraphShadingBoxfunctionSource ↗

Page-content box for paragraph shading: union of this fragment's line boxes.

Excludes collapsed before/after spacing and bottom-border extent so the painted band matches Word's content-area fill (character shading height on a single line).

declare function paragraphShadingBox(lines: readonly {
    readonly box: LayoutBox;
}[], x: number, width: number): LayoutBox | undefined;

paragraphsInCellsfunctionSource ↗

Paragraph ids inside a set of cells, in document order, each once.

declare function paragraphsInCells(layout: SemanticLayout, cellIds: readonly string[]): readonly string[];

paragraphSpacingfunctionSource ↗

Resolve w:spacing before/after from flat paragraph properties.

Line spacing (w:line / w:lineRule) is a separate concern — it changes measured line height, not the gap between paragraphs — and is not resolved here.

w:beforeAutospacing / w:afterAutospacing REPLACE the authored measurement on their own side rather than adding to it; see [AUTO_PARAGRAPH_SPACING_PT](AUTO_PARAGRAPH_SPACING_PT).

declare function paragraphSpacing(props: readonly OoxmlProperty[], context?: ParagraphAutoSpacingContext): ParagraphSpacing;

paragraphTabStopsfunctionSource ↗

Direct w:pPr only — used when no style cascade table is present.

declare function paragraphTabStops(pPr: OoxmlNode | undefined): ResolvedTabStops;

paragraphTextFromLayoutfunctionSource ↗

The text of one paragraph, read back from the layout records.

Word boundaries need characters, and the records carry them: every span holds the text it was laid out from, keyed by the source range it covers. Reading them back keeps word motion in the interaction lane instead of making it a second consumer of the model.

declare function paragraphTextFromLayout(layout: SemanticLayout, paragraphId: string): string;

parseAutonumInstructionfunctionSource ↗

Recognize AUTONUM | AUTONUMLGL | AUTONUMOUT [\* <format>] [\e] [\* MERGEFORMAT], or null for anything else. Any unrecognized switch fails the parse so the field stays inert (paints nothing — its historical rendering), never the raw instruction, never a guessed number.

declare function parseAutonumInstruction(raw: string): AutonumFieldSpec | null;

parsePageBordersfunctionSource ↗

Parse w:pgBorders off one w:sectPr.

Undefined when the element is absent AND when it paints nothing — every edge off, or every edge an art border. Unlike w:pgNumType, an empty-but-present element is not distinguished: these properties are a LAYOUT input, serialization re-emits the canonical tree, and a frame with no edges has exactly one meaning downstream.

declare function parsePageBorders(sectPr: OoxmlNode): SectionPageBorders | undefined;

parsePageNumberingfunctionSource ↗

Parse authored w:pgNumType without inventing schema defaults.

Returns undefined when the element is absent. An empty element yields {} so callers can tell "present but unauthored" from "missing" and serialization can re-emit empty. Hostile / out-of-range attribute values are dropped rather than clamped into meaning.

declare function parsePageNumbering(sectPr: OoxmlNode): SectionPageNumbering | undefined;

parseRefInstructionfunctionSource ↗

Recognize REF <bookmark> [\r|\w|\n] [\t] [\h] [\* MERGEFORMAT] or NOTEREF <bookmark> [\h] [\* MERGEFORMAT], or null for anything else.

The keyword matches case-insensitively; the bookmark name keeps its authored case (it is a lookup key into a Map, never an object property, so hostile names like __proto__ are just names that resolve to nothing). Any unrecognized switch fails the parse so the field falls back to its cached result — never the raw instruction, never a guess. NOTEREF's \p (above/below position text) and \f (note-style formatting) are unrecognized on purpose.

declare function parseRefInstruction(raw: string): RefFieldSpec | null;

parseSectionPropertiesfunctionSource ↗

Parse one w:sectPr into geometry/break properties (null reads as Word's defaults).

declare function parseSectionProperties(sectPr: OoxmlNode | null | undefined): SectionProperties;

planRefFieldResultRefreshfunctionSource ↗

Plan the refresh for one body part, or null when every supported REF result is already fresh (the no-op save path — no transaction, no revision bump, no undo entry).

declare function planRefFieldResultRefresh(part: OoxmlPart, options: RefFieldRefreshOptions): RefreshFieldResultsOp | null;

positionPastDeletionfunctionSource ↗

Where an INSERT aimed at this position actually lands: past any deletion it sits inside.

The caret may rest anywhere in struck text — Word's rule, and the tracked lane's (tree-op-tracked.ts): all-markup shows the words, so the reader can put the caret between two of them. What may NOT happen is new content landing inside the w:del, where it would serialize as w:t under a wrapper that requires w:delText and be taken down by an accept of someone else's deletion. A deletion stays contiguous, so the words go after it — the order a replacement reads in.

RANGE endpoints are not this function's business: a drag may legitimately cover deleted text, so callers adjust only collapsed insertion points.

declare function positionPastDeletion(layout: SemanticLayout, position: SemanticPosition): SemanticPosition;

prepareLayoutFontConfigurationfunctionSource ↗

Copy and hash each usable face once for shared cache identity and admission.

declare function prepareLayoutFontConfiguration(configuration: LayoutFontConfiguration, instrumentation?: LayoutShapingInstrumentation): PreparedLayoutFontConfiguration;

projectedNoteMarkTextfunctionSource ↗

Resolve display text for a noteReference / noteRef node under a mark context.

declare function projectedNoteMarkText(node: OoxmlNode, context: NoteMarkContext | undefined): ProjectedNoteMark | null;

projectedSectionSourceIndexesfunctionSource ↗

Canonical section index behind each section in a revision-projected body.

A removed paragraph mark can collapse an entire section. The projected section keeps the surviving paragraph's geometry, while package APIs such as header/footer resolution remain indexed over the canonical tree. This bridge prevents those two index spaces from being paired positionally.

declare function projectedSectionSourceIndexes(part: OoxmlPart, displayMode?: RevisionDisplayMode, authorFilter?: RevisionAuthorFilter): readonly number[];

provisionalNoteMarksfunctionSource ↗

Build a continuous (pre-page) mark context for the first body layout pass. eachPage reserves digit width; [reprojectBodyNoteMarks](reprojectBodyNoteMarks) publishes final marks onto body citations after page assignment in [attachNotesToLayout](attachNotesToLayout).

declare function provisionalNoteMarks(refs: readonly PageRefHit[], input: NotesLayoutInput): NoteMarkContext;

readBorderSidefunctionSource ↗

Read one OOXML border child into the three-state model.

declare function readBorderSide(node: OoxmlElement | undefined): TableBorderSide;

readCellBordersfunctionSource ↗

Read one cell's w:tcBorders, under the same bounds [readTableBorders](readTableBorders) applies.

declare function readCellBorders(tcPr: OoxmlElement | undefined): CellBorderBox;

readNumPrfunctionSource ↗

Read w:numPr from cascaded paragraph-property nodes (lowest precedence first).

Flat OoxmlProperty[] bags drop nested ilvl/numId, so this walks the tree nodes the same way borders and tabs do.

w:ilvl and w:numId inherit INDEPENDENTLY through the style chain and the direct w:pPr (§17.3.1.19): a tier stating only the level keeps the id it inherits — Word's standard Heading2–Heading9 shape, where only Heading1 names the w:num — and a tier stating only the id keeps the inherited level. Treating each w:numPr node as a full replacement dropped the id at every level-only tier and unnumbered the paragraph. A stated w:numId w:val="0" (or an invalid value) still switches numbering off at that tier even when a lower tier set one; a higher tier stating a valid id re-enables. A level-only tier with no id inherited from below resolves to no numbering.

declare function readNumPr(paragraphPropertyNodes: readonly OoxmlNode[]): {
    numId: string;
    ilvl: number;
} | null;

readSectionPropertiesfunctionSource ↗

The section properties a part declares, or Word's defaults where it says nothing.

Returns the FINAL section (body-level w:sectPr, else the last paragraph-level one). Multi-section geometry belongs to enumerateDocumentSections; chrome that needs "the document's page" still reads the last section, which is what Word's body-level sectPr is.

declare function readSectionProperties(part: OoxmlPart): SectionProperties;

readTableBordersfunctionSource ↗

Read a table's w:tblBorders, dropping or clamping hostile values.

Widths and colours come from a file: an out-of-range w:sz becomes a layout dimension, so it is bounded here rather than downstream.

declare function readTableBorders(tblPr: OoxmlElement | undefined): TableBorderBox;

readTableStructurefunctionSource ↗

Read one typed table node into a bounded structure, or null when the node is not a typed table or sits beyond the nesting ceiling.

declare function readTableStructure(table: OoxmlNode, contentWidthPt: number, depth: number, styleCascade?: StyleCascadeTable, 
displayMode?: RevisionDisplayMode, authorFilter?: RevisionAuthorFilter, compatibilityMode?: number): SemanticTableStructure | null;

resetGraphemeBoundaryfunctionSource ↗

Restore the default Intl.Segmenter boundary and clear the memo.

declare function resetGraphemeBoundary(): void;

resolveBorderConflictfunctionSource ↗

Pick the winner between two candidates on a shared grid line (zero cell spacing).

none loses to any edge; two none/omitted yield omitted (no paint). Width decides; equal widths rank by style, then prefer the darker color, then preferFirst (reading-order / first candidate).

declare function resolveBorderConflict(first: TableBorderSide, second: TableBorderSide, preferFirst?: boolean): TableBorderSide;

resolveDefaultSurfaceMeasurerfunctionSource ↗

The surface's default measurer: canvas when a 2d context was injected, otherwise fixed.

Host-supplied and shaping measurers override this entirely — call only when the options did not already name one. The editor seam is responsible for creating the canvas context.

declare function resolveDefaultSurfaceMeasurer(scale?: number, options?: CanvasMeasurerOptions): ResolvedSurfaceMeasurer;

resolveDefaultWordBoundaryfunctionSource ↗

Cached immutable production boundary (first resolved instance only).

declare function resolveDefaultWordBoundary(): WordBoundary;

resolveNumberingLevelfunctionSource ↗

The effective level for one paragraph's numbering reference, after overrides and style links.

Answers null for a reference the index cannot resolve — a paragraph naming a definition the file never declared is an unnumbered paragraph, not an error.

declare function resolveNumberingLevel(index: NumberingIndex, numId: string, ilvl: number): {
    readonly abstractNumId: string;
    readonly level: NumberingLevel;
    readonly startOverride?: number;
} | null;

resolveOoxmlShadingFillfunctionSource ↗

Resolve a w:shd attribute bag to a validated RRGGBB fill, or undefined.

w:themeFill is a REFERENCE, and Word always writes the value it resolved to alongside it: <w:shd w:val="clear" w:fill="D9E2F3" w:themeFill="accent1" w:themeFillTint="33"/>. Reading w:fill in that case is not inventing a colour from the theme — it is reading the colour the producer computed. Dropping the fill because a theme reference sat next to it left every accent-shaded cell and paragraph unpainted.

val="nil" clears shading. Pattern vals are not rendered; a valid solid fill still paints as a clear fill until pattern support lands. A theme reference with no usable w:fill still resolves to nothing rather than a guess.

declare function resolveOoxmlShadingFill(attributes: Readonly<Record<string, string>> | undefined): string | undefined;

resolveParagraphLayoutInputsfunctionSource ↗

Resolve every paragraph input semantic layout / table cells share: cascaded props when a style table is present, otherwise direct formatting only.

When listItem is provided, its merged level indent becomes the paragraph indent (list hanging / left from numbering.xml), which is what Word uses for fixture list paragraphs that author no direct w:ind.

tableCellStyle carries what the enclosing table's style says about this cell's paragraphs; body paragraphs pass nothing.

inTableCell is asked for separately because a cell paragraph may have no table style to inherit at all, and w:beforeAutospacing still needs to know it is in a cell.

declare function resolveParagraphLayoutInputs(paragraph: OoxmlElement, contentWidth: number, styleCascade: StyleCascadeTable | undefined, listItem?: ResolvedListItem, tableCellStyle?: TableCellStyleFormatting, inTableCell?: boolean, lineUnitPt?: number): ParagraphLayoutInputs;

resolveRunStylefunctionSource ↗

Resolve one run's direct formatting.

Unrecognised values are DROPPED rather than guessed: a w:sz of "large" leaves the default size rather than inventing one, because a wrong measurement moves every glyph after it and a missing one is visible immediately.

themeFonts resolves w:rFonts theme references. Absent, a theme-only rFonts leaves the family inherited — which is what every run of a theme-fonted document does, so the whole document falls back to the surface default face.

declare function resolveRunStyle(props: readonly OoxmlProperty[], themeFonts?: ThemeFonts): ResolvedRunStyle;

resolveStoryListItemsfunctionSource ↗

Resolve every list paragraph in a story to a [ResolvedListItem](ResolvedListItem), keyed by node id.

Non-list paragraphs are absent from the map. Hostile / missing numbering resolves inertly (paragraph omitted — laid out as ordinary text).

declare function resolveStoryListItems(blocks: readonly OoxmlElement[], index: NumberingIndex, styleCascade: StyleCascadeTable | undefined, isFontAvailable?: (family: string) => boolean): ReadonlyMap<string, ResolvedListItem>;

resolveStoryRefFieldsfunctionSource ↗

Resolve the document's REF fields for one layout pass, or null when it has none.

Bookmarks and REF fields resolve across the body story and (when notes is given) the footnote/endnote stories, against ONE shared target index — a footnote REF finds the body bookmark it cites. Header/footer and text-box stories are not given a context and keep painting cached results.

declare function resolveStoryRefFields(blocks: readonly OoxmlElement[], listItems: ReadonlyMap<string, ResolvedListItem> | undefined, notes?: RefNoteParts): RefFieldContext | null;

resolveStrictHexFillfunctionSource ↗

Strict hex fill: exactly six hex digits. Rejects auto, nil, and any non-hex payload (CSS functions, URLs, short hex, theme tokens).

declare function resolveStrictHexFill(raw: string | undefined): string | undefined;

resolveTableCellBorderGridfunctionSource ↗

Resolve borders for every cell in a laid-out table fragment.

Shared vertical edges: conflict(left.right, right.left) → assigned to the left cell, segmented per row when a vMerge restart faces differing neighbors. Shared horizontal edges: conflict(above.bottom, below.top) → assigned to the above cell, segmented per grid column when a gridSpan cell faces differing below neighbors; vMerge interior seams are suppressed per interval.

When geometry is provided, compound edges expand into explicit stroke records with corner-adjusted endpoints in cell-local points.

declare function resolveTableCellBorderGrid(rows: readonly (readonly BorderGridCell[])[], table: TableBorderBox, columnCount: number, geometry?: BorderGridGeometry, work?: TableBorderGridResolveWork, ownershipBudget?: TableBorderOwnershipBudget): ResolvedCellBorders[][];

reviewAnchorIndexfunctionSource ↗

Paragraph id to its place on the page, in ONE pass over the layout.

Built once per layout and reused by every card. The straightforward version — scan the pages until the paragraph turns up, per card — is a full-document walk per card, and a contract with two hundred comments walked the document two hundred times every time the caret moved. Toggling the pane was visibly slow for exactly that reason.

declare function reviewAnchorIndex<TPage extends {
    readonly index: number;
    readonly contentBox: {
        readonly y: number;
    };
}>(layout: {
    readonly pages: readonly TPage[];
}, paragraphFragments: (page: TPage) => readonly {
    readonly paragraphId: string;
    readonly box: {
        readonly y: number;
    };
    readonly lines?: readonly {
        readonly range: {
            readonly end: number;
        };
        readonly box: {
            readonly y: number;
        };
        readonly spans?: readonly {
            readonly range: {
                readonly paragraphId: string;
                readonly end: number;
            };
        }[];
    }[];
}[]): Map<string, ReviewParagraphAnchor>;

reviewItemGeometryfunctionSource ↗

Where a card belongs beside the page, from LAYOUT RECORDS.

The one question the tree cannot answer, and the one a surface must not answer for itself: measuring painted DOM puts the sidebar a repaint behind the document and breaks outright while pagination is in flight.

Returns null when the item has no resolvable range, or when its paragraph is not in this layout — a comment anchored in a header belongs to a story the body layout never saw.

declare function reviewItemGeometry(item: ReviewItem, index: ReadonlyMap<string, ReviewParagraphAnchor>): {
    readonly pageIndex: number;
    readonly y: number;
} | null;

reviewItemKeyfunctionSource ↗

The stable key a surface uses for the active item and for a React list.

declare function reviewItemKey(item: ReviewItem): string;

reviewItemPositionRankfunctionSource ↗

A single comparable number for document order.

Paragraph index dominates offset, so a revision spanning paragraphs still sorts by where it STARTS. An item with no resolvable range sorts last rather than to position zero, which is where an orphan used to land — tearing an orphaned reply out of its own thread.

declare function reviewItemPositionRank(item: ReviewItem, order: ReadonlyMap<string, number>): number;

reviewItemRangesfunctionSource ↗

Every range a decision touches. One card can cover several, in different paragraphs.

declare function reviewItemRanges(item: ReviewItem): readonly ReviewRange[];

reviewItemsAtfunctionSource ↗

Every item covering a position, innermost first.

Returning the whole stack rather than one winner is what lets a surface offer cycling, a stacked card, or a "1 of 3" affordance. A comment wrapping a revision used to be unreachable because only the tightest range was ever returned.

declare function reviewItemsAt(items: readonly ReviewItem[], position: ReviewPosition, order: ReadonlyMap<string, number>): ReviewItem[];

reviewThreadRootOffunctionSource ↗

Walk a reply up to the card that heads its thread. Guarded against a cyclic file.

The head is not always a comment. A reply to a tracked change renders inside the REVISION's card, so resolving it to itself opened an item nothing on screen was drawing — the reply box vanished the moment somebody answered a change.

EXPORTED because the paginated surface answers "which card is open" itself, against its own dismissed-key state, rather than through [activeReviewItem](activeReviewItem). Two copies of the innermost-wins rule was survivable while a reply could only be a comment — the parent came first in comments.xml order and won the tie by accident. It stopped being survivable the moment a reply could answer a revision, which outranks it outright.

declare function reviewThreadRootOf(items: readonly ReviewItem[], comment: ReviewCommentItem): ReviewItem;

revisionAuthorFilterfunctionSource ↗

Build a canonical reviewer filter. An empty input returns undefined for the fast path.

declare function revisionAuthorFilter(hiddenAuthors: Iterable<string>): RevisionAuthorFilter | undefined;

revisionRemovesParagraphfunctionSource ↗

True when a tracked revision has removed this paragraph from the rendered document, so layout should emit no box for it at all.

declare function revisionRemovesParagraph(paragraph: OoxmlNode, displayMode?: RevisionDisplayMode, authorFilter?: RevisionAuthorFilter): boolean;

revisionsAreDeletionfunctionSource ↗

True when this stack of revisions marks its content as deleted from the live document.

declare function revisionsAreDeletion(revisions: readonly RevisionAttribution[]): boolean;

revisionsVisiblefunctionSource ↗

Whether content under this stack of revisions is laid out in the given mode.

Containment governs, so a single enclosing wrapper the mode resolves away suppresses everything inside it regardless of what the inner wrappers say. An insertion inside a deletion does not survive the proposed result: the deletion it sits in was accepted.

declare function revisionsVisible(revisions: readonly RevisionAttribution[], mode: RevisionDisplayMode, authorFilter?: RevisionAuthorFilter): boolean;

roundFontUnitToFixedPointfunctionSource ↗

Convert signed font units by an exact rational multiplier using the declared tie rule.

roundFontUnitToFixedPoint: (fontUnits: number, denominator: number, numerator: number, mode: FixedPointRoundingMode) => FixedPoint

runStylesEqualfunctionSource ↗

Whether two resolved styles are identical, for span merging and cache keys.

declare function runStylesEqual(a: ResolvedRunStyle, b: ResolvedRunStyle): boolean;

segmentGraphemesfunctionSource ↗

Split text into graphemes through the active boundary.

Memoized on the last texts seen, because paragraph layout asks about the same string repeatedly and a full segmentation pass per call made layout quadratic in paragraph length.

declare function segmentGraphemes(text: string): readonly GraphemeSegment[];

segmentWordsfunctionSource ↗

Split text into word segments through the given boundary, or the resolved default.

declare function segmentWords(text: string, boundary?: WordBoundary): readonly WordSegment[];

selectionRectsfunctionSource ↗

The physical rectangles covering a selection, including disjoint bands within bidi lines.

BODY fragments only, and a selection outside the body paints nothing. That is a real gap — a retained pin in a header shows no highlight, and a comment anchored in one draws no band even though the review queue lists it — but it is the honest shape of what this can answer today. Widening the walk to the other stories is not enough on its own: header and footer fragments carry positions relative to their own story box, note fragments relative to their note area, and one header story object is attached to EVERY page it applies to. Fed straight into a page-content-relative rect, those produce a band per page, at coordinates belonging to a different box. Measured, that put a header comment's band on all six pages of a document at the top-left of the body text. Painting nothing is wrong; painting over the wrong words is worse, so the walk stays here until the geometry is carried with it.

declare function selectionRects(layout: SemanticLayout, selection: SemanticSelection, 
order: readonly string[], 
measurer?: TextMeasurer): SelectionRect[];

semanticHorizontalBoundariesfunctionSource ↗

Grapheme offsets corresponding to exact shaped boundaries.

declare function semanticHorizontalBoundaries(run: ShapedRun): readonly number[];

setGraphemeBoundaryfunctionSource ↗

Install a different segmentation strategy, invalidating the memo.

For tests and for runtimes lacking Intl.Segmenter. Call [resetGraphemeBoundary](resetGraphemeBoundary) to restore the default.

declare function setGraphemeBoundary(boundary: GraphemeBoundary): void;

setHarfBuzzWasmUrlfunctionSource ↗

Point the text shaper at an externally hosted copy of harfbuzz.wasm.

Needed only under bundlers that do not emit new URL(..., import.meta.url) assets. esbuild and Bun are the common ones, and so is any build that inlines dynamic imports, such as a library bundle. There, the build succeeds and the shaper fails at runtime with an EditorFontError whose code is wasmUnavailable; this function is the fix. Webpack, Turbopack and Vite emit the binary on their own, and passing a URL there simply overrides theirs.

ts import { setHarfBuzzWasmUrl } from '@docx-editor.dev/core/layout'; setHarfBuzzWasmUrl('/static/harfbuzz.wasm');

Pass a URL your application controls. It is fetched and instantiated as WebAssembly, so never derive it from user input, a query parameter, or remote configuration. Serving it cross-origin needs that origin in your connect-src CSP directive, and WebAssembly needs wasm-unsafe-eval in script-src either way.

Call it before the first editor is created. The runtime reads the location once and caches the result, so a call afterwards warns and does nothing: fix the call site and reload. The file to serve is exported as @docx-editor.dev/core/harfbuzz.wasm, and it must be the copy from the installed package version, because the runtime refuses a version mismatch at load rather than shaping with unverified metrics.

declare function setHarfBuzzWasmUrl(url: string | URL): void;

sha256FontBytesfunctionSource ↗

Synchronous platform-neutral SHA-256 used before font bytes cross into a shaping implementation.

sha256FontBytes: (bytes: Uint8Array) => string

shadingFillFromElementfunctionSource ↗

Read w:shd from a typed/generic element (table tcPr, nested pPr, …).

declare function shadingFillFromElement(shd: OoxmlElement | undefined): string | undefined;

shapedHorizontalBoundariesfunctionSource ↗

UTF-16 boundaries that are both whole-grapheme and HarfBuzz cluster edges.

declare function shapedHorizontalBoundaries(run: ShapedRun): readonly number[];

shapedRunComparatorInputsfunctionSource ↗

Reduce a shaped run to its comparable form, validating it on the way through.

What the D9 determinism oracles compare: two shaping runs of the same text in the same environment must produce byte-identical structures here.

shapedRunComparatorInputs: (input: ShapedRun, environment: ShapingEnvironmentInput) => ShapedRunComparatorInputs

shapingEnvironmentFingerprintfunctionSource ↗

Canonical serialization of every shaping variable, including byte hash and provenance.

shapingEnvironmentFingerprint: (environment: ShapingEnvironmentInput) => string

shapingEnvironmentFingerprintInputsfunctionSource ↗

Reduce an environment to its comparable form, with records sorted so key order cannot affect the result.

shapingEnvironmentFingerprintInputs: (input: ShapingEnvironmentInput) => ShapingEnvironmentFingerprintInputs

shownMarkRevisionfunctionSource ↗

The single decision a one-field reader sees.

A DELETION wins when a mark carries both, for the reason paint draws it that way: a break proposed and then unproposed ends up removed, so that is the decision a reader who can only see one must see. One function decides it, so the deprecated field, the deprecated function and the painted glyph cannot answer differently.

declare function shownMarkRevision(revisions: readonly RevisionAttribution[]): RevisionAttribution | undefined;

spanOffsetXfunctionSource ↗

The x of a model offset inside a span — the inverse of [offsetWithinSpan](offsetWithinSpan).

Shares the measurement, and the cache, with the hit test. Interpolating across the span's advance instead is exact only for a uniform one: in a proportional face the caret for offset 4 of an 8-character span is drawn at half its width, which lands in the middle of a glyph rather than between two.

declare function spanOffsetX(span: StyleSpanRecord, offset: number, measurer: TextMeasurer | undefined): number;

spansInCellsfunctionSource ↗

The style spans a cell selection covers, for reporting active formatting.

declare function spansInCells(layout: SemanticLayout, cellIds: readonly string[]): readonly StyleSpanRecord[];

spansInSelectionfunctionSource ↗

The style spans a selection touches, for reporting active formatting.

declare function spansInSelection(layout: SemanticLayout, selection: SemanticSelection, 
order: readonly string[]): StyleSpanRecord[];

storyBlocksfunctionSource ↗

The story's blocks — paragraphs and tables — in document order, flattening through block-level content-control wrappers under the shared nesting budget.

Repeated calls with the same part and display mode return the SAME array instance, shared by every caller — treat it as read-only; mutating it corrupts later callers.

declare function storyBlocks(part: OoxmlPart, displayMode?: RevisionDisplayMode, authorFilter?: RevisionAuthorFilter): OoxmlElement[];

styleForFontSlotfunctionSource ↗

The style a piece's text is MEASURED AND PAINTED in, given the font slot it carries.

This is the measurer-boundary resolution: pieces and spans keep the run's real resolved style — with fontFamily and fontFamilyEastAsia both intact, so formatting readback and the format painter see the run as authored — and every consumer that turns text into geometry or ink resolves the face through here. The derived object is memoized per (style, family) by [withFontFamily](withFontFamily), so measurers amortizing over style identity keep their caches.

declare function styleForFontSlot(style: ResolvedRunStyle, slot: FontSlot | undefined): ResolvedRunStyle;

syntheticSeparatorBoxfunctionSource ↗

Default rule geometry for a synthetic / marker-only separator, story-relative.

declare function syntheticSeparatorBox(contentWidth: number, flowHeight: number): LayoutBox;

tabAdvanceWidthfunctionSource ↗

Width of a tab glyph so the following segment lands on the destination.

segmentWidth / decimalOffset are already measured in points. Decimal offset is the advance from the segment start to the decimal point (0 when none — treated like right).

declare function tabAdvanceWidth(alignment: TabAlignment, currentX: number, destinationX: number, segmentWidth: number, decimalOffset: number): number;

tableContextAtfunctionSource ↗

The table context of one paragraph — what a toolbar reflects when the caret is in a cell.

Answers for a plain caret, not only for a cell selection, because "am I in a table" is a question about where the caret is and a toolbar that only knew during a rectangle drag would show its table controls disabled while the user was typing in a cell.

declare function tableContextAt(layout: SemanticLayout, paragraphId: string): TableCellContext | null;

tableOriginXfunctionSource ↗

Where a table's left edge sits inside the box that contains it.

Ordinary left-aligned tables start at their indent; centered/right-aligned tables use the remaining width. A verified legacy content-aligned table instead aligns the leading cell's content edge with the text column, without changing its indent.

declare function tableOriginX(structure: SemanticTableStructure, containerWidthPt: number): number;

tabStopsFingerprintfunctionSource ↗

Stable fingerprint for layout cache keys — nested w:tabs are not in flat OoxmlProperty bags, so style-inherited stops must be named explicitly or breaks would collide.

declare function tabStopsFingerprint(tabs: ResolvedTabStops): string;

tocFieldChromeParagraphIdsfunctionSource ↗

Paragraph ids for TOC field begin/end chrome that must not reserve vertical flow when empty.

declare function tocFieldChromeParagraphIds(part: OoxmlPart): ReadonlySet<string>;

tryCreateCanvasMeasurerfunctionSource ↗

Build a canvas-backed measurer, or null when no 2d context was injected.

Prefer [resolveDefaultSurfaceMeasurer](resolveDefaultSurfaceMeasurer) at the editor surface: that keeps the fixed fallback for SSR/tests in one place.

declare function tryCreateCanvasMeasurer(options?: CanvasMeasurerOptions): TextMeasurer | null;

unionLayoutBoxesfunctionSource ↗

Axis-aligned union of boxes, or null when the list is empty.

Used when a control's content spans several fragments or spans on one page.

declare function unionLayoutBoxes(boxes: readonly LayoutBox[]): LayoutBox | null;

utf16OffsetToGraphemefunctionSource ↗

The grapheme index containing a UTF-16 offset. Clamps rather than throwing.

Backed by a single-entry index cache: this runs once per character during paragraph layout, and re-segmenting per call is what made a 20,000-character paragraph take minutes to open. One entry rather than a map, because the keys are file-derived strings of unbounded size.

declare function utf16OffsetToGrapheme(text: string, utf16Offset: number): number;

walkStoryParagraphsfunctionSource ↗

Collect paragraphs of a block list in document order, descending into tables.

Caps nesting so a hostile nested-table document cannot recurse without bound.

declare function walkStoryParagraphs(blocks: readonly OoxmlElement[], maxTableDepth?: number): OoxmlElement[];

withDefaultTabIntervalfunctionSource ↗

Republish stops under a document-wide default-tab interval (w:defaultTabStop).

The cascade resolves stops from the paragraph's own property chain, which cannot see settings.xml; the interval is a document constant that arrives from the session. Returns the input unchanged when nothing moves, so a cache-key fingerprint stays stable.

declare function withDefaultTabInterval(tabs: ResolvedTabStops, defaultIntervalPt: number | undefined): ResolvedTabStops;

Resolve w:numStyleLink delegation using the document's styles (§17.9.21).

Without a style table there is nothing to follow, so the index is returned unchanged — and so it is when nothing delegates, which keeps layout cache identity.

declare function withNumberingStyleLinks(index: NumberingIndex, styleCascade: StyleCascadeTable | undefined): NumberingIndex;

withResolvedListItemsfunctionSource ↗

Attach a full-story list-item map to layout options.

Resolves once over blocks (body story including table cells) so counters continue across section boundaries. No-ops when numbering is absent.

declare function withResolvedListItems<T extends {
    readonly numberingIndex?: NumberingIndex;
    readonly listItems?: ReadonlyMap<string, ResolvedListItem>;
    readonly styleCascade?: StyleCascadeTable;
    readonly isFontAvailable?: (family: string) => boolean;
}>(options: T, blocks: readonly OoxmlElement[]): T & {
    readonly numberingIndex: NumberingIndex;
    readonly listItems?: ReadonlyMap<string, ResolvedListItem>;
};

wordBoundaryfunctionSource ↗

The next word boundary from offset, in direction.

Word-LEFT skips any whitespace immediately behind the caret and then the word behind that, which makes repeated presses walk words rather than alternate with the preceding space.

stops are offsets a word may not run THROUGH even when the characters either side are word characters. They exist because the text this walks is what the VIEW is showing, and a view can show two versions of the document side by side: struck text and the text proposed to replace it abut with no separator, so ALL CAPS deleted and fsdfsd inserted read as the single word CAPSfsdfsd. Those characters are never adjacent in any one version, and a double-click that took both selected across a decision the reader had not made. See deletedTextBoundaries.

declare function wordBoundary(text: string, offset: number, direction: -1 | 1, stops?: ReadonlySet<number>): number;

wordSegmentsToGraphemeRecordsfunctionSource ↗

Map UTF-16 word segments to grapheme-safe half-open ranges within one paragraph.

declare function wordSegmentsToGraphemeRecords(text: string, segments: readonly WordSegment[]): readonly GraphemeWordSegmentRecord[];

Classes (6)

FontResolutionErrorclassSource ↗

A face that could not be admitted, carrying whatever evidence the refusal produced.

RETURNED rather than thrown by FontResourceSnapshot.resolve, because a missing face is an ordinary condition — layout falls back and carries on. It extends Error so a caller that would rather throw can.

declare class FontResolutionError extends Error
MemberTypeSummary
(constructor)Constructs a new instance of the `FontResolutionError` class
actual?number
actualHash?string
codeFontResolutionErrorCode
diagnostic?string
expectedHash?string
limit?number
name
requestFontRequest

HarfBuzzShapingErrorclassSource ↗

A shaping call that was refused, carrying the limit it exceeded where there was one.

Thrown rather than returned: unlike a missing font, a run that cannot be shaped has no sensible fallback measurement, and continuing would lay text out at made-up widths.

declare class HarfBuzzShapingError extends Error
MemberTypeSummary
(constructor)Constructs a new instance of the `HarfBuzzShapingError` class
actual?number
codeHarfBuzzShapingErrorCode
diagnostic?string
limit?number
name

LayoutShapingConfigurationErrorclassSource ↗

Invalid host configuration caught before any bytes reach HarfBuzz.

declare class LayoutShapingConfigurationError extends Error
MemberTypeSummary
(constructor)Constructs a new instance of the `LayoutShapingConfigurationError` class
code"overLimit"

ResolvedCacheclassSource ↗

The layout measurement cache, keyed by fingerprint rather than by revision.

An entry may be reused ACROSS revisions: the model revision is recorded as PROVENANCE, not as an equality condition. Reuse is proven only when the transitive dependency fingerprint, the unit's own input fingerprint, and every non-model environment input all match — which is what lets an edit in one paragraph leave the rest of a long document measured.

declare class ResolvedCache<V>
MemberTypeSummary
evictEpochDrop entries produced against a stale operation epoch — restart affected work on an epoch change (8.3). Returns the number evicted.
evictResourcesEvict only entries whose consumed resource fingerprint changed at the new resource epoch.
getLook up `key` against the CURRENT fingerprints + snapshot (revision excluded from the match). A hit proves the entry is unaffected; a miss names the reason (absent/dependency/input/epoch).
setStore a freshly computed entry with full provenance.
sizenumber

TablePaginationErrorclassSource ↗

Bounded table pagination failure. Prefer this over emitting a fragment that overflows the page content box.

declare class TablePaginationError extends Error
MemberTypeSummary
(constructor)Constructs a new instance of the `TablePaginationError` class
codeTablePaginationErrorCode

UnsupportedScriptErrorclassSource ↗

A code point whose script this engine does not itemize.

Carries the offending codePoint so the caller can report which character stopped it, rather than failing anonymously somewhere in the middle of a paragraph.

declare class UnsupportedScriptError extends Error
MemberTypeSummary
(constructor)Constructs a new instance of the `UnsupportedScriptError` class
code
codePointnumber
name

Interfaces (220)

AbstractNumDefinitioninterfaceSource ↗

One w:abstractNum — the shape of a list, without being a list.

Never referenced by a paragraph directly. Paragraphs name a [NumDefinition](NumDefinition), which names one of these, so several lists can share a definition and still count separately.

interface AbstractNumDefinition
MemberTypeSummary
abstractNumIdstring
levelsReadonlyMap<number, NumberingLevel>

AnchoredDrawingRecordinterfaceSource ↗

interface AnchoredDrawingRecord extends Omit<InlineDrawingRecord, 'kind' | 'baselineOffset' | 'advanceStart' | 'advanceEnd' | 'distL' | 'distR' | 'distT' | 'distB'>
MemberTypeSummary
allowOverlapboolean
anchorParagraphIdstring
behindDocumentboolean
horizontalFrameDrawingHorizontalReferenceFrame
horizontalFrameOriginnumber
kind'anchoredDrawing'
layoutFallback?AnchoredDrawingLayoutFallback
layoutInCellboolean
relativeHeightnumber
sourceOrder?numberCanonical document traversal index within the owner story part.
textboxStory?TextboxStoryLayoutLaid-out textbox story for a `wps:txbx` drawing; paint renders it clipped inside the extent instead of a placeholder. Absent when the drawing carries no story or the host did not thread story layout (the record then degrades to the placeholder path).
verticalFrameDrawingVerticalReferenceFrame
verticalFrameOriginnumber
wrapExclude<ImageWrapTarget, 'inline'>

AutonumFieldSpecinterfaceSource ↗

One recognized AUTONUM-family instruction: the kind and its supported switches.

interface AutonumFieldSpec
MemberTypeSummary
kindAutonumFieldKind
numFmtstring | nullST_NumberFormat resolved from the `\*` switch; null paints decimal.
suppressPeriodboolean`\e`: display the number without its trailing period.

BidiEmbeddingLevelsinterfaceSource ↗

UAX #9 embedding levels, one per UTF-16 code unit, plus the paragraph ranges they were resolved within.

The level is EXACT, not a direction: its parity gives direction, but the numeric value is what reordering needs, and collapsing it early loses nested isolates.

interface BidiEmbeddingLevels
MemberTypeSummary
levelsUint8Array
paragraphsreadonly { readonly start: number; readonly end: number; readonly level: number; }[]

BorderGridGeometryinterfaceSource ↗

The absolute grid a table's borders are drawn on: column widths, and per-row tops and heights.

Shared by every edge so adjacent cells resolve to the SAME line, rather than each computing its own and leaving a hairline gap between them.

interface BorderGridGeometry
MemberTypeSummary
cellBoxesreadonly (readonly { readonly width: number; readonly height: number; }[])[]Per laid-out cell: width/height after vMerge expansion (cell-local stroke space).
columnWidthsPtreadonly number[]Absolute column widths for the whole table (points).
rowBandsreadonly { readonly y: number; readonly height: number; }[]Per laid-out row: absolute top and height in the same coordinate space as cell boxes (only relative differences matter for vertical edge segmentation).

CacheProvenanceinterfaceSource ↗

Everything recorded with a cache entry: the model revision (provenance only) + the fingerprints and snapshot that DO gate reuse.

interface CacheProvenance extends OperationSnapshot
MemberTypeSummary
dependencyFingerprintstringFingerprint of the transitive dependency closure (see DependencyGraph.fingerprint).
inputFingerprintstringFingerprint of the unit's own direct inputs (its content).
resourceDependenciesreadonly ResourceDependencyProvenance[]Exact operation resources this entry consumed, sorted by key.
revisionnumberModel revision the entry was computed at — provenance, NOT compared for reuse.

CanvasMeasurerOptionsinterfaceSource ↗

How the canvas measurer resolves fonts, scales, and bounds its caches. Every field optional.

Layout never creates a canvas itself: without a context this measurer does not exist and the surface falls back to fixed metrics.

interface CanvasMeasurerOptions
MemberTypeSummary
context?CanvasTextContext | nullInjected 2d text context from the editor/browser seam.
fallbackFamily?string
fontAlias?(family: string) => string | undefinedThe engine-minted family a document-embedded face was registered under, if any.
maxMetricsEntries?numberDistinct font-shorthand line metrics retained before LRU eviction.
maxWidthEntries?numberUnique `(font, text)` width entries retained before LRU eviction.
scale?numberLayout units to CSS pixels — the same value the painter uses.

CanvasTextContextinterfaceSource ↗

The slice of a 2D canvas context measurement needs.

A structural subset rather than CanvasRenderingContext2D, so layout stays DOM-free and a test can supply a deterministic stub.

interface CanvasTextContext
MemberTypeSummary
direction?'ltr' | 'rtl' | 'inherit'
fontstring
measureText
textAlign?'left' | 'right' | 'center' | 'start' | 'end'

CanvasTextMetricsinterfaceSource ↗

The canvas text-metrics surface the editor injects.

Structural subset of CanvasRenderingContext2D — declared here so the layout lane stays off the DOM lib. Hosts pass a real 2d context; tests pass a controllable mock.

interface CanvasTextMetrics
MemberTypeSummary
actualBoundingBoxLeft?number
actualBoundingBoxRight?number
fontBoundingBoxAscent?number
fontBoundingBoxDescent?number
widthnumber

CaretAtOptionsinterfaceSource ↗

How caret geometry is resolved.

preferPage disambiguates a paragraph that paints on SEVERAL pages — a shared header appears once per page, and without a preference the caret could be placed on any of its copies.

interface CaretAtOptions
MemberTypeSummary
measurer?TextMeasurer
preferredPageIndex?numberPrefer geometry from this sheet when the same paragraph paints on multiple pages (shared header/footer copies).

CaretGeometryinterfaceSource ↗

A caret position with the geometry that renders it.

interface CaretGeometry
MemberTypeSummary
heightnumber
lineIdstring
pageIndexnumber
positionSemanticPosition
xnumberPage-relative, in the same coordinate space as the line boxes.
ynumber

CascadedParagraphFormattinginterfaceSource ↗

A paragraph's properties after the cascade, plus the same list WITHOUT its own w:pPr.

Both, because a writer needs to know what a paragraph INHERITS to decide whether setting a value is a change or a no-op — and writing back an inherited value freezes it into the paragraph as though the author had chosen it.

interface CascadedParagraphFormatting
MemberTypeSummary
inheritedParagraphPropertiesreadonly OoxmlProperty[]The same list WITHOUT the paragraph's own `w:pPr` — everything it inherits.
markRunPropertiesreadonly OoxmlProperty[]Content cascade plus direct `w:pPr/w:rPr` — empty-line metrics and last-line mark height.
paragraphPropertiesreadonly OoxmlProperty[]Flat paragraph properties in cascade order (defaults → bases → style → direct).
paragraphPropertyNodesreadonly OoxmlNode[]Matching `w:pPr` nodes for nested border resolution.
runPropertiesreadonly OoxmlProperty[]Inherited run properties for CONTENT runs (before direct run `rPr`).
styleIdstring | nullThe style this paragraph resolved to, or null when it names none and there is no document default. `w:contextualSpacing` compares neighbours by exactly this.

CellBorderBoxinterfaceSource ↗

The four resolved edges of one cell, after conflict resolution against its neighbours.

interface CellBorderBox
MemberTypeSummary
bottomTableBorderSide
leftTableBorderSide
rightTableBorderSide
topTableBorderSide

CellMarginsPtinterfaceSource ↗

Resolved cell padding in points, after the table default and any per-cell override.

interface CellMarginsPt
MemberTypeSummary
bottomnumber
leftnumber
rightnumber
topnumber

CellSelectioninterfaceSource ↗

A rectangle of table cells.

interface CellSelection
MemberTypeSummary
cellIdsreadonly string[]Every selected `w:tc`, in document order, with merges resolved.
columns{ readonly from: number; readonly to: number; }Inclusive grid columns.
kind'cells'
rows{ readonly from: number; readonly to: number; }Inclusive row ordinals within the table.
tableIdstringCanonical node id of the `w:tbl`.
textSemanticSelectionThe equivalent text range.

CjkTypographySettingsinterfaceSource ↗

Document-wide East Asian line-break and whitespace policy.

interface CjkTypographySettings
MemberTypeSummary
afterReadonly<Record<string, string>>Custom no-line-end characters, keyed by normalized language tag.
beforeReadonly<Record<string, string>>Custom no-line-start characters, keyed by normalized language tag.
compression'doNotCompress' | 'compressPunctuation' | 'compressPunctuationAndJapaneseKana'Whitespace compression selected by `w:characterSpacingControl`.
strictbooleanApply the strict Japanese small-kana and prolonged-sound-mark restrictions.

CommentAnchorinterfaceSource ↗

Where a comment is anchored, as a range.

orphaned records that the file did not give this comment a usable range — a reference with no range markers, or a start with no end. The comment is still listed, marked orphaned, rather than dropped: a reviewer's remark disappearing silently is worse than one that says it lost its text.

interface CommentAnchor
MemberTypeSummary
commentIdstring
endCommentPosition
orphanedboolean
partNamestringCanonical name of the part the range lives in, so a header comment is attributable.
startCommentPosition

CommentPositioninterfaceSource ↗

A position in one story: a paragraph node id plus a UTF-16 offset inside it.

interface CommentPosition
MemberTypeSummary
offsetnumber
paragraphIdstring

CommentRecordinterfaceSource ↗

One comment as authored in word/comments.xml.

interface CommentRecord
MemberTypeSummary
authorstring
blocksreadonly OoxmlElement[]Body paragraphs, as tree nodes, so the surface renders measured text rather than a string.
date?string
idstring
initials?string
paraId?string`w14:paraId` of the last body paragraph — the key thread state is stored under.
parentCommentId?string`@w16cid:parentId` — the `w:id` of the comment this replies to, when the file names it.

CommentThreadStateinterfaceSource ↗

Thread state for one comment, read from commentsExtended.xml.

interface CommentThreadState
MemberTypeSummary
doneboolean
parentParaId?string`@w15:paraIdParent` — the comment this one replies to, absent for a top-level comment.

CompoundBorderMetricsinterfaceSource ↗

How a multi-line border style (double, triple) is drawn: stroke width, gap, and total extent.

The band is CENTRED on the authored width, so a double border occupies the space Word gives it rather than growing the cell it surrounds.

interface CompoundBorderMetrics
MemberTypeSummary
extentPtnumber
gapPtnumber
insetPtnumberCenters the compound band on the authored width; negative extends outward.
strokePtnumber

ContentControlBoundaryRecordinterfaceSource ↗

Layout-published boundary for one content control (w:sdt / typed contentControl).

Chrome, lock feedback, and hit resolution read this record — never painted DOM. The wrapper itself is not a layout box; fragments cover the content that already flowed in place.

interface ContentControlBoundaryRecord
MemberTypeSummary
alias?string
boundboolean`w:dataBinding` is present — content edits are refused as bound.
controlTypeContentControlMappedType
effectiveLockContentControlLockNested lock union with every ancestor control, collapsed back to a single `ST_Lock` vocabulary value (both axes locked → `sdtContentLocked`).
fragmentsreadonly ContentControlGeometryFragment[]
idstringCanonical node id of the control wrapper — not `w:id`.
levelContentControlLevel
lockContentControlLockThis control's own `w:lock`, before ancestor union.
nestingDepthnumber0 for a top-level control; increments through nested wrappers under the shared nesting bound.
placeholderboolean`w:showingPlcHdr` is present on the control's properties.
tag?string

ContentControlFragmentRecordinterfaceSource ↗

One page-local rectangle covering the part of a control that sits on that page.

interface ContentControlFragmentRecord extends LayoutBox
MemberTypeSummary
pageIndexnumber

ContentControlGeometryFragmentinterfaceSource ↗

One piece of a control's content geometry.

A block control that crosses a page break publishes one fragment per page rather than a single rectangle covering the inter-page gap. An inline control publishes one fragment per LINE it touches, covering the text's vertical extent (line-spacing leading excluded), so a wrapped control never claims the words beside it. Coordinates match fragment boxes (page-content space).

interface ContentControlGeometryFragment
MemberTypeSummary
boxLayoutBox
pageIndexnumber

CreateDocumentFurnitureSourceOptionsinterfaceSource ↗

Inputs that remain valid for the lifetime of one furniture source.

interface CreateDocumentFurnitureSourceOptions
MemberTypeSummary
cacheParagraphLayoutCache<readonly PendingLine[]>
compatibilityMode?() => number | undefined
defaultTabStopPt?() => number
displayMode?RevisionDisplayMode
drawingLayoutTokenForPart?(partName: string) => string
drawingTokenForParagraphForPart?(partName: string, paragraph: OoxmlNode) => string
inlineDrawingLayoutForPart?(partName: string) => InlineDrawingLayoutContext | undefined
linkProjectorsDocumentLinkProjectorsLink/property projection and its inseparable cache identities.
measurerTextMeasurer
numberingIndex?() => NumberingIndex
producerstring
revisionAuthorFilter?RevisionAuthorFilter
styleCascade?() => StyleCascadeTable | undefined
viewHeadlessDocumentView

CreateDocumentNotesInputOptionsinterfaceSource ↗

Inputs for projecting notes through the same semantic layout pass.

interface CreateDocumentNotesInputOptions
MemberTypeSummary
cacheParameters<typeof layoutHeaderFooterStory>[4]
compatibilityMode?number
defaultTabStopPt?number
displayMode?RevisionDisplayMode
drawingLayoutEpochForPart?(partName: string) => string
drawingTokenForParagraphForPart?(partName: string, paragraph: OoxmlNode) => string
inlineDrawingLayoutForPart?(partName: string) => InlineDrawingLayoutContext | undefined
linkProjectorsDocumentLinkProjectorsLink/property projection and its inseparable cache identities.
measurerTextMeasurer
numberingIndex?() => NumberingIndex
producerstring
revisionAuthorFilter?RevisionAuthorFilter
styleCascade?() => StyleCascadeTable | undefined
viewHeadlessDocumentView

DeclaredFontSubstitutioninterfaceSource ↗

A host-declared redirect: requests for from resolve to to.

How a metric-compatible substitute is wired in — a document naming Calibri resolves to Carlito without the document being rewritten.

interface DeclaredFontSubstitution
MemberTypeSummary
fromFontRequest
lineMetrics?{ readonly heightEm: number; readonly baselineEm: number; }
toFontRequest

DocumentFurnitureSourceinterfaceSource ↗

Page furniture supplied to semantic layout.

interface DocumentFurnitureSource
MemberTypeSummary
furniture
sectionFurniture

DocumentLinkProjectorsinterfaceSource ↗

Sanitized projectors paired with the cache identities required to use them safely.

Keep this object intact when passing it to a document composition helper. Projected text and its dependency tokens are one contract: accepting either half independently permits stale paragraph caches after relationship- or property-only revisions.

interface DocumentLinkProjectors extends StoryProjectionDependencies
MemberTypeSummary
projectLinkForPart(partName: string) => HyperlinkProjector

DocumentSectioninterfaceSource ↗

One section of the body story: contiguous top-level blocks plus the properties that end it.

blockStart / blockEndExclusive index into storyBlocks(part).

interface DocumentSection
MemberTypeSummary
blockEndExclusivenumber
blockStartnumber
indexnumber
propertiesSectionProperties

DocumentSectionsEnumerationinterfaceSource ↗

Every section in a document, with a flag saying whether the list was cut short.

truncated is reported rather than silent: section count comes from a file, so a crafted document declaring thousands of paragraph-level w:sectPr marks is bounded, and a reader should be able to tell that happened.

interface DocumentSectionsEnumeration
MemberTypeSummary
sectionsDocumentSection[]
truncatedbooleanTrue when paragraph-level sectPr marks beyond [MAX_DOCUMENT_SECTIONS](MAX_DOCUMENT_SECTIONS) were dropped.

DocumentStyleDependenciesinterfaceSource ↗

Memoized style inputs shared by every story in one document view.

interface DocumentStyleDependencies
MemberTypeSummary
compatibilityMode?() => number | undefined
defaultTabStopPt() => number
numberingIndex() => NumberingIndex
styleCascade() => StyleCascadeTable | undefined

DrawingAccessibilityinterfaceSource ↗

interface DrawingAccessibility
MemberTypeSummary
decorativeboolean
hiddenboolean
labelstring | null

DrawingGeometryinterfaceSource ↗

interface DrawingGeometry
MemberTypeSummary
clipFallbackDrawingClipFallback
clipPolygonreadonly DrawingPoint[] | null
contentBoundsLayoutBox
effectInsetsDrawingInsets
hitBoundsLayoutBox
paintBoundsLayoutBox
transformedCornersreadonly DrawingPoint[]

DrawingImageEffectsinterfaceSource ↗

Picture color adjustments shared by projection, layout, and paint.

interface DrawingImageEffects
MemberTypeSummary
bilevel?number
brightnessnumber
contrastnumber
grayscaleboolean

DrawingInsetsinterfaceSource ↗

interface DrawingInsets
MemberTypeSummary
bottomnumber
leftnumber
rightnumber
topnumber

DrawingOverlayFrameinterfaceSource ↗

Page-content overlay rectangle for a drawing's painted extent.

interface DrawingOverlayFrame
MemberTypeSummary
heightnumber
pageIndexnumber
recordInlineDrawingRecord | AnchoredDrawingRecord
widthnumber
xnumberRelative to [PageRecord.contentBox](PageRecord.contentBox).
ynumber

DrawingPointinterfaceSource ↗

interface DrawingPoint
MemberTypeSummary
xnumber
ynumber

DrawingTransforminterfaceSource ↗

interface DrawingTransform
MemberTypeSummary
extentEmuReadonly<{ cx: number; cy: number; }>Source `a:ext` in EMU; zero falls back to `wp:extent` at geometry time.
flipHorizontalboolean
flipVerticalboolean
offsetEmuReadonly<{ x: number; y: number; }>Source `a:off` in EMU; defaults to origin when absent.
rotationDegreesnumber

EquationFractionGeometryinterfaceSource ↗

interface EquationFractionGeometry extends EquationGeometryBase
MemberTypeSummary
barLayoutBox
denominatorEquationGeometry
kind'fraction'
numeratorEquationGeometry

EquationNaryGeometryinterfaceSource ↗

interface EquationNaryGeometry extends EquationGeometryBase
MemberTypeSummary
bodyEquationGeometry
kind'nary'
lowerLimit?EquationGeometry
operatorEquationTextGeometry
upperLimit?EquationGeometry

EquationRadicalGeometryinterfaceSource ↗

interface EquationRadicalGeometry extends EquationGeometryBase
MemberTypeSummary
barLayoutBox
degree?EquationGeometry
kind'radical'
radicandEquationGeometry
signEquationTextGeometry

EquationRowGeometryinterfaceSource ↗

interface EquationRowGeometry extends EquationGeometryBase
MemberTypeSummary
itemsreadonly EquationGeometry[]
kind'row'

EquationScriptGeometryinterfaceSource ↗

interface EquationScriptGeometry extends EquationGeometryBase
MemberTypeSummary
baseEquationGeometry
kind'script'
subscript?EquationGeometry
superscript?EquationGeometry

EquationSpanRecordinterfaceSource ↗

Equation metadata carried by one atomic semantic span.

interface EquationSpanRecord
MemberTypeSummary
fallbackTextstring
geometryEquationGeometry
sourceNodeIdstring
truncatedboolean

EquationTextGeometryinterfaceSource ↗

interface EquationTextGeometry extends EquationGeometryBase
MemberTypeSummary
fontSizePtnumber
kind'text' | 'fallback'
textstring

FieldAtomMarkerinterfaceSource ↗

What a piece says about the FIELD result it came from, for Word's shading.

Carried from layout rather than decided at paint time because only the walk knows an atom was a field at all — by paint the result is just text. Whether the shading is actually drawn is a view decision made downstream, so this states the fact and nothing about the appearance.

interface FieldAtomMarker
MemberTypeSummary
formControl?{ readonly kind: 'checkbox'; readonly checked: boolean; readonly accessibleName?: string; } | { readonly kind: 'dropdown'; readonly entries: readonly string[]; readonly selectedIndex: number; readonly accessibleName?: string; }A legacy form CONTROL the reader can operate, with the state it paints.
formFieldbooleanA legacy form field: `w:fldChar/w:ffData` (FORMTEXT, FORMCHECKBOX, FORMDROPDOWN).
pageField?{ readonly kind: AllowlistedPageField; readonly picture?: string; }A BODY PAGE / NUMPAGES / SECTIONPAGES atom whose value depends on pagination.
pageRef?PageRefFieldProjectionA BODY `PAGEREF` atom whose value is the page number its bookmark target lands on.

FieldLinkRegistryinterfaceSource ↗

Per-layout registry for projected HYPERLINK fields.

interface FieldLinkRegistry
MemberTypeSummary
clear
linkById
project

FontFingerprintInputsinterfaceSource ↗

A font reduced to the values that identify it for fingerprinting.

Includes the content hash and faceIndex, so two faces with the same family name but different bytes fingerprint differently — which is what stops a cached measurement being reused against a substituted face.

interface FontFingerprintInputs
MemberTypeSummary
byteLengthnumber
faceIndexnumber
familystring
hashstring
idstring
identitystring
requestFontRequest
substitutionFontSubstitution | null

FontRequestinterfaceSource ↗

A face, as something asks for it: family plus the two axes this engine admits.

Only static weights and slants. Variable-font axes are deliberately outside this vocabulary — the shaper refuses variation axes, and a variable file admitted here would render bold at regular weight.

interface FontRequest
MemberTypeSummary
familystring
style'normal' | 'italic'
weightnumber

FontResourceDefinitioninterfaceSource ↗

One face offered to a snapshot, before admission.

hash is checked against the bytes, so a source cannot claim a face it did not supply. Setting availability to forbidden declares a face that exists but must not be used, which resolves as a typed refusal rather than as "missing".

interface FontResourceDefinition
MemberTypeSummary
availability?'available' | 'forbidden'
bytesUint8Array
faceIndexnumber
hashstring
idstring
requestFontRequest

FontResourceInstrumentationinterfaceSource ↗

Optional counters for the operations font admission is expected to do RARELY.

Exists so tests can assert the absence of work: hashing and byte-copying a 64 MB face on every resolve would not be visible in output, only in a stalled document, so the checks assert these fire once rather than per call.

interface FontResourceInstrumentation
MemberTypeSummary
onAdmission?() => void
onHash?() => void
onOwnedByteCopy?() => void
onTableScan?() => void

FontResourceSnapshotinterfaceSource ↗

An immutable set of admitted faces, and the only way to reach one.

epoch identifies the snapshot: fonts change by REPLACING it, never by mutation, so a layout pass holds one snapshot for its whole run and cannot observe a face appearing or vanishing midway.

interface FontResourceSnapshot
MemberTypeSummary
epochnumber
resolveThe admitted face, or a typed refusal. Never throws.

FontResourceSnapshotOptionsinterfaceSource ↗

How a snapshot is built: which faces, under what limits, validated how.

maxFontBytes is clamped to [HARD_MAX_FONT_BYTES](HARD_MAX_FONT_BYTES) — a caller may tighten the budget but never widen it past the engine's own ceiling.

interface FontResourceSnapshotOptions
MemberTypeSummary
epochnumber
instrumentation?FontResourceInstrumentation
maxFontBytesnumber
resourcesreadonly FontResourceDefinition[]
substitutions?readonly DeclaredFontSubstitution[]
validateFontFontByteValidator

FontSubstitutioninterfaceSource ↗

A request that was answered by a DIFFERENT face than the one asked for.

Recorded rather than silently applied, because a substitution changes measurement: it is part of the shaping fingerprint, so a cached run shaped against a substitute is never reused for the real face.

interface FontSubstitution
MemberTypeSummary
lineMetrics?{ readonly heightEm: number; readonly baselineEm: number; }
requestedFontRequest
resolvedFontRequest

GlyphOutlineinterfaceSource ↗

A glyph's outline as SVG path data, in font design units.

interface GlyphOutline
MemberTypeSummary
pathstring
unitsPerEmnumberDesign units per em — divide by this to scale the path to a point size.

GraphemeBoundaryinterfaceSource ↗

The replaceable segmentation strategy.

An explicit seam rather than a direct Intl.Segmenter call, so tests can install a deterministic boundary and a runtime without Intl.Segmenter can be given one.

interface GraphemeBoundary
MemberTypeSummary
segment

GraphemeSegmentinterfaceSource ↗

One user-perceived character, and the UTF-16 range that encodes it.

The unit a caret moves by. An emoji with a skin-tone modifier is ONE segment spanning several UTF-16 code units, so stepping by code unit would put the caret inside it.

interface GraphemeSegment
MemberTypeSummary
indexnumber
textstring
utf16Fromnumber
utf16Tonumber

GraphemeWordSegmentRecordinterfaceSource ↗

A word span expressed in GRAPHEME offsets rather than UTF-16 ones.

What selection actually uses: a range whose ends are UTF-16 offsets could land inside a grapheme, and selecting half an emoji is not a word.

interface GraphemeWordSegmentRecord
MemberTypeSummary
graphemeFromnumber
graphemeTonumber
wordLikeboolean

HarfBuzzFaceCacheEventinterfaceSource ↗

One face-cache transition, for instrumentation.

interface HarfBuzzFaceCacheEvent
MemberTypeSummary
identitystring
kind'created' | 'hit' | 'evicted'

HarfBuzzOutlineCacheEventinterfaceSource ↗

One outline-cache transition, for instrumentation.

interface HarfBuzzOutlineCacheEvent
MemberTypeSummary
kind'created' | 'hit' | 'evicted' | 'skipped' | 'cleared'
retainedBytesnumber

HarfBuzzShapeCacheEventinterfaceSource ↗

One shape-cache transition, for instrumentation.

interface HarfBuzzShapeCacheEvent
MemberTypeSummary
kind'hit' | 'miss' | 'stored' | 'evicted' | 'skipped' | 'cleared'
retainedBytesnumber

HarfBuzzTextShaperinterfaceSource ↗

A [TextShaper](TextShaper) backed by HarfBuzz, holding WASM resources.

[HarfBuzzTextShaper.dispose](HarfBuzzTextShaper.dispose) is not optional housekeeping: the cached faces are WASM allocations that garbage collection cannot reclaim, so a shaper outliving its editor leaks until the page goes away.

interface HarfBuzzTextShaper extends TextShaper
MemberTypeSummary
dispose

HarfBuzzTextShaperInstrumentationinterfaceSource ↗

Optional counters for the work a shaper is expected to do rarely.

Exists so tests can assert the ABSENCE of work — re-opening a face or re-copying its bytes per shape call would not change any output, only make typing slow, which no rendering assertion would catch.

interface HarfBuzzTextShaperInstrumentation
MemberTypeSummary
onByteCopy?() => void
onFaceCacheEvent?(event: HarfBuzzFaceCacheEvent) => void
onOutlineCacheEvent?(event: HarfBuzzOutlineCacheEvent) => void
onOutlinePathCall?() => void
onShapeCacheEvent?(event: HarfBuzzShapeCacheEvent) => void
onShapeCall?() => void
onTableScan?() => void

HarfBuzzTextShaperOptionsinterfaceSource ↗

Resource budgets and cache sizes for one shaper. Every field optional.

The caches exist because shaping is the expensive step: a face is opened once and reused, and identical runs return their previous result. The caps exist because file-derived input decides how much work is asked for.

interface HarfBuzzTextShaperOptions
MemberTypeSummary
instrumentation?HarfBuzzTextShaperInstrumentation
maxCachedFaces?number
maxCachedOutlineBytes?number
maxCachedShapeBytes?number
maxCachedShapes?number
maxCodepoints?number
maxFontBytes?number
maxGlyphs?number
maxInputUtf16?number
maxOutlineBytes?number
maxShapedRunBytes?number

HeaderFooterStoryRecordinterfaceSource ↗

One header or footer story as it sits on one page.

box is absolute (sheet coordinates) and sized to the story's FLOW height — never to any anchored-object extent, which is the rule that keeps a decorated header's hit area from covering the body. fragments are story-relative (origin at the box's top-left). Baseline furniture may be shared across pages of the same variant when the story has no allowlisted PAGE/NUMPAGES/SECTIONPAGES fields; after page-field finalize, projections are per page (or per distinct field values for count-only stories).

interface HeaderFooterStoryRecord
MemberTypeSummary
anchoredDrawings?readonly AnchoredDrawingRecord[]Anchored drawings owned by this story, in story-relative coordinates.
boxLayoutBox
fragmentsreadonly BlockFragmentRecord[]
kind'header' | 'footer'
pageFieldProjector?(context: { readonly pageNumber: number; readonly pageCount: number; readonly sectionPageCount?: number; readonly format?: string; }) => HeaderFooterStoryRecordTransient projector used between furniture attach and document-level page-field finalize. Absent on published layout records after finalize — but not dead: finalize retains it (with the context it last ran under) in a side table keyed on the published record (`strippedStoryProjections` in `field-page-furniture.ts`), so a reused sheet can re-project when the page count moves (#441). The retained closure keeps its minting pass's scope alive for as long as the sheet is reused, and anything that clones a published field-bearing story must carry the entry onto the clone (`carryStrippedPageFieldProjection`).
part?OoxmlPartThe part this story was laid out from. See [HeaderFooterStoryLayout.part](HeaderFooterStoryLayout.part).
partNamestring
rId?stringMain-document relationship id that resolves to this part (`EditorScope.rId`).
variant'default' | 'first' | 'even'

HitPointinterfaceSource ↗

A point in the coordinate space named by the function taking it.

interface HitPoint
MemberTypeSummary
xnumber
ynumber

HitTestOptionsinterfaceSource ↗

How precisely a hit resolves within a run.

Without a measurer the offset is INTERPOLATED across the span's advance, which is exact only for monospaced text — supply one for proportional fonts, or a click lands a character or two away from the glyph under the pointer.

interface HitTestOptions
MemberTypeSummary
measurer?TextMeasurerExact resolution of the character within a run.
verticalWeight?numberVertical weight for the nearest-block rule.

HyperlinkFieldSpecinterfaceSource ↗

One parsed HYPERLINK instruction: the raw, unsanitized pieces.

target and anchor are verbatim from the instruction — the projector at the trust boundary decides what, if anything, they become in a DOM sink.

interface HyperlinkFieldSpec
MemberTypeSummary
anchorstring | null`\l` — a bookmark name in this document, or null.
targetstring | nullThe target as authored (first quoted or bare non-switch token), or null.
tooltipstring | null`\o` — the hover tooltip, or null.

InlineDrawingRecordinterfaceSource ↗

interface InlineDrawingRecord
MemberTypeSummary
accessibilityDrawingAccessibility
advanceEndnumberCaret/hit advance end (slot + totalWidth).
advanceStartnumberCaret/hit advance start (slot left, before distL).
baselineOffsetnumber
cropSourceCrop
distBnumber
distLnumber
distRnumber
distTnumber
drawingNodeIdstring
effectsDrawingImageEffects
geometryDrawingGeometry
heightnumber
hitBoundsLayoutBox
hyperlinkHrefstring | nullSanitized external hyperlink projection; inert until an explicit gesture activates it.
kind'inlineDrawing'
ownerPartNamestring
paintBoundsLayoutBox
paragraphIdstring
placeholderGraphicKindstring | nullFixed non-picture graphic kind for refusal labels (`chart`, `group`, …); null for pictures.
resourceImageResourceState
revisions?readonly RevisionAttribution[]The revision wrappers enclosing the owning run, outermost first — the same stack spans carry, so paint and review chrome give a tracked picture the same cues as tracked text. Absent when the drawing is untracked.
startnumber
transformDrawingTransform
vectorShapeVectorShapeProjection | nullTyped solid-geometry payload for a renderable `wps:wsp` shape; null otherwise.
widthnumber
xnumberLeft edge of the extent box (slot + distL).
ynumber

KeyedRangeinterfaceSource ↗

A model range to highlight, and the key the caller knows it by.

interface KeyedRange
MemberTypeSummary
fromSemanticPosition
keystring
toSemanticPosition

LayoutBoxinterfaceSource ↗

A rectangle in layout POINTS.

Points everywhere in this layer — twips convert at property-read boundaries and CSS pixels at paint. A box carrying either of those would eventually be added to one carrying the other.

interface LayoutBox
MemberTypeSummary
heightnumber
widthnumber
xnumber
ynumber

LayoutCacheStatsinterfaceSource ↗

Cache counters, for asserting that incremental layout is actually reusing work.

interface LayoutCacheStats
MemberTypeSummary
evictionsnumber
hitsnumber
missesnumber
sizenumber

LayoutEnvironmentShapedMeasurerOptionsinterfaceSource ↗

Environment-bound production options that cannot drift from layout cache identity.

interface LayoutEnvironmentShapedMeasurerOptions
MemberTypeSummary
environmentLayoutShapingOptions['environment']Fingerprinted shaping environment; all geometry-affecting controls come from here.
fallbackTextMeasurerBounded measurement fallback when no admitted face resolves.
resolveFont(style: ResolvedRunStyle) => ResolvedFont | nullResolve a run to an admitted face, or null to use the bounded fallback.
shaperTextShaperShaper from the same admitted layout operation.

LayoutFontConfigurationinterfaceSource ↗

Structural font configuration shared by browser and server hosts.

interface LayoutFontConfiguration
MemberTypeSummary
defaultFont{ readonly family: string; readonly sizeHalfPoints: number; }
epochnumber
language?string
maxFontBytesnumber
sourcesreadonly LayoutFontSource[]
substitutions?readonly LayoutFontSubstitution[]

LayoutFontSourceinterfaceSource ↗

Byte-backed face accepted by neutral shaping.

interface LayoutFontSource
MemberTypeSummary
availability?'available' | 'forbidden'
bytesUint8Array
faceIndexnumber
hashstring
idstring
requestFontRequest

LayoutFontSubstitutioninterfaceSource ↗

Explicit face substitution accepted by neutral shaping.

interface LayoutFontSubstitution
MemberTypeSummary
fromFontRequest
lineMetrics?{ readonly heightEm: number; readonly baselineEm: number; }
toFontRequest

LayoutSchedulerinterfaceSource ↗

Coalesces commits into layout passes.

A keystroke is one commit but must not be one full layout pass, so changes accumulate into a scope and are laid out together. Every published layout is tagged with the revision it actually read, which is what makes a stale result detectable rather than merely late.

interface LayoutScheduler
MemberTypeSummary
cancelDrop pending work without publishing — for teardown.
cancelledRunsnumberHow many cooperative runs were abandoned because a newer revision arrived.
flushRun any pending work now, synchronously. Returns whether a layout was published.
invalidateAllRequest a relayout for a reason the store did not report (page size, zoom, fonts).
notifyRecord a commit. Coalesces with anything already pending.
pendingThe scope that would be used if `flush` ran now, or null when nothing is pending.
staleDiscardsnumberHow many layouts were discarded for being stale. Diagnostics, and a test hook.

LayoutSchedulerOptionsinterfaceSource ↗

How the scheduler produces layouts and when it publishes them.

interface LayoutSchedulerOptions
MemberTypeSummary
currentRevision() => numberThe model's revision right now. Read at publish time, never cached.
publish(layout: SemanticLayout, scope: LayoutScope) => voidCalled with a layout that is known current. Never called with a stale one.
run(scope: LayoutScope) => SemanticLayoutProduce a complete layout for the CURRENT model state.
runCooperatively?(scope: LayoutScope) => CooperativeRunRun a layout in slices instead of in one call (task 9.5).
schedule?(run: () => void) => () => voidDefer work to a later turn, returning a canceller.

LayoutScopeinterfaceSource ↗

What a batch of commits can affect.

paragraphIds is the set the commits touched directly. What that set MEANS depends on impact: for a local impact it bounds the work, for a structural one it only says where the reflow starts.

interface LayoutScope
MemberTypeSummary
createdReadonlySet<string>Ids the commits created — no previous layout exists for these.
deletedReadonlySet<string>Ids the commits removed — any retained layout for these must be released.
dependencyKeysReadonlySet<string>Cache keys the commits invalidated (styles, numbering, fonts).
impactImpactClass
paragraphIdsReadonlySet<string>Node ids touched directly by the coalesced commits.
revisionnumberThe revision this scope describes — the layout result must carry the same one.
structuralbooleanTrue when the block SEQUENCE changed, so ids alone cannot bound the reflow.

LayoutSessioninterfaceSource ↗

Carried-over state that makes layout incremental.

A caller creates one and hands the SAME object back each pass. It holds the previous pages, the per-block cache keys and the flow checkpoints a pass resumes from, so an edit low in a document re-lays only what follows it. A no-change pass returns the previous pages by identity.

interface LayoutSession
MemberTypeSummary
balanceLimitnumber | nullColumn-height limit chosen by the last balanced multi-column pass, or null when the last pass did not balance.
checkpointsFlowCheckpoint[]
contextstringGeometry and flow context of the previous pass; a change forces a full pass.
endCursorYnumberFlow state after the last block of the previous pass, for a section that CONTINUES onto this one's last sheet (`w:type="continuous"`).
endLineCounternumberLine counter after the last block of the previous pass.
endsOpenPagebooleanWhether the last page of that pass was still open (no trailing page break).
endSpaceAfternumber
keysstring[]
multiMultiSectionLayoutState | nullPresent when the last pass was multi-section; child sessions live here.
notePageBottomReservesReadonlyMap<number, number> | nullPage-bottom footnote reserves from the last published notes layout.
notesunknownThe notes pass's memoized state (reference hits, mark contexts, per-page attach results), reused while its inputs are unchanged. Opaque here: the shape is owned by `note-pagination.ts`, which is the only reader and writer.
parityDependentbooleanWhether the previous pass read page PARITY: even/odd header variants, or an anchored drawing positioned against an inside/outside frame or alignment.
prepassunknownThe section's memoized prepass (prepared blocks, cache keys, flow keys, document order), reused verbatim while its inputs are unchanged. Opaque here: the shape is owned by `semantic-layout.ts`, which is the only reader and writer.
producer?stringProducer of the previous pass, compared beside [context](context) rather than embedded in it: the producer carries the content-control token, which runs to kilobytes on a control-heavy document, and embedding it copied that token into every section's context string on every pass. Identity-stable when unchanged, so the comparison is a pointer check.
startLineCounternumberLine counter at the start of the previous pass, for translating reused section counts.
startPageParitynumberParity (0/1) of the document page index this session's layout started on.
statsLayoutSessionStats

LayoutSessionStatsinterfaceSource ↗

What the last layout pass actually did — the observable evidence that incremental layout is working.

reusedPages and fullPasses are the ones that matter: a typing keystroke that rebuilds every page produces identical output and unusable performance, so the tests assert on these rather than on the rendered result.

interface LayoutSessionStats
MemberTypeSummary
fullPassesnumberPasses that could not resume and laid the document out from the top.
placednumberParagraphs placed by the last pass, against the number in the document.
reusedPagesnumberPages carried over from the previous layout without being rebuilt.
totalnumber

LayoutShapingInstrumentationinterfaceSource ↗

Optional measurements for resource-budget tests and host diagnostics.

interface LayoutShapingInstrumentation
MemberTypeSummary
onFontAdmission?() => void
onFontByteCopy?() => void
onFontHash?() => void

LayoutShapingOptionsinterfaceSource ↗

A fully resolved shaping bundle: fonts, shaper, and the environment they were admitted under. Produced by the editor lane's font configuration (createLayoutShaping) and consumed to build shaped measurers. Lived in the legacy metrics.ts until the legacy layout lane was deleted; the type is the surviving contract between the two lanes.

interface LayoutShapingOptions
MemberTypeSummary
defaultFont{ readonly family: string; readonly sizeHalfPoints: number; }
environmentLayoutShapingEnvironment
fontsFontResourceSnapshot
ligatureCaretPolicy'cluster-edges-only'
operationOperationSnapshot
shaperTextShaper

LevelOverrideinterfaceSource ↗

One w:lvlOverride on a w:num: a restart value, a replacement level, or both.

How two lists share an abstract definition while numbering independently.

interface LevelOverride
MemberTypeSummary
level?NumberingLevelFull level replacement when `w:lvl` is present under the override.
startOverride?number

LineRecordinterfaceSource ↗

One laid-out line: its geometry, its baseline, and the styled spans it renders.

The unit hit-testing and caret placement resolve against. Geometry comes from HERE, never from the DOM, which is what lets an empty paragraph still get a caret.

interface LineRecord
MemberTypeSummary
anchorRevisions?readonly RevisionAttribution[]Revision attributions of tracked ANCHORED drawings whose anchor sits on this line, absent when there are none.
baselinenumberDistance from the line box top to the text baseline.
boxLayoutBox
changeSites?readonly RevisionAttribution[]Revisions a resolved view answered on this line — content it kept as ordinary text and content it removed between the line's offsets — absent when there are none, and always absent in All Markup, where the spans carry the markup themselves.
contentXnumberWhere the line's content actually starts, after alignment and the first-line indent.
deletedRanges?readonly ModelRange[]Model ranges on this line covering DELETED content, absent when there is none.
drawings?readonly InlineDrawingRecord[]Inline drawings on this line, absent when there are none.
idstring
leadingnumberSpace ABOVE the glyph band inside [box](box) (exact centering, not auto/atLeast).
manualBreakAfter?trueAn authored manual line break ends this line; optional display furniture can show ↵.
rangeSourceRange
spansreadonly StyleSpanRecord[]
trailingSpacing?numberAuto/atLeast line-spacing depth BELOW the glyph band, inside [box](box).

LineSegmentinterfaceSource ↗

The part of a line that belongs to ONE paragraph.

A line normally belongs to one paragraph outright, and then this is the whole of it — the same object every caller read before, so nothing about an ordinary document takes a new path. A resolved display mode merges paragraphs that a tracked decision merges, and the line carrying the join holds spans from two of them. Offsets there are ambiguous by themselves: both paragraphs start at zero, so an offset means nothing without the paragraph it counts in.

interface LineSegment
MemberTypeSummary
drawingsreadonly InlineDrawingRecord[]
endnumber
paragraphIdstring
spansreadonly StyleSpanRecord[]
startnumber

ListCounterAdvanceinterfaceSource ↗

The result of counting ONE list paragraph: the level that applied, the counter vector after it, and the marker text a reader sees.

Counters are a vector across all nine levels, not a single number, because a deeper level restarting resets the ones below it while leaving those above intact.

interface ListCounterAdvance
MemberTypeSummary
abstractNumIdstringEffective abstract numbering template for this num instance.
countersreadonly number[]Counter vector after this item was counted (indices 0..8).
ilvlnumber
levelNumberingLevel
markerTextstringExpanded marker text (empty when vanished / empty lvlText).
numIdstring

ListCounterStateinterfaceSource ↗

The running counters for one layout pass over one story.

Stateful and order-dependent by nature: a list number is a function of every numbered paragraph before it, which is why markers are computed during layout and cannot be read off a paragraph in isolation.

interface ListCounterState
MemberTypeSummary
advanceAdvance counters for one list paragraph.

ListMarkerRecordinterfaceSource ↗

A numbering marker as layout published it.

Geometry is in the same coordinate space as the fragment (page-content or cell-content relative). Paint positions from this box and MUST NOT remeasure the marker.

interface ListMarkerRecord
MemberTypeSummary
boxLayoutBox
levelnumberThe `w:ilvl` this marker was resolved at, 0..8.
numFmtstring`w:numFmt` of the resolved level — `bullet` or a numbering format.
numIdstringThe `w:numId` this marker resolved through.
ordinal?numberResolved counter at this marker's own level; absent for bullets.
styleResolvedRunStyle
textstring

MaterializationInputinterfaceSource ↗

Which pages to build in detail.

A page left out keeps its size and position but no content, so the document's height and page count are unchanged and scrolling to it reveals it rather than reflowing everything below.

interface MaterializationInput
MemberTypeSummary
layoutSemanticLayout
overscanPages?numberExtra pages kept ready either side of the visible band.
pinnedPages?Iterable<number>Pages that must be built wherever they are — caret, selection, a search hit.
viewport?ViewportWindowOmitted means "no viewport": everything is materialized, which is the honest default.

MoveCaretOptionsinterfaceSource ↗

Story-scoped stops are required when navigating inside an open header or footer.

interface MoveCaretOptions
MemberTypeSummary
measurer?TextMeasurer
stops?readonly CaretGeometry[]Precomputed active-story stops; body navigation keeps the indexed default.

NoteAreaRecordinterfaceSource ↗

Footnote / endnote area on one page: separator + stacked note stories.

placement records how the area was positioned. fallbackReason is set when the bounded reflow loop exhausted and layout kept the reference with its note on a later page (D12 named fallback).

interface NoteAreaRecord
MemberTypeSummary
boxLayoutBox
fallbackReason?string
kind'footnotes' | 'endnotes'
notesreadonly NoteStoryRecord[]
placement'pageBottom' | 'beneathText' | 'sectEnd' | 'docEnd'
separator?{ readonly kind: 'separator' | 'continuationSeparator'; readonly box: LayoutBox; readonly fragments: readonly BlockFragmentRecord[]; readonly synthetic: boolean; readonly ruleStyle?: 'single' | 'double'; }Separator rule / authored separator story; absent when no notes on this page.

NoteDisplayMarkinterfaceSource ↗

The mark a note reference paints.

null where w:customMarkFollows suppresses it: the document supplies its own glyph, and painting an automatic number too would show the note twice.

interface NoteDisplayMark
MemberTypeSummary
displayNumber?number1-based automatic sequence number when assigned; absent when suppressed.
markstring | nullFormatted mark, or `null` when suppressed by customMarkFollows.
noteIdnumber

NoteMarkContextinterfaceSource ↗

Lookup of derived display marks keyed by [formatNoteScopeId](formatNoteScopeId).

null mark = customMarkFollows (no automatic digits). Absent key = dangling / unknown — fail-open with an empty display (model atom preserved).

interface NoteMarkContext
MemberTypeSummary
activeNoteKey?stringScope id of the note story currently being laid out (`footnote:N` / `endnote:N`).
marksReadonlyMap<string, string | null>scopeId → formatted mark (or null when suppressed).
reservedMarkText?stringWhen set, every automatic mark measures at least this string's width (eachPage reservation). The string is the widest-measuring candidate under the effective mark style (actual marks plus a bounded per-section value window) — not merely the longest by codepoint count. Display text may still be the real mark; measurement uses the wider of the two so digit-width / proportional-glyph feedback cannot oscillate.

NoteReferenceSiteinterfaceSource ↗

Where one note is referenced from — what per-page and per-section restart rules are computed against.

interface NoteReferenceSite
MemberTypeSummary
customMarkFollows?booleanWhen true, consumes no automatic number (`customMarkFollows`).
noteIdnumberStable note id (`w:id`).
pageIndex?numberPage index of the reference when known (0-based). Required for `eachPage` restart; when omitted, `eachPage` behaves like `continuous` for that site.
sectionIndexnumberSection index of the reference (0-based).

NotesAttachResultinterfaceSource ↗

The layout with notes attached, plus any fallbacks taken and the mark context used.

The marks come back because they feed the body's incremental cache tokens: a note number that changed must invalidate the paragraph that references it.

interface NotesAttachResult
MemberTypeSummary
fallbackReasonsreadonly NotePaginationFallbackReason[]
layoutSemanticLayout
noteMarksNoteMarkContextMark context used for the final body projection (for incremental cache tokens).

NoteSeparatorLayoutinterfaceSource ↗

The rule between body text and the note area.

Synthesized when the document declares none, because Word draws one regardless — a document without an authored separator still shows the line a reader expects.

interface NoteSeparatorLayout
MemberTypeSummary
fallbackReason?NoteLayoutFallbackReasonSet when an oversize authored separator was replaced with a synthetic rule.
flowHeightnumber
fragmentsreadonly BlockFragmentRecord[]
kind'separator' | 'continuationSeparator'
ruleStyle?NoteSeparatorRuleStyleLayout-owned rule when the separator is marker-only (`w:separator` / `w:continuationSeparator`) or fully synthetic. Absent when an authored separator story has real paragraph/run/border content that paint should render as fragments.
syntheticbooleanTrue when the engine synthesized a default rule (document had none).

NotesLayoutInputinterfaceSource ↗

Everything note pagination needs: the note parts, and the per-section properties governing them.

Per-SECTION because numbering, restart rules and placement are all section properties — one document can restart footnote numbering at every section and end notes at the document end.

interface NotesLayoutInput
MemberTypeSummary
cache?ParagraphLayoutCache<readonly PendingLine[]>
compatibilityMode?number
defaultTabStopPt?number
displayMode?RevisionDisplayMode
documentEndnotePropsResolvedEndnoteProperties
documentFootnotePropsResolvedFootnotePropertiesDocument-level defaults (section 0 fallback).
documentProperties?DocumentPropertiesDocument properties for a document-property field inside a note story.
drawingLayoutEpoch?stringPart-level drawing epoch covering the notes parts, standing in for [drawingsForPart](drawingsForPart)'s closure in the notes-pass memo (the closure is rebuilt per pass, so only an epoch can say "the drawing state did not move"). A caller that supplies `drawingsForPart` without this keeps the rebuild path.
drawingsForPart?(ownerPartName: string) => NoteStoryDrawings | undefinedInline drawing support per notes part. Absent means note paragraphs flow without drawing records, which is what a headless caller with no image port wants.
endnotePropsBySectionreadonly ResolvedEndnoteProperties[]Per-section resolved endnote properties.
endnotesPartOoxmlPart | null
footnotePropsBySectionreadonly ResolvedFootnoteProperties[]Per-section resolved footnote properties (index-aligned with document sections).
footnotesPartOoxmlPart | null
linkRelsEpoch?stringContent token over the notes parts' relationship records, standing in for [projectLinkForPart](projectLinkForPart)'s closure in the notes-pass memo. The projector reads relationship state the pinned part identity cannot see move: a replicated rels-only change lands without splicing the notes part, so only a content token catches it. Required whenever `projectLinkForPart` is supplied — without it the memo is disabled, the same fail-closed rule `drawingsForPart` follows through `drawingLayoutEpoch`.
measurerTextMeasurer
numberingIndex?NumberingIndex`numbering.xml`, so a `w:numPr` paragraph inside a note resolves a marker.
producerstring
projectionEpoch?stringCombined notes-part freshness signal; outer memo only, never a paragraph producer.
projectionTokenForParagraphForPart?(ownerPartName: string, paragraph: OoxmlNode) => stringPer-notes-part paragraph identity for projected links and metadata fields.
projectionTokenForTableForPart?(ownerPartName: string, table: OoxmlNode) => stringMemoized table aggregate counterpart to `projectionTokenForParagraphForPart`.
projectLinkForPart?(ownerPartName: string) => HyperlinkProjector | undefinedPer notes-part link projector, preferred over `projectLink`: a `w:hyperlink` inside `/word/footnotes.xml` or `/word/endnotes.xml` declares its `r:id` in that part's own `.rels`, not the body part's. The surface supplies this; the inherited body projector remains only a fallback for callers without per-part resolution.
refFields?RefFieldContextThe document's resolved REF inputs, so a footnote's cross-reference paints the live value the body paints. Normally injected by `semantic-layout` from the context it built over the body and note stories; its values token joins the notes-pass fingerprint so a renumbering edit repaints the notes that cite the renumbered target.
revisionAuthorFilter?RevisionAuthorFilter
styleCascade?StyleCascadeTable

NoteStoryDrawingsinterfaceSource ↗

Inline drawing support for ONE notes part.

A note lives in /word/footnotes.xml or /word/endnotes.xml, not in the body part, so its pictures resolve against that part's relationships — the same per-part shape header/footer furniture uses. Without it a note paragraph flows with no drawing context at all and a picture inside it contributes no record: no image, and no placeholder either.

interface NoteStoryDrawings
MemberTypeSummary
drawingTokenForParagraph?(paragraph: OoxmlNode) => stringPer-paragraph projection + RESOURCE token for the break cache key.
inlineDrawingLayoutInlineDrawingLayoutContext

NoteStoryLayoutinterfaceSource ↗

One note's body laid out as its own story, in story-relative coordinates.

Relative rather than page-absolute because a note moves between pages during pagination — the page it lands on is decided after its content is measured.

interface NoteStoryLayout
MemberTypeSummary
fallbackReason?NoteLayoutFallbackReasonTrue when layout hit a named bound and returned a truncated / empty story.
flowHeightnumberHeight the blocks flow to (points).
fragmentsreadonly BlockFragmentRecord[]Story-relative fragments; origin at the story box's top-left.
noteIdnumber
noteKindNoteKind
noteTypeReturnType<typeof noteTypeOf>
scopeIdstring`footnote:N` / `endnote:N` — matches EditorScope note id encoding.

NoteStoryRecordinterfaceSource ↗

One footnote or endnote story as it sits on one page (or continuation page).

Notes are ordinary editable stories — NOT [data-docx-hf] furniture. box is absolute (sheet coordinates). fragments are story-relative. Separators are nonselectable paint geometry owned by the parent [NoteAreaRecord](NoteAreaRecord).

interface NoteStoryRecord
MemberTypeSummary
boxLayoutBox
continuation?booleanTrue when this is a continuation fragment (no leading mark).
fragmentsreadonly BlockFragmentRecord[]
markstring | nullDerived display mark for this occurrence; null when customMarkFollows / continuation.
noteIdnumber
noteKind'footnote' | 'endnote'
scopeIdstring`footnote:N` / `endnote:N` — EditorScope note id.

NumberingIndexinterfaceSource ↗

The bounded projection of numbering.xml that list layout resolves against.

Projection ONLY — never a mutation or serialization authority. Hostile values are dropped or clamped, and a missing definition resolves to "no list" rather than a guess.

interface NumberingIndex
MemberTypeSummary
abstractNumsReadonlyMap<string, AbstractNumDefinition>
numsReadonlyMap<string, NumDefinition>

NumberingLevelinterfaceSource ↗

One w:lvl: how this depth numbers, what its marker looks like, and how it indents.

interface NumberingLevel
MemberTypeSummary
ilvlnumber
indentNumberingLevelIndent
isLglboolean`w:isLgl` (§17.9.9): render EVERY level referenced by this level's `w:lvlText` in decimal, whatever number format those levels declare for themselves.
lvlJcListMarkerAlign
lvlRestart?number`w:lvlRestart` one-based trigger level, or `0` when the level never restarts. Omitted in XML → restart when the previous level (or any earlier level) is used.
lvlTextstring
numFmtstring
runPropertiesreadonly OoxmlProperty[]Level `w:rPr` as flat properties (for marker face / vanish).
startnumber
suffListSuffix
vanishbooleanTrue when level run props request vanish — marker must not paint.

NumberingLevelIndentinterfaceSource ↗

One level's indent, plus which parts the level actually AUTHORED.

The provenance matters: w:ind cascades per-attribute, so a level that authored only left must not overwrite an inherited hanging with a synthesized zero.

interface NumberingLevelIndent
MemberTypeSummary
authored?{ readonly left?: number; readonly right?: number; readonly start?: number; readonly end?: number; }Authored physical/logical sides, in points, before paragraph direction resolves them.
firstLinenumber
hangingnumber
leftnumber
rightnumber
stated?{ readonly left: boolean; readonly right: boolean; readonly firstLineOffset: boolean; }Which of these the LEVEL actually authored.

NumDefinitioninterfaceSource ↗

One w:num — the thing a paragraph's w:numId actually names.

Points at an [AbstractNumDefinition](AbstractNumDefinition) and may override any of its levels.

interface NumDefinition
MemberTypeSummary
abstractNumIdstring
numIdstring
overridesReadonlyMap<number, LevelOverride>

OperationSnapshotinterfaceSource ↗

Immutable per-operation environment. Configuration, extension, shaping, and producer changes are coarse gates; resource changes are compared through CacheProvenance.resourceDependencies.

interface OperationSnapshot
MemberTypeSummary
configEpochnumber
extensionFingerprintstring
producerVersionnumber
resourceEpochnumber
shapingHashstring

PageBorderFrameRecordinterfaceSource ↗

The page frame on one sheet, already filtered by w:display.

Present only on the pages that actually carry it, so a consumer holding a single page record needs no section context to know what to draw. display rides along because a sheet MINTED after layout (note overflow) has to decide whether it inherits its template's frame, and a firstPage frame is the one that must not be inherited.

interface PageBorderFrameRecord
MemberTypeSummary
displayPageBorderDisplay
strokesreadonly PageBorderStrokeRecord[]
zOrderPageBorderZOrder

PageBorderStrokeRecordinterfaceSource ↗

One w:pgBorders rule as layout published it.

box is the stroke rectangle in PAGE-BOX-relative points — measured from the sheet's own top-left, not from the document-stacked absolute origin and not from the content box. That is what lets a reused sheet move down the stack (remapPage) without the frame being recomputed or shifted: the frame's place on the paper never depended on where the paper is.

Paint MUST NOT re-derive the inset. w:offsetFrom decides whether w:space counts from the sheet edge or from the text, and resolving that needs the section margins, which is layout's to know — the same division columnSeparators already draws.

interface PageBorderStrokeRecord
MemberTypeSummary
boxLayoutBox
edgeParagraphBorderEdge
sidePageBorderSide

PageFurnitureinterfaceSource ↗

Pre-laid page furniture, supplied by the host (phase 2).

Baseline stories are laid out once per variant (layoutHeaderFooterStory) for furniture height. Stories that actually contain allowlisted PAGE/NUMPAGES fields attach a projector so document-level finalize can re-layout under the known page count; field-free furniture reuses the baseline on every sheet.

interface PageFurniture
MemberTypeSummary
evenAndOddHeadersboolean
footersReadonlyMap<HeaderFooterVariantName, HeaderFooterStoryLayout>
headersReadonlyMap<HeaderFooterVariantName, HeaderFooterStoryLayout>
titlePageboolean

PageGeometryinterfaceSource ↗

Page geometry, in points.

interface PageGeometry
MemberTypeSummary
footerDistance?number`w:pgMar/@footer` — sheet edge to footer bottom, in points. Defaults to 36.
headerDistance?number`w:pgMar/@header` — sheet edge to header top, in points. Defaults to 36 (720 twips).
heightnumber
margin{ readonly top: number; readonly right: number; readonly bottom: number; readonly left: number; }
widthnumber

PageRecordinterfaceSource ↗

One laid-out page: the sheet, the content area, and everything that landed on it.

Page identity is REUSED across incremental passes — a pass that changes nothing returns the previous records by reference, which is what lets paint skip untouched pages entirely.

interface PageRecord
MemberTypeSummary
anchoredDrawings?readonly AnchoredDrawingRecord[]Page-content anchored drawings on this sheet, absent when there are none.
boxLayoutBoxThe whole sheet.
columnSeparators?readonly LayoutBox[]Layout-owned vertical rules requested by `w:cols/@w:sep`, content-box relative.
contentBoxLayoutBoxThe area inside the margins that content flows into.
contentControls?readonly ContentControlBoundaryRecord[]Content-control boundaries whose geometry intersects this page.
endnotes?NoteAreaRecordEndnotes collected on this page (sectEnd / docEnd).
footnotes?NoteAreaRecordFootnotes reserved on this page (pageBottom / beneathText / continuations).
fragmentsreadonly BlockFragmentRecord[]
hasBodyPageFields?boolean`true` when this page's body flow (or a body table) carries a PAGE/NUMPAGES/SECTIONPAGES placeholder that document finalize must substitute. Set when the page is assembled, so it rides the record through incremental reuse. `false` lets `finalizePageFieldProjection` skip the substitution walk; `undefined` (a page built by a path that does not stamp it) still walks, which is safe.
header?HeaderFooterStoryRecordPage furniture for this page's variant, absent when the document declares none.
idstring
indexnumber
noteStream?PageNoteStreamOwnership of note-only overflow sheets. Absent on ordinary body pages. Layout pagination sets this so endnote hosting does not treat footnote drain pages as free body space.
pageBorders?PageBorderFrameRecordLayout-owned `w:pgBorders` frame for this sheet, page-box relative. Absent when none.
pageFieldSource?{ readonly pageNumber: number; readonly sectionPageCount: number; readonly format?: string; }Section-local PAGE/SECTIONPAGES inputs for finalize. Absent → physical page index and document-wide section count (empty `w:pgNumType` behaviour).

PageRefFieldProjectioninterfaceSource ↗

What a PAGEREF span carries to document finalize: the resolved target, the normalized authored cache (the calibration oracle), and the sticky calibration identity.

interface PageRefFieldProjection
MemberTypeSummary
cachedstringThe authored cached result, whitespace-collapsed — what the computed number must reproduce.
calibrationPageRefCalibrationCell
targetParagraphIdstringCanonical id of the paragraph the bookmark names — first declaration wins.

ParagraphAutoSpacingContextinterfaceSource ↗

Where a paragraph sits, for the contexts in which Word's auto spacing resolves to 0 instead of [AUTO_PARAGRAPH_SPACING_PT](AUTO_PARAGRAPH_SPACING_PT).

This resolves the interior list-item or table-cell value. Body layout restores each outer list margin in resolveListAutoSpacing, where neighboring blocks are available. A caller that says nothing gets the body answer.

interface ParagraphAutoSpacingContext
MemberTypeSummary
inList?booleanThe paragraph participates in numbering (`w:numPr`), i.e. it is a list item.
inTableCell?booleanThe paragraph lives in a table cell.
lineUnitPt?numberSection grid pitch in points; no grid uses Word's fixed 12pt line unit.

ParagraphBorderEdgeinterfaceSource ↗

One resolved w:pBdr edge: its style, colour, thickness and gap.

widthPt and spacePt are already converted and CLAMPED — both come from a file, and an unbounded border width becomes a layout dimension.

interface ParagraphBorderEdge
MemberTypeSummary
colorstring | nullRRGGBB, or null when auto/missing (paint defaults to black).
shadow?true`w:shadow` — Word offsets a drop shadow behind the rule.
spacePtnumberGap from text to the rule, in points (`w:space`).
valstringAuthored `ST_Border` value (`single`, `dashed`, …).
widthPtnumberBorder thickness in points (`w:sz` is eighths of a point).

ParagraphBordersinterfaceSource ↗

A paragraph's resolved w:pBdr (ECMA-376 §17.3.1.24).

top/left/bottom/right are the four physical edges of the box. The other two are group-relative: between draws at a boundary INSIDE a run of consecutive paragraphs whose border settings are identical, and bar is the vertical change-bar rule beside the paragraph, drawn whether or not the paragraph groups with its neighbours.

interface ParagraphBorders
MemberTypeSummary
bar?ParagraphBorderEdge
between?ParagraphBorderEdge
bottom?ParagraphBorderEdge
left?ParagraphBorderEdge
right?ParagraphBorderEdge
top?ParagraphBorderEdge

ParagraphBorderStrokeRecordinterfaceSource ↗

One w:pBdr rule as layout published it.

box is the STROKE rectangle in the same coordinate space as the fragment, so paint sets a position and a colour and nothing else. It matters that paint cannot derive these itself: Word draws the side rules OUTSIDE the text column, so box.x on a left/bar stroke is left of the fragment box and a painter reasoning from the fragment alone would put it inside the text.

interface ParagraphBorderStrokeRecord
MemberTypeSummary
boxLayoutBox
edgeParagraphBorderEdge
sideParagraphBorderSide

ParagraphBottomBorderRecordinterfaceSource ↗

A bottom paragraph border as layout published it.

box is the rule's geometry in the same coordinate space as the fragment (page-content relative). Paint positions from this box and MUST NOT remeasure the border.

interface ParagraphBottomBorderRecord
MemberTypeSummary
boxLayoutBox
edgeParagraphBorderEdge

ParagraphFragmentRecordinterfaceSource ↗

The part of one paragraph that sits on one page.

A paragraph that crosses a page boundary produces several fragments that all name the SAME paragraphId, which is what lets selection and hit-testing treat it as one paragraph while pagination treats it as two boxes.

interface ParagraphFragmentRecord
MemberTypeSummary
alignment'left' | 'center' | 'right' | 'both'Resolved `w:jc` alignment used by layout.
borders?readonly ParagraphBorderStrokeRecord[]Every `w:pBdr` rule this fragment draws, in paint order.
bottomBorder?ParagraphBottomBorderRecordBottom rule on the final fragment when `w:pBdr/w:bottom` resolves; absent otherwise.
boxLayoutBox
clipToBox?trueA fixed text frame clips its painted ink to this fragment's box; source ranges remain intact.
emptyParagraphStyle?ResolvedRunStyleResolved paragraph-mark style when this fragment has no text or inline drawings.
fragmentIndexnumber0 for the first fragment of the paragraph, 1 for its continuation, and so on.
idstring
indentParagraphIndentThe paragraph's EFFECTIVE indent in points, cascade and numbering merge included.
kind'paragraph'
linesreadonly LineRecord[]
markChangeSites?readonly RevisionAttribution[]The decisions a resolved view answered on this paragraph's MARK: an inserted break it kept, a paragraph-property change or a mark-property change it accepted. Final fragment only, resolved views only; absent when there are none. A removed break merges its paragraph away and reports on the join line instead (see [LineRecord.changeSites](LineRecord.changeSites)).
marker?ListMarkerRecordList marker painted in the hanging-indent slot of the FIRST fragment only.
markFormatRevision?RevisionAttributionThe tracked FORMAT change on this paragraph's mark (`w:pPr/w:rPr/w:rPrChange`), absent when there is none. Final fragment only, and `all-markup` only, like the decisions above.
markRevision?RevisionAttributionThe one decision a single-field reader sees, absent when there are none.
markRevisions?readonly RevisionAttribution[]The revisions on this paragraph's own MARK (`w:pPr/w:rPr/w:ins|w:del`), absent when there are none.
outlineLevelnumber | nullResolved Word outline level (0 = Heading 1), or null for body text.
outOfFlow?trueA positioned text frame retains its source identity without consuming body flow height.
paragraphEnd?trueThis fragment contains the visible paragraph end.
paragraphIdstring
positionedFrame?{ readonly anchorId: string; readonly columnIndex: number; readonly groupId: string; readonly sourceOrder: number; readonly wrap: 'around' | 'none' | 'notBeside'; readonly hSpace: number; readonly vSpace: number; readonly box: LayoutBox; }Placement and wrapping of one authored text-frame group, in page-content coordinates.
propsreadonly OoxmlProperty[]
rangeSourceRange
shading?stringValidated 6-hex paragraph shading fill (`w:pPr/w:shd`), absent for none/auto.
shadingBox?LayoutBoxGeometry of the paragraph shading band when [shading](shading) is set. Absent when there is no fill.
spacingParagraphSpacingBefore/after spacing applied to THIS fragment, in points.
styleIdstring | nullResolved paragraph style after the style/default cascade, or null when none applies.
tabStopsResolvedTabStopsThe paragraph's resolved tab stops — cascade included — and the default interval past the last of them.

ParagraphIndentinterfaceSource ↗

A paragraph's resolved indent in points, in the vocabulary w:ind uses.

left/right are signed; hanging is not (ST_TwipsMeasure). firstLine is signed even though the schema declares it unsigned, because Word's model keeps one signed first-line indent and this engine follows it.

interface ParagraphIndent
MemberTypeSummary
firstLinenumber
hangingnumber
leftnumber
rightnumber

ParagraphKeyInputsinterfaceSource ↗

Everything that decides whether a cached paragraph break is still valid.

producer is in the key because a font arriving after first paint changes every advance in the document while no content changes — without it the cache would serve the pre-font layout forever.

interface ParagraphKeyInputs
MemberTypeSummary
drawingToken?stringInline drawing projection/resource epoch for this paragraph.
exclusionToken?stringActive page exclusion zones affecting this paragraph's break.
paragraphOoxmlNode
producerstringWho produced the measurements.
projectionToken?stringParagraph-local semantic projection identity (links and live metadata fields).
propertiesreadonly OoxmlProperty[]
widthnumberAvailable width, which decides where the lines break.

ParagraphLayoutCacheinterfaceSource ↗

The per-paragraph measurement cache.

Caches the BREAK only — where a paragraph's lines fall at a given width — never its placement. An edit high in a document still repaginates everything below it, while paragraphs nobody touched are never measured again.

interface ParagraphLayoutCache<T>
MemberTypeSummary
clear
get
keyForDerive a break key inside this cache's ownership scope.
releaseRelease a break after final placement when this cache was created for a one-shot pass.
retainDrop entries for paragraphs a commit removed, so the cache cannot grow without bound.
retainAcrossPasses?booleanWhether values released after placement remain available to later layout passes.
retentionPassDueWhether THIS published pass should pay for a document-wide [retain](retain) sweep.
set
statsLayoutCacheStats

ParagraphLayoutCacheOptionsinterfaceSource ↗

How large the paragraph cache grows before least-recently-used eviction.

interface ParagraphLayoutCacheOptions
MemberTypeSummary
maxEntries?numberEntries retained before the least recently used are dropped.
retainAcrossPasses?booleanKeep placed breaks for later revisions. Default true; false bounds one-shot exporters.

ParagraphLayoutInputsinterfaceSource ↗

Everything the line breaker needs about one paragraph, already cascaded and converted.

interface ParagraphLayoutInputs
MemberTypeSummary
alignmentAlignment
availablenumber
bordersParagraphBordersEvery `CT_PBdr` edge after cascade, not just the bottom one.
bottomBorderParagraphBorderEdge | undefined
contextualSpacingboolean`w:contextualSpacing`: drop before/after between same-style neighbours.
indent{ left: number; right: number; hanging: number; firstLine: number; }
inheritedRunPropertiesreadonly OoxmlProperty[]
lineSpacingParagraphLineSpacingResolved `w:line` / `w:lineRule`; single spacing where the cascade says nothing.
listItem?ResolvedListItemResolved list marker inputs when the paragraph participates in numbering.
markRunPropertiesreadonly OoxmlProperty[]Paragraph-mark cascade (`inheritedRunProperties` + direct `w:pPr/w:rPr`). Empty-line sizing and last-line mark height — never content-run face.
outlineLevelnumber | nullResolved outline level, with 9/invalid values treated as body text.
propsOoxmlProperty[]
shadingstring | undefinedValidated 6-hex paragraph shading fill from cascaded `w:pPr/w:shd`, absent for none.
spacingParagraphSpacing
styleIdstring | nullResolved paragraph style id, for the `w:contextualSpacing` neighbour comparison.
tabStopsResolvedTabStopsCascaded custom tab stops + default interval for paragraph-flow breaking.
tabStopsCacheTokenstringFingerprint folded into the paragraph layout cache key — nested `w:tabs` are absent from flat property bags, so style-inherited stops must be named explicitly.

ParagraphLineSpacinginterfaceSource ↗

Resolved line spacing: the rule, and the value it applies.

value means different things per rule — 240ths of a line under auto, points under exact and atLeast — which is why the two travel together and neither is useful alone.

interface ParagraphLineSpacing
MemberTypeSummary
ruleLineSpacingRule
valuenumber`auto`: the 240ths-of-a-line multiplier numerator. Otherwise points.

ParagraphSpacinginterfaceSource ↗

A paragraph's resolved space before and after, in points.

Already collapsed against w:contextualSpacing, so adjacent same-style paragraphs that suppress their gap arrive here with it removed rather than leaving that to whoever stacks them.

interface ParagraphSpacing
MemberTypeSummary
afternumber`w:spacing/@after`, in points.
beforenumber`w:spacing/@before`, in points.

PlacedCellinterfaceSource ↗

One painted occurrence of a cell, and where it sits.

interface PlacedCell
MemberTypeSummary
cellTableCellFragmentRecord
isHeaderRepeatboolean
offsetXnumberWhat to add to the cell's box to reach the page's content-box space.
offsetYnumberThe vertical half of the same offset. See [PlacedCell.offsetX](PlacedCell.offsetX).
pageIndexnumber
rowTableRowFragmentRecord
rowIndexnumberOrdinal within the whole table, shared by a header row and every repeat of it.
tableIdstring

PreferredWidthinterfaceSource ↗

w:tblW / w:tcW — a requested width, whose UNIT depends on its type.

Points for dxa, percent for pct, and zero for auto/nil. Reading value without type is always wrong.

interface PreferredWidth
MemberTypeSummary
typePreferredWidthType
valuenumberPOINTS for `dxa`, PERCENT (0–100) for `pct`, 0 for `auto`/`nil`.

PreparedLayoutFontConfigurationinterfaceSource ↗

Opaque owned configuration shared by cache identity and font admission.

interface PreparedLayoutFontConfiguration
MemberTypeSummary
[PREPARED_LAYOUT_FONT_CONFIGURATION_BRAND]true
fingerprintstringStable identity of the exact owned bytes and every layout-affecting font option.

RefFieldContextinterfaceSource ↗

The story's resolved REF inputs for one layout pass.

Threaded as a runtime rider on the layout options (see layoutSemanticDocument) rather than a SemanticLayoutOptions member, so the public options surface stays put. Absent means every REF field paints its cached result — the pre-existing degradation, and the one header/footer and text-box stories still take. Note stories receive the body's context through NotesLayoutInput.refFields.

interface RefFieldContext
MemberTypeSummary
autonumValueOfThe synthesized display of ONE AUTONUM-family field, keyed by its begin / `w:fldSimple` node id, or null to paint nothing (unsupported switches, or an anchor this scan never saw — both the field's historical rendering). These fields carry no cached result at all, so there is no calibration: the sequential value is the only display they have. Optional so hand-built contexts predating it stay valid.
liveValueOfThe live value ONE field paints, keyed by its begin / `w:fldSimple` node id, or null to keep the cached result (failed calibration, unresolvable, or an anchor this scan never saw). Anchor-keyed so the projection's paint and this context's token fold read the SAME calibration verdict, however each walk collected the field's cached text.
pageRefProjectionOfThe deferred projection of ONE `PAGEREF` field, or null to keep the cached result (missing bookmark, unsupported switches, or an anchor this scan never saw).
tokenForParagraphThe paragraph's REF outputs folded for its block cache key; `''` when it holds none.
valuesTokenstringContent token over each paragraph ID and its PAINTED REF outputs in the story, for the section prepass memo. IDs keep structural edits from moving an identical sequence of outputs between paragraphs while the aggregate falsely reports unchanged dependencies. A renumbering edit can move a REF value in a section whose own blocks and list map are identity-unchanged, and this token is the only validator that sees it. A field that failed calibration contributes its (session-constant) cached text, so the token still moves when painted output or its owning paragraph changes.

RefFieldRefreshOptionsinterfaceSource ↗

interface RefFieldRefreshOptions
MemberTypeSummary
displayMode?RevisionDisplayModeThe mode the surface painted under, so the saved values match the painted ones.
numberingIndex?NumberingIndex
package?OoxmlPackageThe package the part belongs to, for the note-part half of the resolution context — the same context paint uses, so a body REF that targets a footnote bookmark computes the same value both places. Absent narrows resolution to body-declared bookmarks.
pageRefPageNumberOf?(targetParagraphId: string) => string | nullThe DISPLAYED page number of one paragraph in the current finalized layout, or null when it is not placed. PAGEREF results ride the plan through this: the value is pagination's, so only a caller holding the laid-out pages can answer, and a plan without it keeps every PAGEREF result as loaded. The same calibration verdict paint took gates each rewrite.
styleCascade?StyleCascadeTable

RefFieldSpecinterfaceSource ↗

One recognized REF instruction: the target name and the supported switches, nothing else.

interface RefFieldSpec
MemberTypeSummary
bookmarkstring
numberSwitch'r' | 'w' | 'n' | null`r` / `w` paint the target's number; `n` the same without context; null the range text.

RefNotePartsinterfaceSource ↗

Note parts whose stories join the context: their REF fields resolve against the body's bookmarks and numbering (a footnote citing "Section 1.2(c)" targets a body paragraph), and their bookmark declarations become plain-REF targets. Number switches aimed AT a note paragraph still fall back to the cached result — the list map is the body's.

interface RefNoteParts
MemberTypeSummary
endnotesPartOoxmlPart | null
footnotesPartOoxmlPart | null

Sanitized field link retained for interactive consumers.

interface RegisteredFieldLink
MemberTypeSummary

ResolvedCellBordersinterfaceSource ↗

Layout-owned cell borders after conflict resolution and compound expansion.

Convenience top/left/bottom/right are set when that side has a single uniform full-span winner (existing consumers / CSS simple edges). Multi-interval winners live only on edgeSegments. Compound geometry is always on strokes.

interface ResolvedCellBorders
MemberTypeSummary
bottom?ResolvedTableBorderEdge
edgeSegments?readonly ResolvedTableBorderEdgeSegment[]
left?ResolvedTableBorderEdge
right?ResolvedTableBorderEdge
strokes?readonly TableBorderStrokeRecord[]
top?ResolvedTableBorderEdge

ResolvedFontinterfaceSource ↗

A face that passed admission: the bytes are present, within limits, hash-verified, and parse as a font.

Branded, so a ResolvedFont cannot be constructed by an object literal. Holding one is proof the checks ran — which is what lets shaping skip re-validating on every call.

interface ResolvedFont
MemberTypeSummary
[RESOLVED_FONT_BRAND]true
byteLengthnumberOwned byte length, available without creating a defensive byte copy.
bytesUint8Array
faceIndexnumber
familystring
hashstring
idstring
identitystring
requestFontRequest
substitutionFontSubstitution | null

ResolvedListIteminterfaceSource ↗

A paragraph's list membership fully resolved: definition, level, marker text and geometry.

markerText is already expanded through the counter state, so it is the string a reader sees rather than the w:lvlText template.

interface ResolvedListItem
MemberTypeSummary
abstractNumIdstring
cacheTokenstringFingerprint for layout cache keys (indent, marker text, marker face).
ilvlnumber
indentNumberingLevelIndentEffective indent after merging level + paragraph indents, in points.
markerAlignListMarkerAlign
markerStyleResolvedRunStyle
markerTextstring
numFmtstring`w:numFmt` of the resolved level — `bullet` or a numbering format.
numIdstring
ordinal?numberCounter value at this item's own level; absent for bullets.
suffixListSuffix

ResolvedRunStyleinterfaceSource ↗

A run's character properties after the full cascade, in the units layout works in.

Points rather than half-points, RRGGBB rather than theme references — everything already resolved, so measurement and paint never re-run the cascade per glyph.

interface ResolvedRunStyle
MemberTypeSummary
baselineShiftPtnumber`w:position`, in points. Positive raises the baseline.
boldboolean
capsboolean
characterSpacingPtnumber`w:spacing`, in points. Added to every advance.
colorstring | nullRRGGBB, or null for the inherited/automatic colour.
doubleStrikeboolean
fontFamilystring | null
fontFamilyEastAsiastring | nullThe `eastAsia` slot's typeface (`w:rFonts w:eastAsia`/`w:eastAsiaTheme`), or null when no level authors one.
fontSizePtnumberPoints. `w:sz` is half-points, so 22 becomes 11.
hiddenboolean`w:vanish` (ECMA-376 §17.3.2.45): the run is hidden text.
highlightstring | nullAn `ST_HighlightColor` name, or null.
horizontalScalePercentnumber`w:w`, as a percentage. 100 is unscaled.
italicboolean
kerningMinPtnumber`w:kern`, in points: the size at or above which kerning applies. 0 disables it.
shadingstring | nullCharacter shading fill (`w:rPr/w:shd`), validated RRGGBB, or null.
shaping?{ readonly script: string; readonly direction: 'ltr' | 'rtl'; readonly level: number; readonly baseLevel: number; readonly runDirection?: 'ltr' | 'rtl'; readonly wordSpacingPt?: number; }Script and paragraph-resolved direction for shaping and visual placement.
smallCapsboolean
strikeboolean
textOutline?{ readonly widthPt: number; readonly color: string; }Opaque solid `w14:textOutline`, in points; paint only, never a font-weight change.
underlineResolvedUnderline | null
verticalAlignVerticalAlign

ResolvedSurfaceMeasurerinterfaceSource ↗

The measurer a surface ended up with, plus the identity its cache keys must include.

The producer string is load-bearing: the same canvas measuring against document-embedded faces produces DIFFERENT advances, so the two must not share a cache key space or a document would keep its pre-font pagination after the font arrived.

interface ResolvedSurfaceMeasurer
MemberTypeSummary
measurerTextMeasurer
producer'canvas-measurer' | 'canvas-measurer+embedded' | 'fixed-measurer'Cache-invalidation identity when the caller did not supply `producer`.

ResolvedTableBorderEdgeinterfaceSource ↗

Final edge winner; absent means the side/interval is not drawn.

interface ResolvedTableBorderEdge
MemberTypeSummary
colorstring | null
styleTableBorderStyle
widthPtnumber

ResolvedTableBorderEdgeSegmentinterfaceSource ↗

Conflict winner over one grid interval of a cell side.

gridStart/gridEnd are absolute grid column indices for horizontal sides and absolute row indices for vertical sides (half-open). startPt/endPt are cell-local along-axis positions in layout points.

interface ResolvedTableBorderEdgeSegment
MemberTypeSummary
edgeResolvedTableBorderEdge
endPtnumber
gridEndnumber
gridStartnumber
sideTableBorderSideName
startPtnumber

ResolvedTabStopsinterfaceSource ↗

A paragraph's tab stops after the style cascade, with the default interval that applies past the last explicit one.

interface ResolvedTabStops
MemberTypeSummary
defaultIntervalPtnumberDefault-tab interval in points (always positive and bounded).
stopsreadonly TabStop[]Custom stops sorted by ascending position.

ResolvedUnderlineinterfaceSource ↗

A resolved underline: its variant, and its colour when it does not follow the text.

interface ResolvedUnderline
MemberTypeSummary
colorstring | nullRRGGBB, or null when the underline follows the text colour.
variantstringThe authored `ST_Underline` variant.

ResourceDependencyProvenanceinterfaceSource ↗

One resource a cached entry consumed, and the fingerprint it had at the time.

Per-dependency rather than one global epoch, so updating one font does not evict entries that consumed a different, unchanged font.

interface ResourceDependencyProvenance
MemberTypeSummary
fingerprintstring
keystring

ReviewCommentIteminterfaceSource ↗

One comment as a review card. A reply carries parentId; OOXML gives replies no separate element, so threads are reconstructed from that link.

interface ReviewCommentItem
MemberTypeSummary
commentCommentRecord
idstring
kind'comment'
orphanedbooleanTrue when the file gave this comment no usable range.
parentId?stringThe comment this replies to, absent for a top-level comment.
parentRevisionId?stringThe REVISION this comment answers, when it covers exactly that change's characters.
rangeReviewRange | null
replyIdsreadonly string[]Replies to this comment, in document order. Empty for a reply or a childless comment.
resolvedboolean

ReviewCustomIteminterfaceSource ↗

A card contributed by a recognized custom node (defineCustomNode with a reviewCard hook), anchored at the node's range.

Informational, never resolvable: there is nothing to accept or reject, so the engine refuses those verbs on it. title and detail are HOST-authored (the definition's hook produced them), but attrs and text originate in a file an attacker controls — a surface renders every one of these as text, never markup.

interface ReviewCustomItem
MemberTypeSummary
attrsReadonly<Record<string, string>>Attrs decoded from the tag, after the definition's recognition hook. Untrusted input.
cardedbooleanWhether this node asked for a sidebar card.
data?unknownThe payload the node's control binds to, after the definition validated it.
detail?stringCard body, from the definition's `reviewCard` hook.
icon?stringGlyph for this node in the collapsed rail, as an SVG path in a `0 -960 960 960` viewBox.
idstringThe SDT node's stable id in the canonical tree.
kind'custom'
namestringThe definition's `name`.
rangeReviewRange | null
tagstringThe raw `w:tag` the node was recognized from. Untrusted input.
textstringThe SDT's literal content text. Untrusted input.
titlestringCard title, from the definition's `reviewCard` hook. Empty when `carded` is false.

ReviewModelInputinterfaceSource ↗

What the review queue derivation reads: one story part plus its comment parts.

interface ReviewModelInput
MemberTypeSummary
commentsExtendedPart?OoxmlPart | undefined`word/commentsExtended.xml`, absent when the package has none.
commentsPart?OoxmlPart | undefined`word/comments.xml`, absent when the package has none.
customNodePayloads?ReadonlyMap<string, { readonly nodeId: string; readonly label: string; readonly data: string; }> | undefinedThe payload each of the story's controls binds to, keyed by the control's node id.
customNodes?readonly unknown[] | undefinedCustom node definitions from the module registry, forwarded OPAQUELY.
furnitureParts?readonly OoxmlPart[] | undefinedHeader/footer story parts, in section order. Their revisions and comment anchors join the queue: a tracked change in a header is a pending decision like any other, and a queue that only walked the body silently hid it from the rail AND from Accept All.
reportCustomNodeDiagnostic?((diagnostic: unknown) => void) | undefinedWhere a capability package reports a node it could not read. Supplied per editor, so a page with two of them keeps their diagnostics apart.
storyPartOoxmlPartThe story the ranges live in — the main document, a header, a note.
stylesPart?OoxmlPart | undefinedShared style definitions. Their revisions have no paragraph range.

ReviewParagraphAnchorinterfaceSource ↗

Where one paragraph sits, resolved once so a card is an O(1) lookup.

interface ReviewParagraphAnchor
MemberTypeSummary
contentYnumberSheet-absolute y of the page's content box.
fragmentYnumberThe fragment's own y, measured from that content box.
lines?readonly { readonly range: { readonly end: number; }; readonly box: { readonly y: number; }; readonly spans?: readonly { readonly range: { readonly paragraphId: string; readonly end: number; }; }[]; }[]
pageIndexnumber

ReviewPositioninterfaceSource ↗

A position in the model offset space of one story.

interface ReviewPosition
MemberTypeSummary
offsetnumber
paragraphIdstring

ReviewRangeinterfaceSource ↗

Where an item is anchored: a range in one story.

interface ReviewRange
MemberTypeSummary
endReviewPosition
partNamestring
startReviewPosition

ReviewRevisionIteminterfaceSource ↗

One tracked change as a review card.

Keyed per DECISION rather than per site: a revision spanning three ranges is one card, because accepting it accepts all three.

interface ReviewRevisionItem
MemberTypeSummary
addressRevisionAddressThe payload `acceptRevision` / `rejectRevision` take.
addressesreadonly RevisionAddress[]EVERY address this decision covers, `address` first.
authorstring
date?string
formattingChanges?readonly { readonly property: 'bold' | 'italic' | 'underline' | 'strike' | 'fontFamily' | 'fontSize' | 'color' | 'alignment' | 'leftIndent' | 'rightIndent' | 'firstLineIndent' | 'hangingIndent' | 'spaceBefore' | 'spaceAfter'; readonly value: string | null; }[]Changed direct formatting values, ready for localized review summaries.
formattingKind?stringOOXML property-change element, used to resolve independently numbered formatting kinds.
formattingLanguages?readonly string[]Newly applied proofing language codes in a tracked formatting change.
idstringStable across renders and unique per DECISION, not per site.
kind'revision'
markDirection?'insert' | 'delete' | 'moveFrom' | 'moveTo'WHICH decision a `paragraphMark` records, absent for every other kind.
nestingnumberHow deeply this change is NESTED inside other changes, 0 for an unenclosed one.
pairedWith?stringThe other half of a move, or the other side of a delete/insert replacement.
rangesreadonly ReviewRange[]Every site this decision touches, in document order.
readOnlybooleanTrue when the engine cannot resolve this kind, so accept and reject must not be offered.
replacedRangeCount?numberHow many leading `ranges` are the STRUCK half of a replacement.
replacedTextstringThe words a replacement removes. Empty for every other kind.
replyIdsreadonly string[]Comments answering this change, in document order.
revisionKindReviewRevisionKind
structuralChanges?readonly ('rowInsert' | 'rowDelete' | 'cellInsert' | 'cellDelete' | 'cellMerge' | 'numberingInsert')[]Distinct structural operations covered by this decision, in document order.
textstringText the revision covers, for the card summary. Empty for changes with no characters.

RevisionAttributioninterfaceSource ↗

One revision wrapper's provenance, as authored.

id is the verbatim @w:id string rather than a number: ST_DecimalNumber restricts xsd:integer with no bounds, so a file may carry a value outside the safe integer range, and parsing it to a number would silently merge two distinct revisions.

date is absent when the file omits it. @w:date is optional on CT_TrackChange, and inventing one is a silent content change.

interface RevisionAttribution
MemberTypeSummary
authorstring
date?string
idstring
kindRevisionKind
nodeIdstringThe wrapper's node id, so a surface can address this exact site.

RevisionAuthorFilterinterfaceSource ↗

Deprecated. Use [RevisionFilter](RevisionFilter).

interface RevisionAuthorFilter extends RevisionFilter

RevisionFilterinterfaceSource ↗

A view-time tracked-change filter. Revisions rejected by includes use the filter's accepted or rejected projection, while included revisions keep the display mode's normal projection.

cacheKey is a canonical, content-based identity for layout caches. The set itself is kept because author names are attacker-controlled strings and must never be parsed back from a delimiter-based key.

interface RevisionFilter
MemberTypeSummary
cacheKeystring
excludedNodeMode?(nodeId: string, author: string) => 'proposed' | 'original'Accepted/original projection for a revision excluded by `includesNode`.
hiddenAuthorsReadonlySet<string>
includes?(revision: RevisionAttribution) => boolean
includesNode?(nodeId: string, author: string) => boolean
resolvedMarkup?'plain'In a resolved view, content the view keeps paints as ORDINARY text: no author ink, no decoration, no change bar of its own. This is Word's No Markup, Original and Simple Markup, which the review chrome asks for. Without it the accepted projection keeps the attribution on kept insertions, which is what the engine paints when no review module is registered — colour by author, deletions resolved — and what its roster reads.

ScriptIteminterfaceSource ↗

A run of text sharing one script, direction and font slot — the unit handed to the shaper.

Shaping cannot span a script change: Arabic and Latin in one call would produce wrong joining behaviour, so a run is itemized into these first.

interface ScriptItem
MemberTypeSummary
bidiLevelnumber
directionTextDirection
fromnumber
script'Zyyy' | 'Latn' | 'Grek' | 'Cyrl' | 'Hani' | 'Hebr' | 'Arab' | 'Deva' | 'Beng' | 'Thai' | 'Khmr'
slotFontSlot
tonumber

SectionColumnDefinitioninterfaceSource ↗

One explicit w:col: its width and the gap after it.

interface SectionColumnDefinition
MemberTypeSummary
gapTwipsnumberSpace after this column; zero on the final column.
widthTwipsnumber

SectionColumnsinterfaceSource ↗

A section's column layout.

Equal-width and explicit-width columns are one type because a file may declare w:num with no w:col children at all, and layout must handle both without branching at every use site.

interface SectionColumns
MemberTypeSummary
countnumber
definitions?readonly SectionColumnDefinition[]Authored `w:col` geometry when `equalWidth` is false.
equalWidth?boolean
gapTwipsnumberShared gap for equal-width columns and fallback gap for incomplete explicit definitions.
separator?boolean

SectionMarginsinterfaceSource ↗

A section's margins in twips, including the header and footer reserve bands.

interface SectionMargins
MemberTypeSummary
bottomTwipsnumber
footerTwipsnumber
gutterTwipsnumber
headerTwipsnumber
leftTwipsnumber
rightTwipsnumber
topTwipsnumber

SectionPageBordersinterfaceSource ↗

One section's resolved w:pgBorders.

Resolved, not raw: every attribute the file omitted is filled in with the SCHEMA default, so a consumer never has to know which of the three were authored. An edge is present only when it paints — nil / none and art borders are already gone (see [parsePageBorders](parsePageBorders)).

interface SectionPageBorders
MemberTypeSummary
bottom?ParagraphBorderEdge
displayPageBorderDisplay`w:display`; absent attribute reads as `allPages`.
left?ParagraphBorderEdge
offsetFromPageBorderOffsetFrom`w:offsetFrom`; absent attribute reads as `text` (§17.6.10).
right?ParagraphBorderEdge
top?ParagraphBorderEdge
zOrderPageBorderZOrder`w:zOrder`; absent attribute reads as `front`.

SectionPageNumberinginterfaceSource ↗

Authored w:pgNumType (ECMA-376 CT_PageNumber).

Distinguishes three states via [SectionProperties.pageNumbering](SectionProperties.pageNumbering): - element absent → undefined (Word defaults; no empty element to re-emit) - empty <w:pgNumType/>{} (present, no authored attrs; must round-trip empty) - attributes set → only those keys appear (never invent schema defaults like fmt=decimal)

chapStyle / chapSep are preserved for consumers; PAGE projection does not yet compose chapter numbers (heading outline resolution is out of this slice).

interface SectionPageNumbering
MemberTypeSummary
chapSep?stringAuthored `@w:chapSep` when present (hyphen / period / colon / emDash / enDash).
chapStyle?numberAuthored `@w:chapStyle` outline level when present and in range.
fmt?stringAuthored `@w:fmt` (ST_NumberFormat) when present; otherwise omitted.
start?numberAuthored `@w:start` when present and in range; otherwise omitted.

SectionPropertiesinterfaceSource ↗

One section's resolved w:sectPr, as layout needs it.

Resolved, not raw: defaults the file omitted are filled in here (an absent w:type is nextPage), so layout never has to know which attributes were authored and which were inherited.

interface SectionProperties
MemberTypeSummary
breakTypeSectionBreakTypeAbsent `w:type` defaults to `nextPage`.
columnsSectionColumns
gridLinePitchTwips?numberActive document grid line pitch for line-unit paragraph margins.
landscapeboolean
marginsSectionMargins
pageBorders?SectionPageBordersResolved `w:pgBorders` (§17.6.10). Absent when the section declares none, or when every edge it declares is off or an art border — see [parsePageBorders](parsePageBorders).
pageNumbering?SectionPageNumberingAuthored page-number type. Absent when `w:pgNumType` is missing; empty object when the element is present with no attributes (comprehensive-fixture shape).
pageSize{ readonly widthTwips: number; readonly heightTwips: number; }
titlePageboolean

SelectionRectinterfaceSource ↗

One painted selection rectangle, in page-relative layout points.

interface SelectionRect
MemberTypeSummary
heightnumber
pageIndexnumber
widthnumber
xnumber
ynumber

SemanticCommentArtifactRecordinterfaceSource ↗

Normalized comment; all relation ids share the opaque snapshot-local id space.

interface SemanticCommentArtifactRecord
MemberTypeSummary
authorstring
date?string
idstring
initialsstring
kind'comment'
occurrencesreadonly SemanticReviewArtifactOccurrence[]
orphanedboolean
parentId?string
parentRevisionId?string
replyIdsreadonly string[]
resolvedboolean
textstring

SemanticDrawingVisitinterfaceSource ↗

One drawing in bounded graph-enumeration order with exporter-grade provenance.

Enumeration is deliberately not paint order: story anchors (and nested textboxes) are visited before inline line drawings. Renderers use paintLayer plus record geometry to compose layers.

interface SemanticDrawingVisit extends StoryDrawingContext
MemberTypeSummary
absoluteHitBoundsLayoutBoxAbsolute pointer/hit bounds.
absolutePaintBoundsLayoutBoxAbsolute painted bounds, including effects and clipping.
drawingInlineDrawingRecord | AnchoredDrawingRecordPublished drawing record; inline visits also carry paragraph and line.
drawingOriginReadonly<{ x: number; y: number; }>Absolute origin of this drawing's extent in page-stack coordinates.
noteAreaKindNoteAreaRecord['kind'] | nullOwning note-area kind for note/separator drawings; null elsewhere.
noteScopeIdstring | nullNote scope for drawings in note stories; null elsewhere.
pagePageRecordPhysical page carrying this drawing occurrence.
paintLayerSemanticDrawingLayerLayer relative to text in the immediate owning story.
rootSemanticStoryVisitPrecise root host and absolute origin for story-relative geometry.
rootStorySemanticRootStoryKindRoot story from which textbox descent began.
storySemanticStoryKindImmediate story classification; `textbox` after textbox descent.

SemanticHitinterfaceSource ↗

What a point landed on: a semantic position, its caret geometry, and where it sits.

interface SemanticHit
MemberTypeSummary
caretCaretGeometry
cellTableCellAddress | nullNull outside a table; the innermost cell when tables nest.
contentControlIdstring | nullInnermost content-control boundary covering the hit point, or null outside every control.
drawingSemanticHitDrawing | nullNon-null when the hit resolved to an inline drawing atom.
lineIdstring
onGlyphsbooleanTrue when the point was inside the resolved line's box AND inside one of its spans.
pageIndexnumber
positionSemanticPosition

SemanticHitDrawinginterfaceSource ↗

Stable inline drawing identity when a hit resolves to a drawing atom.

interface SemanticHitDrawing
MemberTypeSummary
drawingNodeIdstring
paragraphIdstring
startnumber

SemanticLayoutinterfaceSource ↗

A complete layout pass: every page, plus the document-wide indexes derived alongside them.

Stamped with the store revision it was laid out from, so anything holding geometry can tell whether the document has moved underneath it — which is how stale pointer gestures and overlays are refused rather than applied to coordinates that no longer describe anything.

interface SemanticLayout
MemberTypeSummary
contentControls?readonly ContentControlBoundaryRecord[]Every content-control boundary in document order, including multi-page fragment lists.
controlContextToken?stringFingerprint of wrapper-only control metadata (alias, tag, lock, type, placeholder, binding).
displayMode?RevisionDisplayModeRevision projection already applied to every published record.
pagesreadonly PageRecord[]
reviewArtifacts?readonly SemanticReviewArtifactRecord[]Normalized comments and tracked changes from the same package revision as these pages. Exporters consume this plain-data stream instead of re-reading OOXML or review state.
revisionnumberThe store revision these records were laid out from.

SemanticLayoutOptionsinterfaceSource ↗

Everything a layout pass needs beyond the document itself.

measurer is the only required field — layout is DOM-free and measures through whatever is injected here, which is what lets the same code paginate on a server and in a browser.

interface SemanticLayoutOptions
MemberTypeSummary
cache?ParagraphLayoutCache<readonly PendingLine[]>Reuse of measured-and-broken paragraphs across revisions (task 9.2).
compatibilityMode?numberExplicit Word compatibility mode; absent retains existing geometry.
defaultTabStopPt?number`w:settings/w:defaultTabStop` in points (ECMA-376 §17.15.1.25); absent keeps the 0.5" schema default.
displayMode?RevisionDisplayModeWhich tracked revisions this pass resolves away (ECMA-376 §17.13).
documentProperties?DocumentPropertiesThe document's parsed metadata, for document-property fields (TITLE, AUTHOR, …). Read once by the surface and shared across body, table, note and header/footer flows.
drawingExclusionConverged?booleanInternal: converged exclusion zones — skips the reflow loop when set with zones.
drawingExclusionPass?numberInternal: reflow pass index while wrap exclusions converge.
drawingExclusionZonesByPage?ReadonlyMap<number, readonly ExclusionZone[]>Internal: exclusion zones from the prior reflow pass, keyed by page index.
drawingLayoutEpoch?stringPart-level drawing projection/resource epoch for the section prepass memo.
drawingLayoutToken?string
drawingSourceOrder?ReadonlyMap<string, number>Canonical drawing traversal order within the owner story part.
drawingTokenForParagraph?(paragraph: OoxmlNode) => stringPer-paragraph drawing projection/resource token for break cache keys.
emptyTocPlaceholderParagraphIds?ReadonlySet<string>Begin-paragraph ids of empty TOCs. These keep one layout line so paint can host an identifiable empty-TOC furniture placeholder (overrides chrome suppression).
emptyTocSuppressedResultParagraphIds?ReadonlySet<string>Empty result-paragraph ids inside empty TOCs. Suppressed like field chrome so blank cached rows do not stack under the empty placeholder.
furniture?PageFurnitureHeader/footer stories to attach per page; absent means no furniture.
geometry?PageGeometry
inlineDrawingLayout?InlineDrawingLayoutContextInline drawing projection for typed `w:drawing` / `wp:inline` nodes.
listItems?ReadonlyMap<string, ResolvedListItem>Optional precomputed list items for the body story. When absent and [numberingIndex](numberingIndex) is set, layout walks the full body (including table cells) once so counters continue across section boundaries and table document order.
measurerTextMeasurer
noteMarks?NoteMarkContextDerived note marks for body/note projection (provisional or final).
notes?NotesLayoutInputFootnote/endnote layout input. When present, body layout projects note marks and a post-pass attaches note areas (with bounded reflow for pageBottom reservation).
numberingIndex?NumberingIndexProjection of `/word/numbering.xml`. Absent keeps pre-list behaviour (no markers / level indents). The index is immutable for a session; list counter state is derived per layout pass from document order.
pageBottomReserves?ReadonlyMap<number, number>Per-page bottom reserves (points) subtracted from content height before line placement, keyed by DOCUMENT page index. A section's pass reads its own slice through `pageIndexStart`. Produced by the note reflow loop; absent means full content column.
paragraphLineUnitPt?numberSection grid pitch used for line-unit paragraph margins.
producer?stringWho produced the measurements, folded into every cache key.
projectionEpoch?stringPart-level freshness signal for paragraph-local semantic projection tokens.
projectionTokenForParagraph?(paragraph: OoxmlNode) => stringPer-paragraph identity for projected links and live document-property text.
projectionTokenForTable?(table: OoxmlNode) => stringMemoized aggregate projection identity for an immutable table subtree.
retainKeys?Set<string> | falseCollector for the cache keys a pass wants retained, instead of retaining directly. Supplied by the multi-section orchestrator, which retains once over the union — retaining per section evicted every other section's entries. `false` skips retention for this pass entirely (the orchestrator strides sweeps). See `retainLiveBreakKeys`.
revisionAuthorFilter?RevisionAuthorFilterReviewers whose revisions render as their accepted projection.
sectionColumns?SectionColumnsAuthored column count/gap for anchored `relativeFrom="column"` frame resolution.
sectionFurniture?readonly (PageFurniture | undefined)[]Per-section furniture, index-aligned with `enumerateDocumentSections`.
sectionPageBorders?SectionPageBordersThis section's resolved `w:pgBorders`, for the frame each of its sheets publishes.
session?LayoutSessionIncremental placement across revisions (task 9.3).
styleCascade?StyleCascadeTableStyles-part cascade table (docDefaults + `w:style` last-wins). Absent keeps direct formatting only — the pre-cascade behaviour, used by unit tests that never open a package.
tocFieldChromeParagraphIds?ReadonlySet<string>Cross-paragraph TOC field begin/end paragraph ids. Empty chrome on these ids suppresses the caret placeholder line in layout while the tree nodes stay intact for refresh/save.

SemanticPositioninterfaceSource ↗

A caret position in the model.

interface SemanticPosition
MemberTypeSummary
offsetnumber
paragraphIdstring

SemanticReviewArtifactOccurrenceinterfaceSource ↗

One physical occurrence of a comment or tracked-change source range.

interface SemanticReviewArtifactOccurrence
MemberTypeSummary
geometry?SemanticReviewArtifactOccurrenceGeometryLaid-out bounds when this occurrence can be measured; omitted otherwise.
noteAreaKind'footnotes' | 'endnotes' | null
noteScopeIdstring | null
pageIndexnumber
physicalPageNumbernumber
revisionRole?'replaced' | 'replacement' | 'neutral'Replacement-half meaning for tracked-change occurrences; absent for comments.
rootStorySemanticArtifactRootStoryKind
sourceSemanticReviewArtifactSource
storySemanticArtifactStoryKind
textboxPathreadonly string[]Root-to-leaf drawing ids for a textbox occurrence; empty outside textboxes.

SemanticReviewArtifactOccurrenceGeometryinterfaceSource ↗

Laid-out bounds for one review occurrence.

pageContent uses the same space as line boxes. pageStack uses stacked page coordinates. A point occurrence publishes width: 0.

interface SemanticReviewArtifactOccurrenceGeometry
MemberTypeSummary
pageContentreadonly LayoutBox[]
pageStackreadonly LayoutBox[]

SemanticReviewArtifactPositioninterfaceSource ↗

One model position retained as exporter provenance.

interface SemanticReviewArtifactPosition
MemberTypeSummary
offsetnumber
paragraphIdstring

SemanticReviewArtifactSourceinterfaceSource ↗

Package-relative snapshot provenance, not durable public identity.

Engine-produced occurrences keep start.paragraphId === end.paragraphId. Cross-paragraph source ranges are sliced into per-paragraph occurrences before geometry attaches.

interface SemanticReviewArtifactSource
MemberTypeSummary
endSemanticReviewArtifactPosition
partNamestring
startSemanticReviewArtifactPosition

SemanticSelectioninterfaceSource ↗

A selection as two semantic positions — never as DOM nodes.

anchor is where the selection started and head is where it currently ends, so head before anchor is an ordinary backwards selection rather than an error. Collapsed when the two are equal, which is what a caret is.

interface SemanticSelection
MemberTypeSummary
anchorSemanticPosition
headSemanticPosition

SemanticSpanVisitinterfaceSource ↗

One span in the engine's published story order.

interface SemanticSpanVisit
MemberTypeSummary
absoluteBoxLayoutBoxAbsolute laid-out span bounds in page-stack coordinates.
lineLineRecord
noteAreaKindSemanticStoryVisit['noteAreaKind']
noteScopeIdstring | nullOwning note scope/area where applicable; null for body and page furniture.
pagePageRecord
paragraphParagraphFragmentRecordEnclosing published fragment; use paragraphId for the authored span owner.
paragraphIdstringAuthored paragraph owning this span, including spans merged into another fragment.
rootSemanticStoryVisitPrecise root host and absolute origin for story-relative geometry.
rootStorySemanticRootStoryKindRoot story from which textbox descent began; equal to `story` outside textboxes.
sourceRangeSourceRange | nullModel address for authored text. Projected atoms intentionally return null even though their geometry record carries a range used internally by layout.
spanStyleSpanRecord
storySemanticStoryKind
storyOriginReadonly<{ x: number; y: number; }>Absolute origin of the immediate root or textbox story containing this span.
textboxDepthnumberZero outside a textbox, otherwise its bounded nesting depth.
textboxOwnerAnchoredDrawingRecord | nullImmediate textbox-owning anchor, or null in the root story.
textboxPathreadonly AnchoredDrawingRecord[]Root-to-leaf textbox owners, preserving anchor identity for future exporters.

SemanticTableCellinterfaceSource ↗

One cell in the resolved table structure.

gridSpan is clamped at READ time and layout never re-derives it — the value comes from a file and would otherwise be a loop bound an attacker controls.

interface SemanticTableCell
MemberTypeSummary
blocksreadonly OoxmlElement[]Block children in reading order, with content-control wrappers flattened.
bordersCellBorderBoxThree-state authored `tcBorders` (omitted / none / edge).
gridColumnnumberPhysical grid column after width/style resolution and the bidiVisual projection.
gridColumnId?stringCanonical `w:gridCol` node id for this cell's start column, when the grid is authored.
gridSpannumberClamped to [1, MAX_TABLE_COLUMNS] at read time; layout never re-derives it.
idstring
legacyContentAlignment?trueDerived content-edge geometry for a verified legacy full-width parent table.
logicalGridColumn?numberStored grid index when bidiVisual maps this cell into a physical RTL grid.
marginsCellMarginsPtResolved per-side margins (tcMar over tblCellMar over the table style over Word's default).
preferredWidthPreferredWidth`w:tcW` — the width this cell asked for, as authored.
shading?stringValidated 6-hex shading fill, absent for none/auto.
styleFormattingTableCellStyleFormattingWhat the table style says about this cell's paragraphs and runs (17.7.6.6) — a header row's bold and centring live here, not in the cell's own properties.
textDirection'horizontal' | 'btLr'`w:textDirection`; unsupported values keep horizontal layout.
vAlignCellVerticalAlign`w:vAlign` — defaults to top when omitted/unrecognised.
vMergeContinuebooleanA vMerge cell that is not the restart continues the cell above: box, no content.

SemanticTableRowinterfaceSource ↗

One row in the resolved structure: its cells, its height rule, and any row-level revision.

interface SemanticTableRow
MemberTypeSummary
cantSplitboolean`w:trPr/w:cantSplit` — the row must stay on one page. When it cannot fit a fresh page, layout fails closed rather than fragmenting or overflowing the content box.
cellsreadonly SemanticTableCell[]
changeSites?readonly RevisionAttribution[]The row insertion a resolved view kept the row through; see the fragment record.
heightTableRowHeight`w:trPr/w:trHeight` — auto / atLeast floor / exact (clipped) row height.
idstring
isHeaderboolean`w:trPr/w:tblHeader` — the row repeats atop each page the table continues onto.
revisionAuthor?string
revisionDate?string
revisionId?stringThe `w:trPr/w:ins|w:del` attribution, carried with the kind so a painted row can say WHOSE pending decision it is — the review model addresses the decision by exactly this `(id, author, date)` triple, and a surface with only the kind could highlight the row but never open its card.
revisionKind?'insert' | 'delete'Pending Word row insertion/deletion authored in `w:trPr`.

SemanticTableStructureinterfaceSource ↗

A table resolved into a rectangular grid: column widths, rows, and the widths it asked for.

The grid is normalized here so layout never has to reconcile w:gridCol against actual cell spans — vertical merges and column spans are already accounted for.

interface SemanticTableStructure
MemberTypeSummary
alignmentTableAlignment`w:tblPr/w:jc` (17.4.29) — where the table sits in the text column.
bidiVisual?trueWhether stored columns and horizontal table properties display right to left.
cellSpacingPtnumber`w:tblCellSpacing` (17.4.45) in points: the gap between adjacent cell edges. Applied as a half-gap inset on each side of every cell, so cells separate visually without the grid itself moving. Word ALSO grows the table's overall width by the spacing it adds around the outside; that part is not modelled, so a spaced table is laid out on the same grid its file states rather than a wider one.
columnWidthsPtreadonly number[]
defaultMarginsCellMarginsPtTable-level `tblCellMar` defaults (per-side, Word's own default when a side is omitted).
float?TableFloatPosition`w:tblPr/w:tblpPr` (17.4.57) — present when the table is positioned against an anchor box. Placement then comes from [tableFloatOriginX](tableFloatOriginX) rather than `w:jc`/`w:tblInd`.
indentPtnumber`w:tblInd` (17.4.50) in points — "this indentation should shift the table into the text margin by the specified amount". Applies to a left-aligned table; `w:jc` decides the placement outright for the other two.
layoutFixedboolean`w:tblPr/w:tblLayout/@w:type="fixed"` (17.4.52 — 17.4.53 is the `w:tblPrEx` exception variant, not this element). Fixed layout takes the grid as final; anything else is autofit, which in Word never renders wider than the text column.
legacyContentAlignment?trueVerified pre-2013 content-aligned full-width inline table; derived, never serialized.
rowsreadonly SemanticTableRow[]
tableBordersTableBorderBoxTable-level `tblBorders` (three-state, including insideH/insideV).
tableWidthPreferredWidth`w:tblPr/w:tblW` — the width the table asked for.

SemanticTrackedChangeArtifactRecordinterfaceSource ↗

Normalized change; ids are opaque and stable only within the source snapshot.

interface SemanticTrackedChangeArtifactRecord
MemberTypeSummary
authorstring
change'insert' | 'delete' | 'replace' | 'moveFrom' | 'moveTo' | 'format' | 'paragraphMark' | 'structural'
date?string
idstring
kind'tracked-change'
markDirection?'insert' | 'delete' | 'moveFrom' | 'moveTo'
nestingnumberNested tracked-change depth, where the innermost decision is operative.
occurrencesreadonly SemanticReviewArtifactOccurrence[]
pairedWith?string
readOnlyboolean
replacedRangeCount?numberNumber of leading source ranges belonging to struck text in a replacement.
replacedTextstring
replyIdsreadonly string[]
textstring

ShapedClusterinterfaceSource ↗

One cluster: the smallest indivisible text-to-glyph correspondence.

The unit the CARET moves by. A cluster may be several characters (a ligature) or several glyphs (a decomposed mark), so neither a character index nor a glyph index is a valid caret position — caretEdges is, and it includes both endpoints.

interface ShapedCluster
MemberTypeSummary
advanceFixedPoint
caretEdgesreadonly FixedPoint[]Fixed-point edges from this cluster's visual origin, including both endpoints.
fontSpannumberIndex into ShapedRun.fontSpans, preserving the exact fallback choice.
glyphEndnumber
glyphStartnumberHalf-open visual glyph range in ShapedRun.glyphs.
textEndnumber
textStartnumberHalf-open logical UTF-16 range in ShapedRun.text.

ShapedFontSpaninterfaceSource ↗

A stretch of glyphs that came from ONE face.

A run whose text needed fallback has several of these. Recording the exact face per span is what lets a re-shape reproduce the same result rather than re-running fallback selection and possibly choosing differently.

interface ShapedFontSpan
MemberTypeSummary
fallbackIndexnumber | nullnull denotes the primary font; otherwise this is the environment fallback-order index.
fontResolvedFont
glyphEndnumber
glyphStartnumber

ShapedGlyphinterfaceSource ↗

One positioned glyph.

id is a glyph index in its FACE, not a character — a ligature is one glyph spanning several characters, and a single character may produce several glyphs. Use cluster to get back to text.

interface ShapedGlyph
MemberTypeSummary
advanceXFixedPoint
advanceYFixedPoint
clusternumberUTF-16 text offset identifying the cluster that produced this glyph.
idnumber
offsetXFixedPoint
offsetYFixedPoint
originXFixedPointPen origin before this glyph's shaping offsets, in fixed-point run coordinates.
originYFixedPoint
outlineGlyphOutlineExact monochrome outline returned by the admitted HarfBuzz face.

ShapedMeasurerOptionsinterfaceSource ↗

How the shaped measurer resolves fonts and bounds its work.

Font resolution is the HOST's: returning null means "not available" and measurement falls back rather than throwing, because a document naming a font nobody has must still lay out.

interface ShapedMeasurerOptions
MemberTypeSummary
fallbackTextMeasurerUsed when no font resolves.
features?Readonly<Record<string, number>>
fixedPointScale?numberFixed-point units per point in the shaper's output.
language?string
normalization?NormalizationPolicyOptional low-level shaping controls; omitted values preserve the released defaults.
resolveFont(style: ResolvedRunStyle) => ResolvedFont | nullThe font a run should be measured with.
roundingMode?FixedPointRoundingMode
script?stringISO 15924 script and BCP 47 language for shaping. Latin/English by default.
shaperTextShaper
shapingLibraryVersionedShapingLibrary
unicodeDataVersionstring

ShapedRuninterfaceSource ↗

One shaped run: text turned into positioned glyphs, with everything needed to measure it, paint it, and put a caret in it.

The engine's measurement unit. Layout never measures characters — it measures these.

interface ShapedRun
MemberTypeSummary
bidiLevelnumber
clustersreadonly ShapedCluster[]
directionTextDirection
fontSpansreadonly ShapedFontSpan[]
glyphsreadonly ShapedGlyph[]
metricsShapedVerticalMetrics
textstring

ShapedRunComparatorInputsinterfaceSource ↗

A [ShapedRun](ShapedRun) reduced to the fields two shaping results must agree on to be considered identical.

Fonts appear as [FontFingerprintInputs](FontFingerprintInputs) rather than whole ResolvedFont objects, so the comparison is over VALUES and does not depend on object identity — which is what makes it work across a reload or a worker boundary.

interface ShapedRunComparatorInputs
MemberTypeSummary
bidiLevelnumber
clustersreadonly ShapedCluster[]
directionTextDirection
fontSpansreadonly { readonly glyphStart: number; readonly glyphEnd: number; readonly fallbackIndex: number | null; readonly font: FontFingerprintInputs; }[]
glyphsreadonly ShapedGlyph[]
languagestring
metricsShapedVerticalMetrics
scriptstring
textstring

ShapedVerticalMetricsinterfaceSource ↗

A run's vertical metrics, from the face that shaped it. Drives line height and baseline.

interface ShapedVerticalMetrics
MemberTypeSummary
ascentFixedPoint
descentFixedPoint
lineGapFixedPoint

ShapeInputinterfaceSource ↗

One shaping call: the text, its size, its bidi level, and the environment to shape it in.

interface ShapeInput
MemberTypeSummary
bidiLevelnumberExact UAX #9 embedding/isolate level; direction is its parity projection.
environmentShapingEnvironment
fontSizeHalfPointsnumber
textstring

ShapingEnvironmentinterfaceSource ↗

A validated [ShapingEnvironmentInput](ShapingEnvironmentInput) — build one with createShapingEnvironment.

Structurally identical to its input, but the nominal distinction is the point: holding one means the tags, axes and fonts inside it have already been checked.

interface ShapingEnvironment extends ShapingEnvironmentInput

ShapingEnvironmentFingerprintInputsinterfaceSource ↗

A [ShapingEnvironment](ShapingEnvironment) reduced to comparable values.

Records and axis maps become SORTED entry arrays, because two environments differing only in key insertion order must fingerprint the same — otherwise a cache would miss on a difference that changes no glyph.

interface ShapingEnvironmentFingerprintInputs
MemberTypeSummary
directionTextDirection
fallbackOrderreadonly FontFingerprintInputs[]
featuresreadonly (readonly [string, number])[]
fixedPointScalenumber
fontFontFingerprintInputs
languagestring
normalizationNormalizationPolicy
roundingModeFixedPointRoundingMode
scriptstring
shapingLibraryVersionedShapingLibrary
unicodeDataVersionstring
variationAxesreadonly (readonly [string, number])[]

ShapingEnvironmentInputinterfaceSource ↗

Everything that determines how text shapes — the complete input to a [ShapingEnvironment](ShapingEnvironment).

Exhaustive on purpose. Any field that could change a glyph's position belongs here, because the environment's fingerprint is what decides whether a cached shaped run may be reused.

interface ShapingEnvironmentInput
MemberTypeSummary
directionTextDirection
fallbackOrderreadonly ResolvedFont[]
featuresReadonly<Record<string, number>>
fixedPointScalenumber
fontResolvedFont
languagestring
normalizationNormalizationPolicy
roundingModeFixedPointRoundingMode
scriptstring
shapingLibraryVersionedShapingLibrary
unicodeDataVersionstring
variationAxesReadonly<Record<string, number>>

SourceCropinterfaceSource ↗

a:srcRect — how much of each edge of the source image is cropped away, as fractions.

interface SourceCrop
MemberTypeSummary
bottomnumber
leftnumber
rightnumber
topnumber

SourceRangeinterfaceSource ↗

A half-open UTF-16 range inside one paragraph, addressed by its canonical node id.

interface SourceRange
MemberTypeSummary
endnumber
paragraphIdstring
startnumber

SpanLinkRecordinterfaceSource ↗

The hyperlink a span sits inside, as layout resolved it.

Already SANITIZED: href is the runtime projection produced once at the trust boundary, and null means the link is inert — a refused scheme, or a relationship the package does not declare. Paint, hit-testing and the popover consume this and never the authored target, so there is exactly one place a file-derived URL becomes something a browser can follow.

id is the w:hyperlink node's canonical id, which is what makes the spans of one link recognisable as one link across the several lines it wraps onto — and what an unlink or a retarget addresses.

interface SpanLinkRecord
MemberTypeSummary
anchor?stringBookmark name for an internal link, so navigation need not re-parse the fragment.
hrefstring | nullSanitized runtime projection: an absolute URL, `#anchor`, or null when inert.
idstring
kind'external' | 'internal' | 'unresolved'
tooltip?string`w:tooltip` — paint puts it on the anchor's `title`.

StoryDrawingContextinterfaceSource ↗

Location of one drawing within a recursively painted story graph.

interface StoryDrawingContext extends StoryParagraphFragmentContext
MemberTypeSummary
lineLineRecord | nullEnclosing line for an inline drawing; null for a story-level anchor.
paragraphParagraphFragmentRecord | nullEnclosing paragraph for an inline drawing; null for a story-level anchor.

StoryDrawingHostinterfaceSource ↗

The fragment-plus-anchored-drawings shape every laid-out story shares.

interface StoryDrawingHost
MemberTypeSummary
anchoredDrawings?readonly AnchoredDrawingRecord[]Story-level positioned drawings, when that story supports anchors.
fragmentsreadonly BlockFragmentRecord[]Root story fragments in their published reading order.

StoryParagraphFragmentContextinterfaceSource ↗

Location of one paragraph fragment within a recursively painted story graph.

interface StoryParagraphFragmentContext
MemberTypeSummary
storyOriginReadonly<{ x: number; y: number; }>Absolute origin of the immediate story containing this record.
textboxDepthnumberZero for the supplied story; increments for every anchored textbox boundary.
textboxOwnerAnchoredDrawingRecord | nullDrawing whose textbox directly owns this fragment, or null for the root story.
textboxPathreadonly AnchoredDrawingRecord[]Root-to-leaf owning drawings, empty for the supplied story.

StoryProjectionDependenciesinterfaceSource ↗

Paired projector/cache identities shared by browser, exporters, and future story hosts.

interface StoryProjectionDependencies
MemberTypeSummary
epochForPart(partName: string) => string
tokenForParagraphForPart(partName: string, paragraph: OoxmlNode) => string
tokenForTableForPart(partName: string, table: OoxmlNode) => stringMemoized aggregate for every paragraph in an immutable table subtree.

StyleCascadeTableinterfaceSource ↗

The whole styles part, indexed and ready to resolve against.

cacheToken is load-bearing: it folds into layout cache producers so breaks measured under one styles part are never reused under another.

interface StyleCascadeTable
MemberTypeSummary
cacheTokenstringBounded fingerprint folded into layout cache producers so a different styles part cannot reuse breaks measured under another cascade. Computed once per table (FNV-1a hex).
defaultCharacterStyleIdstring | null`w:style[@w:default='1'][@w:type='character']` — last wins among defaults of that type.
defaultParagraphStyleIdstring | null`w:style[@w:default='1'][@w:type='paragraph']` — last wins among defaults of that type.
defaultTableStyleIdstring | null`w:style[@w:default='1'][@w:type='table']` — last wins among defaults of that type.
docDefaultsParagraphreadonly OoxmlProperty[]
docDefaultsParagraphNodeOoxmlElement | undefined
docDefaultsRunreadonly OoxmlProperty[]
stylesReadonlyMap<string, StyleDefinition>
themeFontsThemeFontsThe theme part's typefaces, for `w:rFonts` theme references.
typography?CjkTypographySettings

StyleDefinitioninterfaceSource ↗

interface StyleDefinition
MemberTypeSummary
basedOnstring | null
conditionalTableFormatsReadonlyMap<string, OoxmlElement>
nextstring | null`w:next` — the authoring style for a following paragraph.
outlineLevelnumber | null
paragraphPropertiesreadonly OoxmlProperty[]
paragraphPropertiesNodeOoxmlElement | undefined
runPropertiesreadonly OoxmlProperty[]
styleIdstring
tablePropertiesNodeOoxmlElement | undefined
tableRowPropertiesNodeOoxmlElement | undefined
typestring

StyleSpanRecordinterfaceSource ↗

A run of text on one line sharing identical resolved formatting.

interface StyleSpanRecord
MemberTypeSummary
boxLayoutBox
caretEdges?readonly number[]Cumulative advances from [box](box).x to each UTF-16 caret boundary in [text](text).
changeSites?readonly RevisionAttribution[]The revisions a resolved view accepted into this text, which paints as ordinary text.
equation?EquationSpanRecordPaint-ready geometry for one atomic Office Math equation.
fieldAtom?FieldAtomMarkerPresent when this span is a field's displayed RESULT, for the shading Word draws under one.
fontSlot?FontSlotThe `w:rFonts` slot this span's text resolves its face through; absent means the base (ascii/hAnsi) slots. [style](style) stays the run's full resolution — with both `fontFamily` and `fontFamilyEastAsia` — so formatting readback and the format painter see the run as authored; measurement, paint and hit-testing resolve the effective face with `styleForFontSlot(span.style, span.fontSlot)`.
glyphOffsetPt?numberHorizontal ink displacement in points from box.x, before drawing the glyphs. CJK opening punctuation removes its left side bearing; its advance and caret boundaries remain box-based. Zero marks trailing-bearing compression with no ink displacement. Exporters must apply this offset to the ink origin.
lineEndWhitespace?trueAuthored trailing spaces that layout may clip at the line's right edge.
noteNav?{ readonly scopeId: string; readonly direction: 'to-note' | 'to-body'; }Footnote/endnote navigation metadata for projected note atoms.
projected?booleanLive PAGE/NUMPAGES/SECTIONPAGES projection (layout-time evaluated text).
propsreadonly OoxmlProperty[]The run's authored properties, retained as evidence.
rangeSourceRange
revisions?readonly RevisionAttribution[]The revision wrappers this text sits inside, outermost first, absent when untracked.
styleResolvedRunStyleThe same properties RESOLVED — one unit system, defaults applied.
tabLeader?TabLeader`w:tab/@w:leader` of the stop a `\t` span advanced to (ECMA-376 §17.3.1.38).
tabLeaderAdvancePt?numberAdvance of ONE leader glyph in this run's face, in points, measured by layout.
textstring
wrapAdvanceBefore?numberHorizontal jump, in points, that a floating object's wrap zone forced before this span.

TabDestinationinterfaceSource ↗

Where one tab character lands: the resolved x, and the stop that decided it.

interface TabDestination
MemberTypeSummary
alignmentTabAlignment
leader?TabLeaderLeader of the stop that was reached; absent for `none` and for default-interval tabs.
positionPtnumber

TableBorderBoxinterfaceSource ↗

A table's six authored border edges: four outer, plus the two interior intervals.

interface TableBorderBox
MemberTypeSummary
bottomTableBorderSide
insideHTableBorderSide
insideVTableBorderSide
leftTableBorderSide
rightTableBorderSide
topTableBorderSide

TableBorderStrokeRecordinterfaceSource ↗

One published stroke rectangle in cell-local layout points.

Paint multiplies x/y/width/height by scale and draws — no metrics, gaps, or corner math.

interface TableBorderStrokeRecord
MemberTypeSummary
colorstring | null
cssStyle'solid' | 'dashed' | 'dotted'CSS keyword for this stroke (compound strokes are always solid).
heightnumber
role'outer' | 'inner' | 'middle' | 'edge'
sideTableBorderSideName
widthnumber
xnumber
ynumber

TableCellAddressinterfaceSource ↗

The innermost table cell a point resolved through.

interface TableCellAddress
MemberTypeSummary
cellIdstringCanonical node id of the `w:tc`.
gridColumnnumber
gridSpannumber
rowIdstringCanonical node id of the `w:tr`.
rowIndexnumberOrdinal in the WHOLE table, stable across fragments and header repeats.
tableIdstringCanonical node id of the `w:tbl`.

TableCellContextinterfaceSource ↗

Where a paragraph sits in a table, if it sits in one.

interface TableCellContext
MemberTypeSummary
columnIndexnumber
columnsnumber
rowIndexnumber
rowsnumber
tableIdstring

TableCellFragmentRecordinterfaceSource ↗

One table cell on one page, already resolved against the grid.

gridSpan is clamped at read time, because it comes from a file and an unclamped span is a loop bound an attacker controls. A vertical-merge continuation paints its box but holds no blocks — its content belongs to the cell that started the merge.

interface TableCellFragmentRecord
MemberTypeSummary
blocksreadonly BlockFragmentRecord[]Nested blocks in reading order; recursion carries nested tables.
borders?ResolvedCellBordersLayout-owned resolved borders after collapsed conflict resolution.
boxLayoutBox
gridColumnnumberFirst grid column this cell occupies.
gridColumnId?stringCanonical `w:gridCol` node id for this cell's start column, when authored.
gridSpannumberGrid columns spanned, already clamped at read time.
idstringCanonical node id of the `w:tc`.
logicalGridColumn?numberStored grid index for an RTL cell; gridColumn indexes physical columnEdges.
paintInert?booleanWhen true, paint skips borders/fill/content for this cell (vMerge continue). Grid bookkeeping and the box remain so selection/geometry walks stay consistent.
rowSpan?numberNumber of rows this restart cell visually spans (1 when not a vertical merge).
shading?stringValidated 6-hex cell shading fill, absent for none/auto.
textDirection?'btLr'Bottom-to-top cell content uses a rotated local inline axis.
vMergeContinuebooleanA vertical-merge continuation paints its box but holds no blocks.

TableCellStyleFormattinginterfaceSource ↗

What a table style contributes to the paragraphs of ONE cell: the style's whole-table w:pPr/w:rPr followed by every w:tblStylePr the cell is under (17.7.6.6), weakest first in the caller's condition order (banding, column, row, corner).

This is how Word makes a header row bold and centred while the document states nothing but <w:tblStyle w:val="…"/> on the table and plain runs in the cells.

interface TableCellStyleFormatting
MemberTypeSummary
paragraphPropertiesreadonly OoxmlProperty[]
paragraphPropertyNodesreadonly OoxmlElement[]Matching `w:pPr` nodes, for nested `w:pBdr` / `w:tabs` resolution.
runPropertiesreadonly OoxmlProperty[]Inherited run properties for every run in the cell, before the paragraph style.

TableFragmentRecordinterfaceSource ↗

The part of one table that sits on one page.

A table that crosses a page boundary produces one fragment per page it spans, which is what lets it checkpoint like a paragraph: the flow loop places whole fragments, and resuming after a table needs no knowledge of its interior.

interface TableFragmentRecord
MemberTypeSummary
boxLayoutBox
columnEdgesreadonly number[]Resolved column boundary x positions in table-local points, left edge through right edge. Length is column count + 1.
floatingWrap?{ readonly anchorId: string; readonly columnIndex: number; readonly float: TableFloatPosition; readonly sourceOrder: number; }Source and positioning inputs needed to reconstruct wrapping on an incremental pass.
fragmentIndexnumber0 for the first page the table touches, 1 for its continuation, and so on.
idstring
kind'table'
nestingDepthnumberNesting depth: 0 for body-level tables, increasing for nested tables.
rowsreadonly TableRowFragmentRecord[]
tableIdstringCanonical node id of the `w:tbl`.

TableRowFragmentRecordinterfaceSource ↗

One table row on one page.

A FRAGMENT, not the row: a row split across a page break appears once per page it touches, and a repeated header row appears on every page of its table.

interface TableRowFragmentRecord
MemberTypeSummary
boxLayoutBox
cellsreadonly TableCellFragmentRecord[]
changeSites?readonly RevisionAttribution[]The row insertion a resolved view kept this row through, absent in All Markup (where [revisionKind](revisionKind) carries it) and for an untracked row. A removed row has no record.
idstringCanonical node id of the `w:tr`.
isContinuation?booleanTrue when this record continues a row that already emitted content on a prior page (cell content fragmented at a paragraph/line boundary). Same `id` as the lead fragment.
isHeaderRepeatbooleanTrue for a `w:tblHeader` row RE-EMITTED at the top of a continuation page. Painted, but excluded from interaction walks so each caret stop exists exactly once.
isHeaderRowbooleanTrue when the authored row resolves `w:tblHeader`, including its first occurrence.
revisionAuthor?string
revisionDate?string
revisionId?stringThe `w:trPr/w:ins|w:del` attribution — the `(id, author, date)` triple the review model addresses this decision by, so painted rows can carry it the way revision spans do.
revisionKind?'insert' | 'delete'Pending tracked row insertion/deletion, when authored in `w:trPr`.
rowIndexnumberAuthored row ordinal within the table; repeats share the original row's index.

TabStopinterfaceSource ↗

One authored w:tab: where it sits, how it aligns, and what fills the gap.

interface TabStop
MemberTypeSummary
alignmentTabAlignment
leader?TabLeaderAbsent for `none` — the schema default and the overwhelming majority of stops.
positionPtnumberPosition from the paragraph content origin, in points.

TextboxStoryLayoutinterfaceSource ↗

One text box's story laid out inside its extent, in content-box-relative coordinates.

Fragments origin at the content box's top-left; paint places the content box at drawing origin + contentOffset and clips to the extent.

interface TextboxStoryLayout
MemberTypeSummary
clippedResourceToken?stringResource identities of the drawings the clip DROPPED, in flow order.
contentHeightnumberContent box height (extent minus vertical insets).
contentOffsetReadonly<{ x: number; y: number; }>Offset of the content box inside the drawing extent: insets plus vertical anchoring.
contentWidthnumberContent box width (extent minus horizontal insets).
fallbackReason?TextboxStoryFallbackReasonTrue when layout hit a named bound and returned a truncated / empty story.
fillHexstring | nullSolid fill of the hosting shape, painted behind the story; null for no fill.
flowHeightnumberHeight the blocks flow to (points), before vertical anchoring.
fragmentsreadonly BlockFragmentRecord[]Content-box-relative fragments (origin at the content box's top-left).
strokeHexstring | nullSolid outline of the hosting shape; null for no outline.
strokeWidthPtnumberOutline width in points; 0 when absent.

TextMeasurerinterfaceSource ↗

Text measurement, injected.

A real implementation shapes with the resolved font; the tests supply a deterministic one. Layout never reads the DOM, so this is the only way width and height enter it.

interface TextMeasurer
MemberTypeSummary
caretAdvancesOptional whole-span logical caret advances, indexed by UTF-16 offset. Values are nondecreasing, start at zero, and end at the measured advance. Ligature interiors may share an edge. Undefined selects a bounded approximate fallback.
inkBoundsOptional conservative ink bounds for one grapheme, in points from its origin. Includes size and horizontal scale, but not trailing character spacing. Undefined keeps layout on the advance-only path.
lineMetricsLine height and baseline for the resolved style.
measureAdvance width of `text` in the resolved style.

TextShaperinterfaceSource ↗

The one thing layout needs from a shaping backend.

Injected rather than imported, which is what keeps layout DOM-free and testable: a fixed-metric shaper measures deterministically in a test, HarfBuzz measures for real in a browser, and layout cannot tell the difference.

interface TextShaper
MemberTypeSummary
shape

VectorShapeComponentinterfaceSource ↗

interface VectorShapeComponent
MemberTypeSummary
arrowheadsEmu?readonly (readonly Readonly<{ x: number; y: number; }>[])[]Filled line-end polygons in the same projected coordinate space.
fillAlphanumber
fillHexstring | null
strokeAlphanumber
strokeHexstring | null
strokeWidthEmunumber
subpathsClosed?readonly boolean[]Authored close commands; omitted by older consumers means closed polygons.
subpathsEmureadonly (readonly Readonly<{ x: number; y: number; }>[])[]

VectorShapeProjectioninterfaceSource ↗

The renderable subset of a wps:wsp non-picture graphic, or of one bounded wpg:wgp group of them: closed polygon subpaths (a:custGeom with move/line/close/cubicBezTo verbs, or a supported a:prstGeom) with a solid fill and/or stroke. The colour may come from a:srgbClr or from the theme, through a:schemeClr or a wps:style matrix reference. Anything richer (gradient and picture fills, text bodies, rotation, a nested group) projects as null and paints the labelled placeholder instead.

interface VectorShapeProjection
MemberTypeSummary
componentsreadonly VectorShapeComponent[]Independently styled paths, always non-empty. A direct shape has one component.
extentEmuReadonly<{ cx: number; cy: number; }>The drawing extent that frames the subpath coordinate space.
fillAlpha?number
fillHexstring | nullValidated 6-digit sRGB hex (no `#`) of the one component, or null. A group of two or more components has no single fill, so this is null there as well: null means "no one fill to name", not "nothing is filled". Read `components` to paint.
strokeAlpha?number
strokeHexstring | nullAs `fillHex`, for the stroke: the one component's stroke, else null.
strokeWidthEmunumberThe one component's stroke width in EMU; 0 when absent or when grouped.
subpathsEmureadonly (readonly Readonly<{ x: number; y: number; }>[])[]Every component's subpath polygons, flattened, in extent-EMU space; fill rule is even-odd. Painting reads `components`, which keeps each polygon with its own colours; this stays the geometry summary (bounds, hit tests, wrap holes).

VersionedShapingLibraryinterfaceSource ↗

The shaping library and its exact version.

Versioned because a library upgrade can change glyph positioning, and a cached measurement taken under the old one must not be reused under the new one.

interface VersionedShapingLibrary
MemberTypeSummary
namestring
versionstring

ViewportWindowinterfaceSource ↗

The visible band of the document, in layout units.

interface ViewportWindow
MemberTypeSummary
heightnumber
topnumberDistance from the top of the document to the top of the visible area, in layout units.

WordBoundaryinterfaceSource ↗

The replaceable word-segmentation strategy.

Falls back to a BOUNDED grapheme-safe splitter where Intl.Segmenter is absent — bounded because the input is file-derived, and grapheme-safe so a fallback never splits inside an emoji.

interface WordBoundary
MemberTypeSummary
segment

WordBoundaryResolverDepsinterfaceSource ↗

Injection points for [createDefaultWordBoundary](createDefaultWordBoundary), so tests can force either path.

interface WordBoundaryResolverDeps
MemberTypeSummary
createFallbackBoundary?() => WordBoundary
createIntlBoundary?() => WordBoundary
isIntlAvailable?() => boolean

WordSegmentinterfaceSource ↗

One word-segmentation span. wordLike separates words from the whitespace and punctuation between them, which is what double-click selection needs to skip.

interface WordSegment
MemberTypeSummary
utf16Fromnumber
utf16Tonumber
wordLikeboolean

Type aliases (67)

AnchoredDrawingLayoutFallbacktypeSource ↗

Named fallback when a positioning frame cannot be resolved (OpenSpec 4.6).

type AnchoredDrawingLayoutFallback = 'unresolvable-frame' | 'page-defer-exhausted';

AutonumFieldKindtypeSource ↗

type AutonumFieldKind = 'AUTONUM' | 'AUTONUMLGL' | 'AUTONUMOUT';

BlockFragmentRecordtypeSource ↗

A top-level (or cell-level) block fragment, discriminated by kind.

type BlockFragmentRecord = ParagraphFragmentRecord | TableFragmentRecord;

CacheLookuptypeSource ↗

A cache probe: the value and its provenance on a hit, or the reason it missed.

Misses are typed rather than merely absent, so a caller can tell a cold entry from one invalidated by a dependency change.

type CacheLookup<V> = {
    readonly hit: true;
    readonly value: V;
    readonly provenance: CacheProvenance;
} | CacheMiss;

CacheMisstypeSource ↗

Why a lookup missed — for cache-instrumentation assertions.

type CacheMiss = {
    readonly hit: false;
    readonly reason: 'absent';
} | {
    readonly hit: false;
    readonly reason: 'dependency-changed';
} | {
    readonly hit: false;
    readonly reason: 'input-changed';
} | {
    readonly hit: false;
    readonly reason: 'resource-changed';
    readonly resourceKey: string;
} | {
    readonly hit: false;
    readonly reason: 'epoch-changed';
    readonly epoch: keyof OperationSnapshot;
};

CellVerticalAligntypeSource ↗

w:vAlign — where a cell's content sits when the row is taller than the content.

type CellVerticalAlign = 'top' | 'center' | 'bottom';

ContentControlLeveltypeSource ↗

Where the control sits in the tree relative to its content.

type ContentControlLevel = 'block' | 'inline' | 'row' | 'cell';

ContentControlLocktypeSource ↗

Raw w:lock/@w:val on one control, or unlocked when absent / unrecognised.

Effective permissions across a nesting chain are the union of every ancestor's lock on two axes (content edit / removal); see [ContentControlBoundaryRecord.effectiveLock](ContentControlBoundaryRecord.effectiveLock).

type ContentControlLock = 'unlocked' | 'sdtLocked' | 'contentLocked' | 'sdtContentLocked';

ContentControlMappedTypetypeSource ↗

Mapped control type for layout / chrome — same members as the shipped public ContentControlType. Untyped and preserved-only kinds report as richText.

type ContentControlMappedType = 'richText' | 'plainText' | 'checkbox' | 'dropdown' | 'comboBox' | 'date' | 'picture' | 'buildingBlockGallery' | 'repeatingSection';

DrawingClipFallbacktypeSource ↗

type DrawingClipFallback = 'none' | 'unsupported-preset';

DrawingHorizontalReferenceFrametypeSource ↗

type DrawingHorizontalReferenceFrame = 'character' | 'column' | 'insideMargin' | 'leftMargin' | 'margin' | 'outsideMargin' | 'page' | 'rightMargin';

DrawingVerticalReferenceFrametypeSource ↗

type DrawingVerticalReferenceFrame = 'bottomMargin' | 'insideMargin' | 'line' | 'margin' | 'outsideMargin' | 'page' | 'paragraph' | 'topMargin';

EquationGeometrytypeSource ↗

type EquationGeometry = EquationTextGeometry | EquationRowGeometry | EquationFractionGeometry | EquationRadicalGeometry | EquationScriptGeometry | EquationNaryGeometry;

FieldLinkProjectortypeSource ↗

How layout turns a parsed HYPERLINK field instruction into the sanitized record spans carry.

Injected for the same reason as [HyperlinkProjector](HyperlinkProjector): the spec's raw target must cross the surface's ONE href trust boundary, and layout owns no sanitization policy. null means no link — the cached result still paints as plain text, which is the right degradation.

type FieldLinkProjector = (spec: HyperlinkFieldSpec) => SpanLinkRecord | null;

FixedPointtypeSource ↗

Fixed-point coordinates are safe integers in units declared by ShapingEnvironment.fixedPointScale.

type FixedPoint = number & {
    readonly [FIXED_POINT]: true;
};

FixedPointRoundingModetypeSource ↗

How fixed-point conversion breaks ties. Part of the shaping fingerprint.

type FixedPointRoundingMode = 'halfAwayFromZero' | 'halfToEven' | 'towardZero';

FontByteValidatortypeSource ↗

The injected check that bytes really are a font.

Injected because it is the shaper that knows — HarfBuzz can open a face and read its tables, and this layer must not duplicate that judgement. Every byte reaching it is file input.

type FontByteValidator = (bytes: Uint8Array, faceIndex: number) => FontValidationResult;

FontResolutionErrorCodetypeSource ↗

Why a face was not admitted.

forbidden and hashMismatch are adversarial signals rather than ordinary failures: the first is a face the host declared off-limits, the second is bytes that are not what their source claimed.

type FontResolutionErrorCode = 'missing' | 'forbidden' | 'overLimit' | 'malformed' | 'hashMismatch';

FontSlottypeSource ↗

Which w:rFonts slot a character resolves its face through.

OOXML gives a run up to four faces and picks between them by SCRIPT, so one run of mixed Latin and CJK text uses two different fonts without saying so anywhere in its properties.

type FontSlot = 'ascii' | 'hAnsi' | 'eastAsia' | 'cs';

FontValidationResulttypeSource ↗

Whether bytes parse as a usable font, with a diagnostic when they do not.

type FontValidationResult = {
    readonly valid: true;
} | {
    readonly valid: false;
    readonly diagnostic: string;
};

HarfBuzzShapingErrorCodetypeSource ↗

Why shaping refused.

Mostly RESOURCE limits, because every input here derives from a file: text length, codepoint count, glyph count and outline size are all attacker-influenced, and an unbounded shape call is a denial-of-service vector rather than a rendering bug.

type HarfBuzzShapingErrorCode = 'notInitialized' | 'wasmUnavailable' | 'unsupportedRuntime' | 'fontOverLimit' | 'malformedFont' | 'textOverLimit' | 'codepointsOverLimit' | 'glyphOverLimit' | 'outlineOverLimit' | 'shapedRunOverLimit' | 'unsupportedVariationAxes' | 'unsupportedFallback' | 'unsupportedColorFont' | 'unsupportedNormalization' | 'invalidBidiLevel' | 'shapingLibraryMismatch' | 'disposed';

HeaderFooterVariantNametypeSource ↗

Which header/footer variant a page shows (ECMA-376 §17.10.5).

type HeaderFooterVariantName = 'default' | 'first' | 'even';

HyperlinkProjectortypeSource ↗

How layout turns a typed w:hyperlink node into the sanitized record spans carry.

Injected rather than computed here because resolving r:id needs the PACKAGE's relationships and this module only ever sees one part's tree. null means the caller declined to project — the runs still measure and paint, they simply carry no link, which is the right degradation: text is never lost for want of a target.

type HyperlinkProjector = (link: OoxmlNode) => SpanLinkRecord | null;

ImageWrapTargettypeSource ↗

Nine Word wrap menu targets (inline plus eight floating modes).

type ImageWrapTarget = 'inline' | 'square' | 'squareLeft' | 'squareRight' | 'tight' | 'through' | 'topAndBottom' | 'behind' | 'inFront';

LayoutShapingEnvironmenttypeSource ↗

Fingerprinted, operation-wide portion of every shaping call.

type LayoutShapingEnvironment = Omit<ShapingEnvironmentInput, 'font' | 'direction' | 'fallbackOrder'>;

LineSpacingRuletypeSource ↗

Resolved line spacing (w:spacing/@line + @lineRule, ECMA-376 17.3.1.33).

auto is the interesting one: @line is 240ths of a line, so 240 is single, 360 is one-and-a-half, 480 is double — and Word's own Normal style since 2013 is 259, i.e. 1.08. A document laid out at a flat single spacing is ~8% tight on EVERY line, which moves every page break, so this is not a cosmetic detail.

exact fixes the line box at @line twips and lets tall glyphs clip, the way Word does. atLeast uses it as a floor.

type LineSpacingRule = 'auto' | 'exact' | 'atLeast';

ListMarkerAligntypeSource ↗

w:lvlJc — how a list marker aligns within its own indent.

type ListMarkerAlign = 'left' | 'center' | 'right';

ListSuffixtypeSource ↗

w:suff — what separates a list marker from the text after it.

type ListSuffix = 'tab' | 'space' | 'nothing';

One caret movement, in Word's own vocabulary.

Visual rather than logical where the two differ: left means left on screen, which in right-to-left text is forward through the string.

type NavigationCommand = 'left' | 'right' | 'up' | 'down' | 'wordLeft' | 'wordRight' | 'lineStart' | 'lineEnd' | 'documentStart' | 'documentEnd' | 'pageUp' | 'pageDown';

NormalizationPolicytypeSource ↗

Which Unicode normalization is applied before shaping, if any.

type NormalizationPolicy = 'none' | 'NFC' | 'NFD' | 'NFKC' | 'NFKD';

NoteLayoutFallbackReasontypeSource ↗

Why note layout stopped short and fell back.

Every one is a BOUND rather than a bug: note counts, fragment counts and heights all come from a file, and a document can ask for more note area than a page has. Falling back with a reason keeps the document open instead of failing to lay out.

type NoteLayoutFallbackReason = 'note-count-limit' | 'note-fragment-limit' | 'note-reflow-exhausted' | 'note-height-cap'
/** Authored separator/continuationSeparator taller than the content column. */
 | 'note-separator-height-cap' | 'missing-note-body' | 'dangling-note-reference';

NotePaginationFallbackReasontypeSource ↗

Why note PAGINATION fell back, widening [NoteLayoutFallbackReason](NoteLayoutFallbackReason) with the reasons that only arise while distributing notes across pages.

type NotePaginationFallbackReason = NoteLayoutFallbackReason | 'note-reflow-exhausted' | 'note-area-fragment-limit' | 'note-overflow-page-limit'
/**
 * Overflow/drain iteration placed zero note stories while carry/pending remained —
 * abort rather than minting blank separator-only sheets up to the page budget.
 */
 | 'note-overflow-stalled'
/** A single note line exceeds the full content column; content is not placed overflowing. */
 | 'note-line-exceeds-page';

NoteSeparatorRuleStyletypeSource ↗

Paint style for Word-default / marker-only separator rules (not CSS inventing content).

type NoteSeparatorRuleStyle = 'single' | 'double';

OperationSnapshotFieldtypeSource ↗

Which field of an [OperationSnapshot](OperationSnapshot) changed.

type OperationSnapshotField = keyof OperationSnapshot;

OperationSnapshotGuardtypeSource ↗

Whether the environment is still the one an in-flight operation started under.

restart names the fields that moved. A long layout pass whose fonts or configuration change midway must restart rather than finish against a mixture of both.

type OperationSnapshotGuard = {
    readonly status: 'current';
} | {
    readonly status: 'restart';
    readonly changed: readonly OperationSnapshotField[];
};

PageBorderDisplaytypeSource ↗

w:display (ST_PgBorderDisplay) — which pages of the section carry the frame.

type PageBorderDisplay = 'allPages' | 'firstPage' | 'notFirstPage';

PageBorderOffsetFromtypeSource ↗

w:offsetFrom (ST_PgBorderOffset) — what w:space on each edge is measured from.

The schema default is text, NOT page. Word's own UI opens on "Edge of page", which is why the wrong default is easy to assume and expensive to hold: at text the rule sits w:space points outside the TEXT, so its distance from the sheet edge is the margin minus the space — a number that moves whenever the margins do.

type PageBorderOffsetFrom = 'page' | 'text';

PageBorderSidetypeSource ↗

Which of the four page-frame edges.

type PageBorderSide = (typeof PAGE_BORDER_SIDES)[number];

PageBorderZOrdertypeSource ↗

w:zOrder (ST_PgBorderZOrder) — whether the frame paints over the text or under it.

type PageBorderZOrder = 'front' | 'back';

PageRefCalibrationCelltypeSource ↗

Sticky calibration identity for one PAGEREF field.

An opaque frozen object rather than a mutable verdict holder because span markers are serialized into fragment signatures — a verdict written into the marker would move a signature that no painted output moved. The verdict itself lives beside the finalize pass (field-page-furniture.ts), keyed weakly on this object; the registry below carries the object across passes the same way REF verdicts are carried.

type PageRefCalibrationCell = Readonly<Record<never, never>>;

PageRefIndextypeSource ↗

Paragraph-id → refs index for linear [filterRefsOnPage](filterRefsOnPage) over a layout pass.

type PageRefIndex = ReadonlyMap<string, readonly PageRefHit[]>;

ParagraphBorderSidetypeSource ↗

Which of the six CT_PBdr edges.

Four are physical box edges; between and bar are group-relative, drawn only where consecutive paragraphs share a border definition.

type ParagraphBorderSide = (typeof PARAGRAPH_BORDER_SIDES)[number];

PreferredWidthTypetypeSource ↗

w:tblW / w:tcW / w:wBefore (CT_TblWidth, 17.4.63 / 17.4.71 / 17.4.86): a PREFERRED width plus the unit it is stated in. Preferred is the operative word — it is what the producer asked for, not what the table resolved to.

pct is stated in fiftieths of a percent (5000 = 100%) by Word, and in the "50%" string form of ST_Percentage by others; both are read. auto and nil carry no width.

type PreferredWidthType = 'dxa' | 'pct' | 'auto' | 'nil';

ReviewItemtypeSource ↗

One pending decision in the review queue: a tracked change, a comment thread, or a pro custom-node card. Discriminate on kind.

The store's own derivation (collectReviewItems) only ever produces the first two; the kind: 'custom' card is contributed by the pro review module, which recognizes the node.

type ReviewItem = ReviewRevisionItem | ReviewCommentItem | ReviewCustomItem;

ReviewRevisionKindtypeSource ↗

What kind of decision a revision card represents.

Wider than the four content wrappers, because a reviewer has to be shown every pending decision, including the ones that decorate no characters. A card the surface cannot show is a change the reviewer never learns about — and acceptAllRevisions refuses if ANY revision in the document is one the engine cannot resolve, so an invisible one makes Accept All fail for a reason nothing on screen explains.

type ReviewRevisionKind = 'insert' | 'delete'
/**
 * A deletion and an insertion that are one edit: text typed over a selection.
 *
 * Word shows these as a single `Replaced "x" with "y"` card, and resolving one half
 * without the other is never what the reviewer meant — accepting the deletion alone
 * leaves the replacement text unproposed, rejecting it alone leaves both.
 */
 | 'replace' | 'moveFrom' | 'moveTo'
/** `w:rPrChange` / `w:pPrChange` — the words are unchanged, their formatting is not. */
 | 'format'
/** `w:pPr/w:rPr/w:ins|w:del` — a paragraph split or merge. */
 | 'paragraphMark'
/** A row, cell, section or grid revision. Supported row revisions are resolvable. */
 | 'structural';

RevisionDisplayModetypeSource ↗

Which revisions layout resolves before producing pages.

- all-markup shows both halves of every change. - proposed shows what the document becomes if every change is accepted. - original shows what it was before any of them.

The last two are specified as equal to accept-all and reject-all OUTPUT, which is what makes them testable, without either applying an op.

type RevisionDisplayMode = 'all-markup' | 'proposed' | 'original';

RevisionKindtypeSource ↗

What a revision wrapper asserts about the content inside it.

moveFrom / moveTo are deliberately distinct from delete / insert: a move is one decision with two halves, and presenting it as an unrelated deletion and insertion invites resolving one without the other, which duplicates or loses the content.

type RevisionKind = 'insert' | 'delete' | 'moveFrom' | 'moveTo' | 'format';

SectionBreakTypetypeSource ↗

How this section is placed relative to the previous one (ECMA-376 17.6.22, ST_SectionMark).

All five schema values are read. nextColumn paginates like nextPage for now: in a single-column section that IS Word's behaviour, and multi-column flow is not modelled, so collapsing it at the parse boundary would only hide the authored value from a consumer that asks.

type SectionBreakType = 'nextPage' | 'continuous' | 'evenPage' | 'oddPage' | 'nextColumn';

SemanticArtifactRootStoryKindtypeSource ↗

Published root story containing an artifact occurrence.

type SemanticArtifactRootStoryKind = 'body' | 'header' | 'footer' | 'footnote' | 'endnote' | 'note-separator';

SemanticArtifactStoryKindtypeSource ↗

Exact story in which a review artifact's source anchor was laid out.

type SemanticArtifactStoryKind = SemanticArtifactRootStoryKind | 'textbox';

SemanticDrawingLayertypeSource ↗

Drawing layer relative to its owning story's text.

type SemanticDrawingLayer = 'behind-text' | 'inline' | 'in-front-of-text';

SemanticReviewArtifactRecordtypeSource ↗

Exporter-neutral review artifact normalized by core.

type SemanticReviewArtifactRecord = SemanticTrackedChangeArtifactRecord | SemanticCommentArtifactRecord;

SemanticRootStoryKindtypeSource ↗

Root story kinds published directly from one page record.

type SemanticRootStoryKind = 'body' | 'header' | 'footer' | 'footnote' | 'endnote' | 'note-separator';

SemanticStoryKindtypeSource ↗

Story containing a visited semantic record.

type SemanticStoryKind = SemanticRootStoryKind | 'textbox';

SemanticStoryVisittypeSource ↗

One root story in the engine's complete published page/story order.

The story discriminant preserves the precise published host type so exporters can consume furniture and note metadata without casting or searching the page graph a second time.

type SemanticStoryVisit = {
    readonly page: PageRecord;
    readonly story: 'body';
    readonly host: PageRecord;
    readonly box: LayoutBox;
    readonly origin: Readonly<{
        x: number;
        y: number;
    }>;
    readonly noteScopeId: null;
    readonly noteAreaKind: null;
} | {
    readonly page: PageRecord;
    readonly story: 'header' | 'footer';
    readonly host: HeaderFooterStoryRecord;
    readonly box: LayoutBox;
    readonly origin: Readonly<{
        x: number;
        y: number;
    }>;
    readonly noteScopeId: null;
    readonly noteAreaKind: null;
} | {
    readonly page: PageRecord;
    readonly story: 'footnote' | 'endnote';
    readonly host: NoteStoryRecord;
    readonly box: LayoutBox;
    readonly origin: Readonly<{
        x: number;
        y: number;
    }>;
    readonly noteScopeId: string;
    readonly noteAreaKind: NoteAreaRecord['kind'];
} | {
    readonly page: PageRecord;
    readonly story: 'note-separator';
    readonly host: NonNullable<NoteAreaRecord['separator']>;
    readonly box: LayoutBox;
    readonly origin: Readonly<{
        x: number;
        y: number;
    }>;
    readonly noteScopeId: null;
    readonly noteAreaKind: NoteAreaRecord['kind'];
};

TabAlignmenttypeSource ↗

How a tab stop positions the text that follows it.

Only left is a plain cursor jump. The other three size the tab glyph from the MEASURED following segment, so its end, centre or decimal point lands on the stop.

type TabAlignment = 'left' | 'center' | 'right' | 'decimal';

TabLeadertypeSource ↗

w:tab/@w:leader (ECMA-376 §17.3.1.38, ST_TabTlc): the character repeated across the space a tab reserves. none is the default and is represented by an absent leader.

This is the difference between a Word table of contents and a column of headings floating next to a column of page numbers, so it is carried through layout to paint rather than dropped as a geometry-irrelevant attribute.

type TabLeader = 'dot' | 'hyphen' | 'underscore' | 'heavy' | 'middleDot';

TableAlignmenttypeSource ↗

w:tblPr/w:jc (17.4.29, ST_JcTable): where the table sits within the text column.

type TableAlignment = 'left' | 'center' | 'right';

TableBorderSidetypeSource ↗

One border edge in one of three states.

omitted and none are NOT the same: an omitted edge inherits from the table style or the neighbouring cell, while an explicit none wins the conflict and draws nothing. Collapsing them would let a style's border reappear where the author removed it.

type TableBorderSide = {
    readonly state: 'omitted';
} | {
    readonly state: 'none';
} | {
    readonly state: 'edge';
    readonly style: TableBorderStyle;
    readonly color: string | null;
    readonly widthPt: number;
};

TableBorderSideNametypeSource ↗

Which physical edge of a box a border sits on.

type TableBorderSideName = 'top' | 'right' | 'bottom' | 'left';

TableBorderStyletypeSource ↗

One of the border line styles this engine draws.

An ALLOWLIST, not the full ST_Border enumeration: a file may name any of the seventy-odd OOXML border styles, and anything outside this set falls back rather than being passed through to paint.

type TableBorderStyle = (typeof TABLE_BORDER_STYLES)[number];

TablePaginationErrorCodetypeSource ↗

Why a table could not be paginated as authored.

Each is a bound: a row taller than a page, a row that cannot be split, or a row producing more fragments than the limit allows.

type TablePaginationErrorCode = 'table-row-overheight' | 'table-row-split-unsupported' | 'table-row-fragment-limit';

TableRowHeighttypeSource ↗

w:trHeight — a row's height rule and its value.

auto carries no value at all, which is why this is a union rather than a rule plus an optional number.

type TableRowHeight = {
    readonly rule: 'auto';
} | {
    readonly rule: 'atLeast' | 'exact';
    readonly valuePt: number;
};

TableRowHeightRuletypeSource ↗

w:trPr/w:trHeight (17.4.81) resolved for layout. Points leave the reader already — twips convert once here, matching every other table geometry boundary.

Word quirk (matches Form025U and Word's UI export): a present @w:val with an omitted @w:hRule is treated as atLeast, not ECMA's auto. Explicit auto still ignores val.

type TableRowHeightRule = 'auto' | 'atLeast' | 'exact';

TextboxStoryFallbackReasontypeSource ↗

Why textbox story layout stopped short.

Every one is a BOUND rather than a bug: nesting depth, fragment counts and the extent all come from a file. Falling back with a reason keeps the drawing rendered (clipped) instead of failing the layout pass.

type TextboxStoryFallbackReason = 'textbox-nesting-limit' | 'textbox-fragment-limit'
/** Flowed content is taller than the extent; trailing fragments were dropped. */
 | 'textbox-height-clip';

TextDirectiontypeSource ↗

Which way a run reads. The parity projection of its bidi embedding level.

type TextDirection = 'ltr' | 'rtl';

VerticalAligntypeSource ↗

w:vertAlign — script position, which also scales the run's effective size.

type VerticalAlign = 'baseline' | 'superscript' | 'subscript';

Variables (53)

AUTO_PARAGRAPH_SPACING_PTconstSource ↗

The gap Word substitutes when w:beforeAutospacing / w:afterAutospacing is on (ECMA-376 §17.3.1.33, the w:spacing clause both attributes belong to).

The attribute means "the consumer decides", and the authored @before / @after beside it is IGNORED rather than used as the value. Word's answer is HTML's default <p> margin, 14pt, which is what a document round-tripped through Word's HTML filter carries — and this one is everywhere, because Word writes w:before="100" w:beforeAutospacing="1" for it. Reading only the literal 100 twips lays every such paragraph out 9pt tight, which moves page breaks.

AUTO_PARAGRAPH_SPACING_PT = 14

AUTO_PREFERRED_WIDTHconstSource ↗

The frozen "no preferred width" value — what a table or cell that declares none resolves to.

AUTO_PREFERRED_WIDTH: PreferredWidth

boundedStructuralFontValidatorconstSource ↗

Bounded minimum sfnt/TTC check; Task 4 supplies full parser-backed validation.

boundedStructuralFontValidator: FontByteValidator

CELL_PADconstSource ↗

The uniform 3 pt (60 twip) inset this lane used to apply on every side.

Word's defaults are not uniform — see [DEFAULT_CELL_MARGINS](DEFAULT_CELL_MARGINS) — so nothing resolves against this any more. Kept because it is published.

CELL_PAD = 3

COMPOUND_BORDER_MIN_GAP_PTconstSource ↗

Minimum gap between compound strokes, in points.

COMPOUND_BORDER_MIN_GAP_PT = 1

COMPOUND_BORDER_MIN_STROKE_PTconstSource ↗

Minimum stroke width for a compound (double/triple) band, in points.

COMPOUND_BORDER_MIN_STROKE_PT = 1

DEFAULT_CANVAS_FONT_STACKconstSource ↗

The stack used when a run names no font (or names one the sink refuses).

Paint only sets font-family when w:rFonts supplies a validated name, so an unstyled run inherits the surrounding face. Measuring one stack and painting another drifts every advance; this is the Word-like Latin fallback the canvas path measures against.

DEFAULT_CANVAS_FONT_STACK = "Calibri, Carlito, Helvetica, Arial, sans-serif"

DEFAULT_CELL_MARGINSconstSource ↗

Word's own default cell padding, for a document whose styles part states none.

0 top, 0 bottom, 108 twips left and right — the values TableNormal carries. A uniform 3 pt on all four sides made every row of every table that authored no w:tblCellMar 6 pt taller than Word's, and that error compounds down a table until it paginates a page early. A document that DOES ship a default table style resolves against that instead; this is the floor beneath it.

DEFAULT_CELL_MARGINS: CellMarginsPt

DEFAULT_PAGE_GEOMETRYconstSource ↗

US Letter with one-inch margins, in points.

DEFAULT_PAGE_GEOMETRY: PageGeometry

DEFAULT_REVISION_DISPLAY_MODEconstSource ↗

How a document renders tracked changes when nothing says otherwise.

all-markup matches Word's own default: a reader who opens a document with pending changes sees them, rather than a clean-looking document hiding edits nobody has accepted.

DEFAULT_REVISION_DISPLAY_MODE: RevisionDisplayMode

DEFAULT_RUN_STYLEconstSource ↗

The style a run inherits when it authors nothing.

DEFAULT_RUN_STYLE: ResolvedRunStyle

DEFAULT_SECTION_PROPERTIESconstSource ↗

US Letter, portrait, one-inch margins: Word's own default when a section says nothing.

DEFAULT_SECTION_PROPERTIES: SectionProperties

DEFAULT_TAB_INTERVAL_PTconstSource ↗

The default tab interval in points — [DEFAULT_TAB_INTERVAL_TWIPS](DEFAULT_TAB_INTERVAL_TWIPS) converted.

DEFAULT_TAB_INTERVAL_PT: number

DEFAULT_TAB_INTERVAL_TWIPSconstSource ↗

OOXML / Word default when w:settings/w:defaultTabStop is absent: 720 twips = 0.5".

DEFAULT_TAB_INTERVAL_TWIPS = 720

DEFAULT_VERTICAL_WEIGHTconstSource ↗

How much more a point of vertical distance counts than a point of horizontal distance.

Without it, clicking far out in the right margin beside a two-word line picks whichever block happens to be directly below, because that block is horizontally nearer. Weighting the vertical axis makes "the line I am level with" win, which is what the pointer meant.

DEFAULT_VERTICAL_WEIGHT = 8

EMPTY_NUMBERING_INDEXconstSource ↗

Empty index for tests / documents without numbering.

EMPTY_NUMBERING_INDEX: NumberingIndex

EMPTY_TAB_STOPSconstSource ↗

The frozen "no custom stops" value, so a paragraph without tabs mints no object.

EMPTY_TAB_STOPS: ResolvedTabStops

GRAPHEME_SEGMENTER_LOCALEconstSource ↗

Invariant locale for deterministic cross-runtime grapheme boundaries.

GRAPHEME_SEGMENTER_LOCALE: "und"

HARD_MAX_AGGREGATE_FONT_BYTESconstSource ↗

Most bytes all admitted faces may total, whatever a caller configures.

HARD_MAX_AGGREGATE_FONT_BYTES: number

HARD_MAX_FONT_BYTESconstSource ↗

Largest single face this engine will ever admit, whatever a caller configures.

A CEILING, not a default: a host may set a smaller maxFontBytes, but nothing can raise it past this. Font bytes come from files, and an unbounded face is a memory-exhaustion vector.

HARD_MAX_FONT_BYTES: number

HARD_MAX_FONT_SOURCESconstSource ↗

Most faces one snapshot may hold, whatever a caller configures.

HARD_MAX_FONT_SOURCES = 256

HARFBUZZ_SHAPING_LIBRARYconstSource ↗

The exact HarfBuzz build this engine shapes against.

Pinned and verified at load: a runtime reporting a different version is REFUSED rather than used, because glyph positioning can change between releases and a cached measurement taken under one build must not be trusted under another.

HARFBUZZ_SHAPING_LIBRARY: VersionedShapingLibrary

harfBuzzFontValidatorconstSource ↗

Structural sfnt validation that does not construct native HarfBuzz objects.

harfBuzzFontValidator: FontByteValidator

intlGraphemeBoundaryconstSource ↗

The default boundary, over Intl.Segmenter at the invariant und locale.

Locale-invariant on purpose: grapheme boundaries must not vary with the user's locale, or the same document would paginate differently for different readers.

intlGraphemeBoundary: GraphemeBoundary

MAX_BORDER_SPACE_PTconstSource ↗

Soft ceiling on border-to-text gap (w:space, already in points).

MAX_BORDER_SPACE_PT = 3168

MAX_BORDER_WIDTH_PTconstSource ↗

Soft ceiling on border width (96 eighths = 12pt). Word's UI tops out well below this.

MAX_BORDER_WIDTH_PT = 12

MAX_DOCUMENT_SECTIONSconstSource ↗

Hard ceiling on sections enumerated from a document (matches write-path MAX_SECTIONS in note/hf lifecycle). Hostile packages with unbounded w:sectPr marks fail closed here rather than amplifying layout props arrays.

MAX_DOCUMENT_SECTIONS = 4096

MAX_EACH_PAGE_MARK_CANDIDATESconstSource ↗

Cap on synthetic eachPage mark candidates measured per section (plus actual marks).

eachPage sequences restart every page, so a page almost never carries more than a handful of auto-numbered notes. Measuring numStart .. numStart + N - 1 covers single→double digit decimal growth and typical roman width peaks (e.g. viii vs ix) without scanning hostile numStart ranges unboundedly. Derived marks already assigned for the pass are always included in addition to this window.

MAX_EACH_PAGE_MARK_CANDIDATES = 12

MAX_LVL_OVERRIDESconstSource ↗

Soft ceiling on override entries per w:num.

MAX_LVL_OVERRIDES = 9

MAX_LVL_TEXT_LENGTHconstSource ↗

Soft ceiling on authored w:lvlText before expansion.

MAX_LVL_TEXT_LENGTH = 64

MAX_MARKER_TEXT_LENGTHconstSource ↗

Soft ceiling on an expanded marker string (codepoints).

MAX_MARKER_TEXT_LENGTH = 64

MAX_NOTE_FRAGMENTSconstSource ↗

Hard ceiling on fragments emitted for one note (split / continuation).

MAX_NOTE_FRAGMENTS = 512

MAX_NOTE_OVERFLOW_PAGESconstSource ↗

Cap on empty pages created solely to drain footnote/endnote overflow.

MAX_NOTE_OVERFLOW_PAGES = 256

MAX_NOTE_REFLOW_ATTEMPTSconstSource ↗

Bound on reflow attempts for an UNSEEDED document layout pass (cold open).

Sized for a cold open of a reference-dense document: adoption is a forward fixed-point iteration whose settled prefix extends a few pages per round, so a legal document with a hundred footnotes converges in tens of rounds (a 53-page/108-note fixture took 24). Orbits exit earlier through the fingerprint/envelope checks below, so the cap is a safety bound, not the expected cost.

MAX_NOTE_REFLOW_ATTEMPTS = 64

MAX_NOTES_LAID_OUTconstSource ↗

Hard ceiling on notes laid out in one pass (fail closed beyond).

MAX_NOTES_LAID_OUT = 10000

MAX_NUMBERING_DEFINITIONSconstSource ↗

Soft ceiling on abstractNum / num entries read from one part.

MAX_NUMBERING_DEFINITIONS = 512

MAX_PARAGRAPH_SPACING_PTconstSource ↗

Soft ceiling matching the spike's resolved-style limit (31_680 twips ≈ 22"). Beyond that an attacker-authored spacing would push pagination into pathological page counts.

MAX_PARAGRAPH_SPACING_PT: number

MAX_SDT_NESTINGconstSource ↗

Nested content-control wrappers deeper than this stop flattening; content stays preserved.

MAX_CONTENT_CONTROL_NESTING = 32

MAX_STYLE_BASED_ON_DEPTHconstSource ↗

Soft ceiling on basedOn chain length — enough for real templates, refuses hostile graphs.

MAX_STYLE_BASED_ON_DEPTH = 32

MAX_STYLE_DEFINITIONSconstSource ↗

Soft ceiling on style definitions read from one styles part.

MAX_STYLE_DEFINITIONS = 4096

MAX_TAB_POSITION_TWIPSconstSource ↗

Soft ceiling on a tab position (31_680 twips ≈ 22"), matching paragraph-spacing bounds so a hostile stop cannot shove layout into pathological widths.

MAX_TAB_POSITION_TWIPS = 31680

MAX_TAB_STOPSconstSource ↗

Soft ceiling matching Word's practical custom-tab UI limit.

MAX_TAB_STOPS = 64

MAX_TABLE_BORDER_STROKESconstSource ↗

Soft cap on published stroke rectangles per cell (security / pathological spans).

MAX_TABLE_BORDER_STROKES = 256

MAX_TABLE_COLUMNSconstSource ↗

Far above anything Word authors (its UI caps at 63) while keeping allocation bounded.

MAX_TABLE_COLUMNS = 1024

MAX_TABLE_NESTINGconstSource ↗

Layout-time nesting ceiling. Parse-time depth (MAX_DEPTH = 256 XML levels) alone still admits ~80 levels of w:tbl recursion into the layout walk; deeper tables render as an empty cell box rather than recursing.

MAX_TABLE_NESTING = 16

MAX_TABLE_ROW_FRAGMENTSconstSource ↗

Soft ceiling on fragments emitted for one authored row (hostile / runaway splits).

MAX_TABLE_ROW_FRAGMENTS = 4096

MAX_TABLE_ROW_HEIGHT_PTconstSource ↗

Soft ceiling on an authored w:trHeight (~22"). Hostile w:val otherwise becomes a multi-page row that every pagination preflight and cell box inherits.

MAX_TABLE_ROW_HEIGHT_PT: number

PAGE_BORDER_SIDESconstSource ↗

The four physical sides of CT_PageBorders.

Four, not the six of w:pBdr: w:between and w:bar are paragraph-group rules and the page has no analogue for either.

PAGE_BORDER_SIDES: readonly ["top", "left", "bottom", "right"]

PARAGRAPH_BORDER_SIDESconstSource ↗

The six CT_PBdr children, in schema order (ECMA-376 §17.3.1.24).

PARAGRAPH_BORDER_SIDES: readonly ["top", "left", "bottom", "right", "between", "bar"]

SINGLE_LINE_SPACINGconstSource ↗

Single spacing: what a paragraph that says nothing gets.

SINGLE_LINE_SPACING: ParagraphLineSpacing

TAB_LEADER_GLYPHconstSource ↗

The character each leader repeats (§17.3.1.38, ST_TabTlc).

Lives with the type rather than with the painter because LAYOUT has to measure it: a leader is the same character typed over and over, and the only way to space it the way typing it would is to ask the measurer how wide it actually is.

TAB_LEADER_GLYPH: ReadonlyMap<TabLeader, string>

W15_NAMESPACE_URIconstSource ↗

The w15 namespace: commentsExtended.xml — thread parent and resolved state.

W15_NAMESPACE_URI = "http://schemas.microsoft.com/office/word/2012/wordml"

WORD_SEGMENTER_LOCALEconstSource ↗

Invariant locale for deterministic cross-runtime word boundaries.

WORD_SEGMENTER_LOCALE: "und"

On this page

FunctionsactiveReviewItemanchorLineYappliedSpaceBeforeapplyLineSpacingattachNotesToLayoutbaselineShiftPtOfborderExtentPtborderWeightbottomBorderExtentPtboundedFallbackWordSegmentsbuildNumberingIndexbuildPageRefIndexbuildStyleCascadeTablecaptureOperationSnapshotcaretAtcaretBoxOnLinecaretStopscaretStopsForBlockscascadedBottomBordercascadedParagraphBorderscascadedTabStopscascadeParagraphFormattingcascadeRunPropertiescellSelectionBetweencellSelectionRectscellSelectionTextclampListValuecollapsedSpaceBeforecollectFlowBlockscommentBodyTextcommentInitialscompositionAnchorcomputeDoubleBorderMetricsPtcomputeFootnoteReservescontentControlAtPointcontentControlAtSemanticcontentControlBoundariescontentControlContentChildrencontentControlHoldingParagraphcontentControlRecordsInPartcontentControlsInLayoutcontentControlsOfLayoutcreateBoundedFallbackWordBoundarycreateDefaultWordBoundarycreateDocumentFurnitureSourcecreateDocumentLinkProjectorscreateDocumentNotesInputcreateDocumentStyleDependenciescreateFieldLinkRegistrycreateFixedMeasurercreateFontResourceSnapshotcreateHarfBuzzTextShapercreateIntlWordBoundarycreateLayoutSchedulercreateLayoutSessioncreateLayoutShapedMeasurercreateLayoutShapingcreateListCounterStatecreateParagraphLayoutCachecreateShapedMeasurercreateShapedMeasurercreateShapedRuncreateShapingEnvironmentdefaultNoteSeparatorRuleStyledefaultTabIntervalFromSettingsdeletedTextBoundariesderiveNoteDisplayMarksderiveNoteDisplayMarksResolveddisplayTextdisposeLayoutShapingdocumentOrderdocumentRelationshipTargetIneffectiveBorderSideeffectiveContentControlLockemptyTocPlaceholderParagraphIdsemptyTocSuppressedResultParagraphIdsenumerateDocumentSectionsenumerateDocumentSectionsBoundedeveryStoryOrderexpandLvlTextexportSourceRangeOffilterRefsOnPagefindDrawingOverlayFrameInLayoutfindSeparatorNotefirstReviewRangefixedPointfontRequestKeyforEachSemanticDrawingforEachSemanticSpanforEachSemanticStoryforEachStoryParagraphFragmentformatDecimalformatDecimalZeroformatLowerLetterformatLowerRomanformatNumFmtformatPageNumberformatRevisionOfformatUpperLetterformatUpperRomanfragmentOwnsAtomOffsetfragmentsOfParagraphgeometryOfSectiongraphemeBoundaryEpochgraphemeCountgraphemeOffsetToUtf16guardOperationSnapshothitTestPagehitTestSemantichitTestSheetinitializeHarfBuzzisCanvasMeasurementAvailableisContentControlisContentControlContentisCumulativeGeometryTrustedFromLineOriginisFurniturePointisGeometryTrustedCaretOffsetisHarfBuzzInitializedisIntlSegmenterAvailableisIntlWordSegmenterAvailableisMarkerOnlySeparatorNoteisValidStyleIdisWholeGraphemeHorizontalBoundaryitemizeScriptFontSlotskeyedRangeRectslayoutEquationlayoutFontConfigurationFingerprintlayoutHeaderFooterStorylayoutNoteByIdlayoutNoteSeparatorlayoutNoteStorylayoutSemanticDocumentlineAtPositionlineEndOffsetlineSegmentslinesOflistMarkerBoxmarkRevisionRemovesMarkmeasureDisplayTextmergeListIndentmoveCaretnextTabDestinationnormalNotesOfnoteDisplayMarkMapnoteLineIdPrefixnoteMarkKeynoteSeparatorAreaBoxnoteStoryBlockspageAtYpageBorderFramepageBordersFingerprintpageRefPageNumbersFromLayoutpagesToMaterializeparagraphBorderExtentPtparagraphBordersparagraphBordersFingerprintparagraphBorderStrokeWidthPtparagraphBreaksBeforeparagraphContextualSpacingparagraphFragmentsOfparagraphFragmentsOfBlocksparagraphLayoutKeyparagraphLineSpacingparagraphMarkDeletedparagraphMarkFormatRevisionOfparagraphMarkRevisionOfparagraphMarkRevisionsOfparagraphOrderOfPartparagraphSectionNodeparagraphShadingparagraphShadingBoxparagraphsInCellsparagraphSpacingparagraphTabStopsparagraphTextFromLayoutparseAutonumInstructionparsePageBordersparsePageNumberingparseRefInstructionparseSectionPropertiesplanRefFieldResultRefreshpositionPastDeletionprepareLayoutFontConfigurationprojectedNoteMarkTextprojectedSectionSourceIndexesprovisionalNoteMarksreadBorderSidereadCellBordersreadNumPrreadSectionPropertiesreadTableBordersreadTableStructureresetGraphemeBoundaryresolveBorderConflictresolveDefaultSurfaceMeasurerresolveDefaultWordBoundaryresolveNumberingLevelresolveOoxmlShadingFillresolveParagraphLayoutInputsresolveRunStyleresolveStoryListItemsresolveStoryRefFieldsresolveStrictHexFillresolveTableCellBorderGridreviewAnchorIndexreviewItemGeometryreviewItemKeyreviewItemPositionRankreviewItemRangesreviewItemsAtreviewThreadRootOfrevisionAuthorFilterrevisionRemovesParagraphrevisionsAreDeletionrevisionsVisibleroundFontUnitToFixedPointrunStylesEqualsegmentGraphemessegmentWordsselectionRectssemanticHorizontalBoundariessetGraphemeBoundarysetHarfBuzzWasmUrlsha256FontBytesshadingFillFromElementshapedHorizontalBoundariesshapedRunComparatorInputsshapingEnvironmentFingerprintshapingEnvironmentFingerprintInputsshownMarkRevisionspanOffsetXspansInCellsspansInSelectionstoryBlocksstyleForFontSlotsyntheticSeparatorBoxtabAdvanceWidthtableContextAttableOriginXtabStopsFingerprinttocFieldChromeParagraphIdstryCreateCanvasMeasurerunionLayoutBoxesutf16OffsetToGraphemewalkStoryParagraphswithDefaultTabIntervalwithNumberingStyleLinkswithResolvedListItemswordBoundarywordSegmentsToGraphemeRecordsClassesFontResolutionErrorHarfBuzzShapingErrorLayoutShapingConfigurationErrorResolvedCacheTablePaginationErrorUnsupportedScriptErrorInterfacesAbstractNumDefinitionAnchoredDrawingRecordAutonumFieldSpecBidiEmbeddingLevelsBorderGridGeometryCacheProvenanceCanvasMeasurerOptionsCanvasTextContextCanvasTextMetricsCaretAtOptionsCaretGeometryCascadedParagraphFormattingCellBorderBoxCellMarginsPtCellSelectionCjkTypographySettingsCommentAnchorCommentPositionCommentRecordCommentThreadStateCompoundBorderMetricsContentControlBoundaryRecordContentControlFragmentRecordContentControlGeometryFragmentCreateDocumentFurnitureSourceOptionsCreateDocumentNotesInputOptionsDeclaredFontSubstitutionDocumentFurnitureSourceDocumentLinkProjectorsDocumentSectionDocumentSectionsEnumerationDocumentStyleDependenciesDrawingAccessibilityDrawingGeometryDrawingImageEffectsDrawingInsetsDrawingOverlayFrameDrawingPointDrawingTransformEquationFractionGeometryEquationNaryGeometryEquationRadicalGeometryEquationRowGeometryEquationScriptGeometryEquationSpanRecordEquationTextGeometryFieldAtomMarkerFieldLinkRegistryFontFingerprintInputsFontRequestFontResourceDefinitionFontResourceInstrumentationFontResourceSnapshotFontResourceSnapshotOptionsFontSubstitutionGlyphOutlineGraphemeBoundaryGraphemeSegmentGraphemeWordSegmentRecordHarfBuzzFaceCacheEventHarfBuzzOutlineCacheEventHarfBuzzShapeCacheEventHarfBuzzTextShaperHarfBuzzTextShaperInstrumentationHarfBuzzTextShaperOptionsHeaderFooterStoryRecordHitPointHitTestOptionsHyperlinkFieldSpecInlineDrawingRecordKeyedRangeLayoutBoxLayoutCacheStatsLayoutEnvironmentShapedMeasurerOptionsLayoutFontConfigurationLayoutFontSourceLayoutFontSubstitutionLayoutSchedulerLayoutSchedulerOptionsLayoutScopeLayoutSessionLayoutSessionStatsLayoutShapingInstrumentationLayoutShapingOptionsLevelOverrideLineRecordLineSegmentListCounterAdvanceListCounterStateListMarkerRecordMaterializationInputMoveCaretOptionsNoteAreaRecordNoteDisplayMarkNoteMarkContextNoteReferenceSiteNotesAttachResultNoteSeparatorLayoutNotesLayoutInputNoteStoryDrawingsNoteStoryLayoutNoteStoryRecordNumberingIndexNumberingLevelNumberingLevelIndentNumDefinitionOperationSnapshotPageBorderFrameRecordPageBorderStrokeRecordPageFurniturePageGeometryPageRecordPageRefFieldProjectionParagraphAutoSpacingContextParagraphBorderEdgeParagraphBordersParagraphBorderStrokeRecordParagraphBottomBorderRecordParagraphFragmentRecordParagraphIndentParagraphKeyInputsParagraphLayoutCacheParagraphLayoutCacheOptionsParagraphLayoutInputsParagraphLineSpacingParagraphSpacingPlacedCellPreferredWidthPreparedLayoutFontConfigurationRefFieldContextRefFieldRefreshOptionsRefFieldSpecRefNotePartsRegisteredFieldLinkResolvedCellBordersResolvedFontResolvedListItemResolvedRunStyleResolvedSurfaceMeasurerResolvedTableBorderEdgeResolvedTableBorderEdgeSegmentResolvedTabStopsResolvedUnderlineResourceDependencyProvenanceReviewCommentItemReviewCustomItemReviewModelInputReviewParagraphAnchorReviewPositionReviewRangeReviewRevisionItemRevisionAttributionRevisionAuthorFilterRevisionFilterScriptItemSectionColumnDefinitionSectionColumnsSectionMarginsSectionPageBordersSectionPageNumberingSectionPropertiesSelectionRectSemanticCommentArtifactRecordSemanticDrawingVisitSemanticHitSemanticHitDrawingSemanticLayoutSemanticLayoutOptionsSemanticPositionSemanticReviewArtifactOccurrenceSemanticReviewArtifactOccurrenceGeometrySemanticReviewArtifactPositionSemanticReviewArtifactSourceSemanticSelectionSemanticSpanVisitSemanticTableCellSemanticTableRowSemanticTableStructureSemanticTrackedChangeArtifactRecordShapedClusterShapedFontSpanShapedGlyphShapedMeasurerOptionsShapedRunShapedRunComparatorInputsShapedVerticalMetricsShapeInputShapingEnvironmentShapingEnvironmentFingerprintInputsShapingEnvironmentInputSourceCropSourceRangeSpanLinkRecordStoryDrawingContextStoryDrawingHostStoryParagraphFragmentContextStoryProjectionDependenciesStyleCascadeTableStyleDefinitionStyleSpanRecordTabDestinationTableBorderBoxTableBorderStrokeRecordTableCellAddressTableCellContextTableCellFragmentRecordTableCellStyleFormattingTableFragmentRecordTableRowFragmentRecordTabStopTextboxStoryLayoutTextMeasurerTextShaperVectorShapeComponentVectorShapeProjectionVersionedShapingLibraryViewportWindowWordBoundaryWordBoundaryResolverDepsWordSegmentType aliasesAnchoredDrawingLayoutFallbackAutonumFieldKindBlockFragmentRecordCacheLookupCacheMissCellVerticalAlignContentControlLevelContentControlLockContentControlMappedTypeDrawingClipFallbackDrawingHorizontalReferenceFrameDrawingVerticalReferenceFrameEquationGeometryFieldLinkProjectorFixedPointFixedPointRoundingModeFontByteValidatorFontResolutionErrorCodeFontSlotFontValidationResultHarfBuzzShapingErrorCodeHeaderFooterVariantNameHyperlinkProjectorImageWrapTargetLayoutShapingEnvironmentLineSpacingRuleListMarkerAlignListSuffixNavigationCommandNormalizationPolicyNoteLayoutFallbackReasonNotePaginationFallbackReasonNoteSeparatorRuleStyleOperationSnapshotFieldOperationSnapshotGuardPageBorderDisplayPageBorderOffsetFromPageBorderSidePageBorderZOrderPageRefCalibrationCellPageRefIndexParagraphBorderSidePreferredWidthTypeReviewItemReviewRevisionKindRevisionDisplayModeRevisionKindSectionBreakTypeSemanticArtifactRootStoryKindSemanticArtifactStoryKindSemanticDrawingLayerSemanticReviewArtifactRecordSemanticRootStoryKindSemanticStoryKindSemanticStoryVisitTabAlignmentTabLeaderTableAlignmentTableBorderSideTableBorderSideNameTableBorderStyleTablePaginationErrorCodeTableRowHeightTableRowHeightRuleTextboxStoryFallbackReasonTextDirectionVerticalAlignVariablesAUTO_PARAGRAPH_SPACING_PTAUTO_PREFERRED_WIDTHboundedStructuralFontValidatorCELL_PADCOMPOUND_BORDER_MIN_GAP_PTCOMPOUND_BORDER_MIN_STROKE_PTDEFAULT_CANVAS_FONT_STACKDEFAULT_CELL_MARGINSDEFAULT_PAGE_GEOMETRYDEFAULT_REVISION_DISPLAY_MODEDEFAULT_RUN_STYLEDEFAULT_SECTION_PROPERTIESDEFAULT_TAB_INTERVAL_PTDEFAULT_TAB_INTERVAL_TWIPSDEFAULT_VERTICAL_WEIGHTEMPTY_NUMBERING_INDEXEMPTY_TAB_STOPSGRAPHEME_SEGMENTER_LOCALEHARD_MAX_AGGREGATE_FONT_BYTESHARD_MAX_FONT_BYTESHARD_MAX_FONT_SOURCESHARFBUZZ_SHAPING_LIBRARYharfBuzzFontValidatorintlGraphemeBoundaryMAX_BORDER_SPACE_PTMAX_BORDER_WIDTH_PTMAX_DOCUMENT_SECTIONSMAX_EACH_PAGE_MARK_CANDIDATESMAX_LVL_OVERRIDESMAX_LVL_TEXT_LENGTHMAX_MARKER_TEXT_LENGTHMAX_NOTE_FRAGMENTSMAX_NOTE_OVERFLOW_PAGESMAX_NOTE_REFLOW_ATTEMPTSMAX_NOTES_LAID_OUTMAX_NUMBERING_DEFINITIONSMAX_PARAGRAPH_SPACING_PTMAX_SDT_NESTINGMAX_STYLE_BASED_ON_DEPTHMAX_STYLE_DEFINITIONSMAX_TAB_POSITION_TWIPSMAX_TAB_STOPSMAX_TABLE_BORDER_STROKESMAX_TABLE_COLUMNSMAX_TABLE_NESTINGMAX_TABLE_ROW_FRAGMENTSMAX_TABLE_ROW_HEIGHT_PTPAGE_BORDER_SIDESPARAGRAPH_BORDER_SIDESSINGLE_LINE_SPACINGTAB_LEADER_GLYPHW15_NAMESPACE_URIWORD_SEGMENTER_LOCALE