@docx4j/core-ts 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +5 -2
  2. package/dist/html/convert.mjs +38 -14
  3. package/dist/model/content/Body.d.mts +13 -1
  4. package/dist/model/content/Body.mjs +90 -19
  5. package/dist/model/content/Comment.mjs +7 -0
  6. package/dist/model/content/InlinePicture.d.mts +71 -7
  7. package/dist/model/content/InlinePicture.mjs +201 -28
  8. package/dist/model/content/List.mjs +10 -1
  9. package/dist/model/content/Paragraph.d.mts +28 -5
  10. package/dist/model/content/Paragraph.mjs +77 -37
  11. package/dist/model/content/Range.d.mts +18 -2
  12. package/dist/model/content/Range.mjs +194 -64
  13. package/dist/model/content/TrackedChange.d.mts +129 -3
  14. package/dist/model/content/TrackedChange.mjs +577 -12
  15. package/dist/model/content/binder.d.mts +2 -1
  16. package/dist/model/content/binder.mjs +48 -1
  17. package/dist/model/content/index.d.mts +2 -2
  18. package/dist/model/content/index.mjs +1 -1
  19. package/dist/model/content/relationships.d.mts +30 -0
  20. package/dist/model/content/relationships.mjs +133 -0
  21. package/dist/model/content/tree.d.mts +52 -2
  22. package/dist/model/content/tree.mjs +48 -3
  23. package/dist/model/customxml/pictures.d.mts +5 -2
  24. package/dist/model/customxml/pictures.mjs +13 -7
  25. package/dist/model/fonts/families.generated.mjs +2 -2
  26. package/dist/model/fonts/registry.mjs +7 -1
  27. package/dist/model/fonts/substitutions.generated.mjs +2 -2
  28. package/dist/model/fonts/themes.generated.mjs +1 -1
  29. package/dist/model/listnumbering/definitions.mjs +18 -0
  30. package/dist/model/properties/PropertyResolver.d.mts +27 -6
  31. package/dist/model/properties/PropertyResolver.mjs +83 -16
  32. package/dist/model/properties/catalogue.d.mts +15 -1
  33. package/dist/model/properties/catalogue.mjs +80 -27
  34. package/dist/model/properties/table.d.mts +16 -2
  35. package/dist/model/properties/table.mjs +13 -3
  36. package/dist/opc/Load.d.mts +9 -2
  37. package/dist/opc/index.d.mts +2 -2
  38. package/dist/opc/index.mjs +2 -2
  39. package/dist/opc/mce/preprocessor.d.mts +62 -6
  40. package/dist/opc/mce/preprocessor.mjs +142 -35
  41. package/dist/opc/mce/understood.d.mts +10 -0
  42. package/dist/opc/mce/understood.mjs +25 -3
  43. package/dist/packages/OpcPackage.d.mts +7 -0
  44. package/dist/packages/OpcPackage.mjs +15 -3
  45. package/dist/packages/WordprocessingMLPackage.d.mts +35 -2
  46. package/dist/packages/WordprocessingMLPackage.mjs +98 -2
  47. package/dist/parts/XmlPart.d.mts +26 -5
  48. package/dist/parts/XmlPart.mjs +67 -18
  49. package/package.json +2 -2
@@ -10,7 +10,8 @@ export interface Bound {
10
10
  * The tree object: for an element, what a walk of the typed tree would hand you at that path,
11
11
  * never a `{ name, value }` wrapper; for an attribute or a text node, the object of the element
12
12
  * that owns it. Undefined for an element the model does not build - a wildcard child is its own
13
- * object, so this is undefined only above the root or for a node the marshal did not report.
13
+ * object, and so is each element inside one (the node at the same place in the tree), so this is
14
+ * undefined only above the root or for a node the marshal did not report.
14
15
  */
15
16
  object: unknown;
16
17
  /** Set when an attribute was selected: its qualified name on `object`'s element. */
@@ -33,11 +33,12 @@ export async function bindSnapshot(element) {
33
33
  /** Turns selected nodes into `Bound`s against a snapshot, with one path cache for them all. */
34
34
  export function boundsOf(nodes, snapshot) {
35
35
  const paths = new Paths();
36
+ const indexes = new Map();
36
37
  return nodes.map((node) => {
37
38
  const owner = owningElement(node);
38
39
  const bound = {
39
40
  node,
40
- object: owner === undefined ? undefined : snapshot.objects.get(owner),
41
+ object: owner === undefined ? undefined : objectOf(owner, snapshot.objects, indexes),
41
42
  path: paths.of(node),
42
43
  };
43
44
  if (node.nodeType === 2)
@@ -45,6 +46,49 @@ export function boundsOf(nodes, snapshot) {
45
46
  return bound;
46
47
  });
47
48
  }
49
+ /**
50
+ * The tree object behind a snapshot element. The marshal reports a wildcard child's imported copy
51
+ * but nothing inside it, so an element there maps to the node at the same place under the original:
52
+ * the copy is deep, so the child positions agree. Since CR-010 phase 4 a kept branch's DrawingML is
53
+ * DOM from the branch down (an `xdr:graphicFrame`, a `p:sp`), and a selection lands inside it.
54
+ * Below a typed ancestor an unreported element stays unmapped.
55
+ */
56
+ function objectOf(element, objects, indexes) {
57
+ if (objects.has(element))
58
+ return objects.get(element);
59
+ const path = [];
60
+ let at = element;
61
+ while (!objects.has(at)) {
62
+ path.push(at);
63
+ const parent = at.parentNode;
64
+ if (parent === null || parent.nodeType !== 1)
65
+ return undefined;
66
+ at = parent;
67
+ }
68
+ let node = objects.get(at);
69
+ if (!isNode(node))
70
+ return undefined;
71
+ for (let k = path.length - 1; k >= 0; k--) {
72
+ node = node.childNodes[childIndex(path[k], indexes)];
73
+ if (node === undefined || node === null)
74
+ return undefined;
75
+ }
76
+ return node;
77
+ }
78
+ /** A node's position among its parent's child nodes, each parent's counted once. */
79
+ function childIndex(node, indexes) {
80
+ var _a;
81
+ const parent = node.parentNode;
82
+ let index = indexes.get(parent);
83
+ if (index === undefined) {
84
+ index = new Map();
85
+ let i = 0;
86
+ for (let child = parent.firstChild; child; child = child.nextSibling)
87
+ index.set(child, i++);
88
+ indexes.set(parent, index);
89
+ }
90
+ return (_a = index.get(node)) !== null && _a !== void 0 ? _a : -1;
91
+ }
48
92
  /**
49
93
  * The element an XPath result belongs to: itself for an element, its owner for an attribute, its
50
94
  * parent for a text, comment or processing-instruction node. A document node has none.
@@ -123,6 +167,9 @@ class Paths {
123
167
  return (_b = positions.get(element)) !== null && _b !== void 0 ? _b : 0;
124
168
  }
125
169
  }
170
+ function isNode(node) {
171
+ return typeof node === 'object' && node !== null && typeof node.nodeType === 'number';
172
+ }
126
173
  function isElement(node) {
127
174
  return typeof node === 'object' && node !== null && node.nodeType === 1;
128
175
  }
@@ -12,8 +12,8 @@ export { InlinePicture, imageInfoOf, naturalSizeEmu, addImage, addImagePart, wri
12
12
  export { ContentControl, collectControls, collectRunControls, W14_NS, W15_NS, type ContentControlType, type ContentControlForm, type ContentControlAppearance } from './ContentControl.mjs';
13
13
  export { contentOf, isFlatOpc, rewriteRelationshipIds, type OoxmlOptions } from './ooxml.mjs';
14
14
  export { type SearchOptions, searchPattern, findAll, matchesOf, expandReplacement } from './search.mjs';
15
- export { segmentsOf, runsOf, runItemsOf, childrenOf, rowsOf, cellsOf, BLOCK_LEVEL_TYPES, SDT_TYPES, runOf, paragraphOf, textOfView, revisionKindOf, type TextSegment, type Located, type TextView, type TextViewOptions, type RevisionKind, type RevisionHolder } from './tree.mjs';
16
- export { TrackedChange, trackedChangesOfParagraph, trackedChangesOfRow, joinWithNext, type TrackedChangeType, type TrackedChangeTarget } from './TrackedChange.mjs';
15
+ export { segmentsOf, runsOf, runItemsOf, selectedBranchOf, isAlternateContent, childrenOf, rowsOf, cellsOf, BLOCK_LEVEL_TYPES, SDT_TYPES, runOf, paragraphOf, textOfView, revisionKindOf, type TextSegment, type Located, type TextView, type TextViewOptions, type RevisionKind, type RevisionHolder } from './tree.mjs';
16
+ export { TrackedChange, trackedChangesOfParagraph, trackedChangesOfRow, joinWithNext, type TrackedChangeType, type TrackedChangeTarget, type NoteRemovals } from './TrackedChange.mjs';
17
17
  export { ChangeTracker, trackerOf, calendarOf, dateOf, wordCalendarOf, revisionDateOf, copyRPr, markDeleted, markInserted, highestAnnotationId, MARKUP_TYPES, toDeletedText, toRestoredText, restoreRPr, restorePPr, trackInsertedParagraph, trackInsertedTable, trackInsertedBlocks, wrapNewRuns, wrapInsertedRuns, paraRPrOf, rowPrOf, pruneParagraphProperties, type ChangeTrackingMode, type TrackingHost, type TrackingScope, type TrackedPart, } from './tracking.mjs';
18
18
  export { wml, wmlOne, p, r, t, br, tab, tbl, tr, tc, sdt, sdtPr, nextSdtId, sdtProperty, sdtKindOf, inlinePicture, rPrToElements, rPrFromElements, textOf, walk, walkAll, find, linkParents, applyRunOptions, readRunOptions, UNDERLINE_TO_WML, isElement, typeNameOf, W_NS, type Element, type Wrapper, type WmlOptions, type Raw, type Interpolated, type RunOptions, type RunFormatting, type ParagraphOptions, type TableOptions, type CellOptions, type SdtKind, type SdtForm, type SdtOptions } from '@docx4j/generated-objects-ts/builders/wml';
19
19
  export { StylesFacade, type StylePackageLike } from './stylesFacade.mjs';
@@ -14,7 +14,7 @@ export { InlinePicture, imageInfoOf, naturalSizeEmu, addImage, addImagePart, wri
14
14
  export { ContentControl, collectControls, collectRunControls, W14_NS, W15_NS } from './ContentControl.mjs';
15
15
  export { contentOf, isFlatOpc, rewriteRelationshipIds } from './ooxml.mjs';
16
16
  export { searchPattern, findAll, matchesOf, expandReplacement } from './search.mjs';
17
- export { segmentsOf, runsOf, runItemsOf, childrenOf, rowsOf, cellsOf, BLOCK_LEVEL_TYPES, SDT_TYPES, runOf, paragraphOf, textOfView, revisionKindOf } from './tree.mjs';
17
+ export { segmentsOf, runsOf, runItemsOf, selectedBranchOf, isAlternateContent, childrenOf, rowsOf, cellsOf, BLOCK_LEVEL_TYPES, SDT_TYPES, runOf, paragraphOf, textOfView, revisionKindOf } from './tree.mjs';
18
18
  // change tracking (CR-002 phase F)
19
19
  export { TrackedChange, trackedChangesOfParagraph, trackedChangesOfRow, joinWithNext } from './TrackedChange.mjs';
20
20
  export { ChangeTracker, trackerOf, calendarOf, dateOf, wordCalendarOf, revisionDateOf, copyRPr, markDeleted, markInserted, highestAnnotationId, MARKUP_TYPES, toDeletedText, toRestoredText, restoreRPr, restorePPr, trackInsertedParagraph, trackInsertedTable, trackInsertedBlocks, wrapNewRuns, wrapInsertedRuns, paraRPrOf, rowPrOf, pruneParagraphProperties, } from './tracking.mjs';
@@ -0,0 +1,30 @@
1
+ import type { Part } from '../../parts/Part.mjs';
2
+ /**
3
+ * Adds to `into` every relationship id a tree references: the `r:` attributes of its typed objects (read
4
+ * off the model's mapping, as docx4j reads its fields' `@XmlAttribute`), those kept in an
5
+ * `otherAttributes` map, and those of any DOM it holds.
6
+ */
7
+ export declare function relationshipIdsIn(tree: unknown, into: Set<string>): void;
8
+ /**
9
+ * The relationships of `part` among `candidates` that nothing left in the part references are removed,
10
+ * and the part each targeted when no relationship in the package targets it any more, with what that
11
+ * part alone related to (`RelationshipsPart.removeParts`). A part not unmarshalled can't be read for
12
+ * what still references, so nothing is removed from it.
13
+ */
14
+ export declare function dropRelationshipsUnused(part: Part, candidates: Set<string>): void;
15
+ /**
16
+ * Relationship ids, by the name of the part they belong to, that content removed outside a
17
+ * resolution referenced: a picture deleted with tracking off, or taken back from its author's own
18
+ * insertion. They are settled when the package is saved rather than at once, so that content put
19
+ * back in the meantime (a cut and a paste of the same drawing) keeps its relationship.
20
+ */
21
+ export type RelationshipRemovals = Map<string, Set<string>>;
22
+ /** Queues `ids` of `part` for `flushPendingRelationshipRemovals`. */
23
+ export declare function queueRelationshipRemovals(pending: RelationshipRemovals | undefined, part: Part | undefined, ids: Iterable<string>): void;
24
+ /** What `flushPendingRelationshipRemovals` needs of the package. */
25
+ interface PartsHost {
26
+ getPart(name: string): Part | undefined;
27
+ }
28
+ /** Settles the queued ids against each part as it now stands (`dropRelationshipsUnused`); then `pending` is empty. */
29
+ export declare function flushPendingRelationshipRemovals(pkg: PartsHost, pending: RelationshipRemovals): void;
30
+ export {};
@@ -0,0 +1,133 @@
1
+ /**
2
+ * The relationships content references, and the removal of those nothing references any more
3
+ * (CR-002 section 46, docx4j CR-043's D7): shared by the tracked-change resolution
4
+ * (`TrackedChange.mts`) and the pictures (`InlinePicture.delete`, section 47).
5
+ */
6
+ import { getContextSync } from '@docx4j/generated-objects-ts';
7
+ const R_NS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
8
+ /** Per type, the properties that are attributes in the relationships namespace (`r:id`, `r:embed`, `r:link`, ...). */
9
+ const relationshipAttributes = new Map();
10
+ function relationshipAttributesOf(typeName) {
11
+ var _a, _b;
12
+ let names = relationshipAttributes.get(typeName);
13
+ if (names)
14
+ return names;
15
+ const found = [];
16
+ let info;
17
+ try {
18
+ info = getContextSync().getTypeInfoByName(typeName);
19
+ }
20
+ catch {
21
+ info = undefined;
22
+ }
23
+ for (let ti = info; ti; ti = ti.baseTypeInfo) {
24
+ for (const property of (_a = ti.properties) !== null && _a !== void 0 ? _a : []) {
25
+ if (((_b = property.attributeName) === null || _b === void 0 ? void 0 : _b.namespaceURI) === R_NS && property.name)
26
+ found.push(property.name);
27
+ }
28
+ }
29
+ relationshipAttributes.set(typeName, names = found);
30
+ return names;
31
+ }
32
+ /**
33
+ * Adds to `into` every relationship id a tree references: the `r:` attributes of its typed objects (read
34
+ * off the model's mapping, as docx4j reads its fields' `@XmlAttribute`), those kept in an
35
+ * `otherAttributes` map, and those of any DOM it holds.
36
+ */
37
+ export function relationshipIdsIn(tree, into) {
38
+ const seen = new Set();
39
+ const visitDom = (node) => {
40
+ if (node.nodeType !== 1)
41
+ return;
42
+ const attributes = node.attributes;
43
+ for (let i = 0; i < attributes.length; i++) {
44
+ const a = attributes[i];
45
+ if (a.namespaceURI === R_NS && a.value)
46
+ into.add(a.value);
47
+ }
48
+ for (let c = node.firstChild; c; c = c.nextSibling)
49
+ visitDom(c);
50
+ };
51
+ const visit = (o) => {
52
+ if (typeof o !== 'object' || o === null || seen.has(o))
53
+ return;
54
+ seen.add(o);
55
+ if (Array.isArray(o)) {
56
+ for (const item of o)
57
+ visit(item);
58
+ return;
59
+ }
60
+ if (typeof o.nodeType === 'number') {
61
+ visitDom(o);
62
+ return;
63
+ }
64
+ const record = o;
65
+ const typeName = record.TYPE_NAME;
66
+ if (typeof typeName === 'string') {
67
+ for (const name of relationshipAttributesOf(typeName)) {
68
+ const value = record[name];
69
+ if (typeof value === 'string' && value)
70
+ into.add(value);
71
+ }
72
+ }
73
+ const other = record.otherAttributes;
74
+ if (other && typeof other === 'object') {
75
+ for (const [key, value] of Object.entries(other))
76
+ if (key.startsWith(`{${R_NS}}`) && typeof value === 'string')
77
+ into.add(value);
78
+ }
79
+ for (const key in record)
80
+ if (key !== 'PARENT' && key !== 'otherAttributes')
81
+ visit(record[key]);
82
+ };
83
+ visit(tree);
84
+ }
85
+ /**
86
+ * The relationships of `part` among `candidates` that nothing left in the part references are removed,
87
+ * and the part each targeted when no relationship in the package targets it any more, with what that
88
+ * part alone related to (`RelationshipsPart.removeParts`). A part not unmarshalled can't be read for
89
+ * what still references, so nothing is removed from it.
90
+ */
91
+ export function dropRelationshipsUnused(part, candidates) {
92
+ var _a, _b;
93
+ const rels = part.relationshipsPart;
94
+ const contents = part.isUnmarshalled
95
+ ? part.contents : undefined;
96
+ if (!rels || contents === undefined)
97
+ return;
98
+ const used = new Set();
99
+ relationshipIdsIn(contents, used);
100
+ for (const id of candidates) {
101
+ if (used.has(id))
102
+ continue;
103
+ const rel = rels.getRelationshipById(id);
104
+ if (!rel)
105
+ continue;
106
+ const target = rels.getPart(rel);
107
+ rels.removeRelationship(rel);
108
+ if (target && target.sourceRelationships.length === 0) {
109
+ (_a = target.relationshipsPart) === null || _a === void 0 ? void 0 : _a.removeParts();
110
+ (_b = target.package) === null || _b === void 0 ? void 0 : _b.parts.remove(target.partName);
111
+ }
112
+ }
113
+ }
114
+ /** Queues `ids` of `part` for `flushPendingRelationshipRemovals`. */
115
+ export function queueRelationshipRemovals(pending, part, ids) {
116
+ if (!pending || !part)
117
+ return;
118
+ let set = pending.get(part.partName.name);
119
+ for (const id of ids) {
120
+ if (!set)
121
+ pending.set(part.partName.name, set = new Set());
122
+ set.add(id);
123
+ }
124
+ }
125
+ /** Settles the queued ids against each part as it now stands (`dropRelationshipsUnused`); then `pending` is empty. */
126
+ export function flushPendingRelationshipRemovals(pkg, pending) {
127
+ for (const [name, ids] of pending) {
128
+ const part = pkg.getPart(name);
129
+ if (part)
130
+ dropRelationshipsUnused(part, ids);
131
+ }
132
+ pending.clear();
133
+ }
@@ -1,4 +1,5 @@
1
1
  import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
2
+ import type * as mce from '@docx4j/generated-objects-ts/modules/org_docx4j_mce';
2
3
  import { isElement, runItemsOf, type Element } from '@docx4j/generated-objects-ts/builders/wml';
3
4
  export { isElement, typeNameOf, walk, find, linkParents, textOf, W_NS, type Element } from '@docx4j/generated-objects-ts/builders/wml';
4
5
  /** The two views of a tracked document: as it will read once accepted, or as it read before the changes. */
@@ -7,6 +8,47 @@ export interface TextViewOptions {
7
8
  /** 'accepted' (the default: w:ins included, w:del excluded) or 'original' (the other way). */
8
9
  view?: TextView;
9
10
  }
11
+ /** `segmentsOf`'s options: a view, and whether drawn objects get a segment of their own. */
12
+ export interface SegmentOptions extends TextViewOptions {
13
+ /**
14
+ * True to list each picture or other drawn object (`OBJECT_ITEMS`) as a segment of no text at its
15
+ * place in the text (`object` set), so that a deletion of a span can find it (CR-002 section 48).
16
+ */
17
+ objects?: boolean;
18
+ }
19
+ /**
20
+ * Run content that stands in the text and has no text of its own: a `w:drawing` (a picture, a chart, a
21
+ * text box), a VML `w:pict` and an embedded `w:object`. Office JS counts an inline picture as in a
22
+ * range, so a span's deletion takes the objects in it (CR-002 section 48). A kept `mc:AlternateContent`
23
+ * in a run is one such object too, whatever its branches hold (`ALTERNATE_CONTENT`, CR-010 phase 3).
24
+ */
25
+ export declare const OBJECT_ITEMS: ReadonlySet<string>;
26
+ /** The TYPE_NAME of a kept `mc:AlternateContent` (the default load since CR-010 phase 4; under `KEPT_HOSTS` with `mcePreprocess: true`). */
27
+ export declare const ALTERNATE_CONTENT = "org_docx4j_mce.AlternateContent";
28
+ /**
29
+ * The branch of a kept `mc:AlternateContent` the content API reads (docx4j's `McMode.READ`, CR-010
30
+ * phase 3): the objects package's `mcBranchOf` over the prefixes load understands
31
+ * (`UNDERSTOOD_PREFIXES`), so a reader of the kept element takes the branch the preprocessor would have
32
+ * resolved it to. A mutator walks every branch instead (docx4j's `McMode.ALL`). Undefined for an element
33
+ * with no branches.
34
+ */
35
+ export declare function selectedBranchOf(value: mce.AlternateContent | undefined): Element[] | undefined;
36
+ /** True for a kept `mc:AlternateContent`: its element pair, or its value. */
37
+ export declare function isAlternateContent(value: unknown): boolean;
38
+ /**
39
+ * Which objects at a span's edges are in the span. An object stands between two characters, so one at
40
+ * a span's start or end offset may be inside it or outside it, and offsets alone cannot say which. A
41
+ * paragraph's whole range holds the objects at both of its edges (`WHOLE`); a span of text, such as a
42
+ * search found, holds only the objects strictly inside it (CR-002 section 48).
43
+ */
44
+ export interface SpanEdges {
45
+ start: boolean;
46
+ end: boolean;
47
+ }
48
+ /** Both edges: the objects at a span's start and at its end are in it. */
49
+ export declare const WHOLE: SpanEdges;
50
+ /** True when an object at offset `at` is in the span [start, end) with these edges. */
51
+ export declare function objectInSpan(at: number, start: number, end: number, edges?: SpanEdges): boolean;
10
52
  /** The four run-level revision holders (CR-002 phase F); their runs live under `customXmlOrSmartTagOrSdt`. */
11
53
  export type RevisionKind = 'ins' | 'del' | 'moveFrom' | 'moveTo';
12
54
  /** The run-level revision a run sits in. */
@@ -37,6 +79,8 @@ export interface TextSegment {
37
79
  end: number;
38
80
  /** True for w:t: text that can be edited in place. */
39
81
  editable: boolean;
82
+ /** True for a drawn object (`OBJECT_ITEMS`, or a kept `mc:AlternateContent`), whose segment has no text: listed only when asked for. */
83
+ object?: boolean;
40
84
  /**
41
85
  * The nearest enclosing w:ins / w:del / w:moveFrom / w:moveTo, when the run is in one.
42
86
  * A deletion of this run goes inside it (`runOwner` is already its item list); an insertion
@@ -53,9 +97,15 @@ declare function itemText(item: Element): string | undefined;
53
97
  /**
54
98
  * The text segments of a paragraph (or any run holder) in order. The default view is the
55
99
  * accepted one: the runs of a `w:ins` or `w:moveTo` count, those of a `w:del` or `w:moveFrom`
56
- * do not. `{ view: 'original' }` is the other way round (CR-002 phase F).
100
+ * do not. `{ view: 'original' }` is the other way round (CR-002 phase F). `{ objects: true }`
101
+ * lists the drawn objects too, each a segment of no text where it stands (CR-002 section 48).
102
+ *
103
+ * A kept `mc:AlternateContent` in a run is one object segment, whatever its branches hold, so that
104
+ * removing a span removes every branch with it (CR-010 phase 3). A drawing adds no text, so the
105
+ * offsets are a resolved load's. One in a paragraph's content, outside a run, is not listed: Word
106
+ * writes none, and the corpus has none (CR-010 section 11.3).
57
107
  */
58
- export declare function segmentsOf(container: object, options?: TextViewOptions): TextSegment[];
108
+ export declare function segmentsOf(container: object, options?: SegmentOptions): TextSegment[];
59
109
  /** The text of a paragraph or container in one of the two views (`textOf` is the accepted one). */
60
110
  export declare function textOfView(container: object, options?: TextViewOptions): string;
61
111
  /** The runs of a paragraph, direct and nested in hyperlinks, content controls and insertions, in order. */
@@ -1,5 +1,36 @@
1
- import { isElement, typeNameOf, runItemsOf } from '@docx4j/generated-objects-ts/builders/wml';
1
+ import { isElement, typeNameOf, runItemsOf, mcBranchOf } from '@docx4j/generated-objects-ts/builders/wml';
2
+ import { UNDERSTOOD_PREFIXES } from '../../opc/mce/understood.mjs';
2
3
  export { isElement, typeNameOf, walk, find, linkParents, textOf, W_NS } from '@docx4j/generated-objects-ts/builders/wml';
4
+ /**
5
+ * Run content that stands in the text and has no text of its own: a `w:drawing` (a picture, a chart, a
6
+ * text box), a VML `w:pict` and an embedded `w:object`. Office JS counts an inline picture as in a
7
+ * range, so a span's deletion takes the objects in it (CR-002 section 48). A kept `mc:AlternateContent`
8
+ * in a run is one such object too, whatever its branches hold (`ALTERNATE_CONTENT`, CR-010 phase 3).
9
+ */
10
+ export const OBJECT_ITEMS = new Set(['drawing', 'pict', 'object']);
11
+ /** The TYPE_NAME of a kept `mc:AlternateContent` (the default load since CR-010 phase 4; under `KEPT_HOSTS` with `mcePreprocess: true`). */
12
+ export const ALTERNATE_CONTENT = 'org_docx4j_mce.AlternateContent';
13
+ /**
14
+ * The branch of a kept `mc:AlternateContent` the content API reads (docx4j's `McMode.READ`, CR-010
15
+ * phase 3): the objects package's `mcBranchOf` over the prefixes load understands
16
+ * (`UNDERSTOOD_PREFIXES`), so a reader of the kept element takes the branch the preprocessor would have
17
+ * resolved it to. A mutator walks every branch instead (docx4j's `McMode.ALL`). Undefined for an element
18
+ * with no branches.
19
+ */
20
+ export function selectedBranchOf(value) {
21
+ return mcBranchOf(value, { understood: UNDERSTOOD_PREFIXES });
22
+ }
23
+ /** True for a kept `mc:AlternateContent`: its element pair, or its value. */
24
+ export function isAlternateContent(value) {
25
+ const v = isElement(value) ? value.value : value;
26
+ return typeof v === 'object' && v !== null && v.TYPE_NAME === ALTERNATE_CONTENT;
27
+ }
28
+ /** Both edges: the objects at a span's start and at its end are in it. */
29
+ export const WHOLE = Object.freeze({ start: true, end: true });
30
+ /** True when an object at offset `at` is in the span [start, end) with these edges. */
31
+ export function objectInSpan(at, start, end, edges) {
32
+ return (start < at && at < end) || (at === start && (edges === null || edges === void 0 ? void 0 : edges.start) === true) || (at === end && (edges === null || edges === void 0 ? void 0 : edges.end) === true);
33
+ }
3
34
  /** Types whose value holds runs (directly or through sdtContent); the revision holders are separate. */
4
35
  const RUN_HOLDERS = new Set([
5
36
  'org_docx4j_wml.P.Hyperlink', 'org_docx4j_wml.SdtRun', 'org_docx4j_wml.CTSmartTagRun',
@@ -43,11 +74,18 @@ function itemText(item) {
43
74
  /**
44
75
  * The text segments of a paragraph (or any run holder) in order. The default view is the
45
76
  * accepted one: the runs of a `w:ins` or `w:moveTo` count, those of a `w:del` or `w:moveFrom`
46
- * do not. `{ view: 'original' }` is the other way round (CR-002 phase F).
77
+ * do not. `{ view: 'original' }` is the other way round (CR-002 phase F). `{ objects: true }`
78
+ * lists the drawn objects too, each a segment of no text where it stands (CR-002 section 48).
79
+ *
80
+ * A kept `mc:AlternateContent` in a run is one object segment, whatever its branches hold, so that
81
+ * removing a span removes every branch with it (CR-010 phase 3). A drawing adds no text, so the
82
+ * offsets are a resolved load's. One in a paragraph's content, outside a run, is not listed: Word
83
+ * writes none, and the corpus has none (CR-010 section 11.3).
47
84
  */
48
85
  export function segmentsOf(container, options) {
49
86
  var _a;
50
87
  const view = (_a = options === null || options === void 0 ? void 0 : options.view) !== null && _a !== void 0 ? _a : 'accepted';
88
+ const objects = (options === null || options === void 0 ? void 0 : options.objects) === true;
51
89
  const out = [];
52
90
  let pos = 0;
53
91
  const visitRuns = (items, revision) => {
@@ -63,8 +101,15 @@ export function segmentsOf(container, options) {
63
101
  for (let j = 0; j < content.length; j++) {
64
102
  const item = content[j];
65
103
  const text = itemText(item);
66
- if (text === undefined)
104
+ if (text === undefined) {
105
+ if (objects && (OBJECT_ITEMS.has(item.name.localPart) || isAlternateContent(item))) {
106
+ const seg = { item, owner: content, index: j, run, runOwner: items, runIndex: i, text: '', start: pos, end: pos, editable: false, object: true };
107
+ if (revision)
108
+ seg.revision = revision;
109
+ out.push(seg);
110
+ }
67
111
  continue;
112
+ }
68
113
  const seg = {
69
114
  item, owner: content, index: j, run, runOwner: items, runIndex: i, text,
70
115
  start: pos, end: pos + text.length, editable: item.name.localPart === 't',
@@ -26,7 +26,9 @@ export declare function isPictureHandlerBound(control: ContentControl): boolean;
26
26
  export declare function pictureWidthOf(params: Map<string, string>): PictureWidth;
27
27
  /**
28
28
  * Binds one control to a value: base64 image data (a data URL accepted). With `keep`, the first
29
- * `a:blip`'s `r:embed` is pointed at a new image part and the drawing is left as it is; a picture
29
+ * `a:blip` is pointed at a new image part and the drawing is left as it is, as Word binds a picture
30
+ * control (`setBlipImage`: a raster image in `r:embed`, the `asvg:svgBlip` taken away; an SVG under
31
+ * the `asvg:svgBlip`, `r:embed` taken away; the effects kept; CR-002 section 52); a picture
30
32
  * control holding no picture gets a new inline one at its natural size instead (docx4j's pre-v3
31
33
  * fallback), a tag-bound control holding none is left and noted. Otherwise the control's content
32
34
  * becomes one run holding a new inline picture, sized as `PictureWidth` says, in the first
@@ -44,7 +46,8 @@ export declare function applyPictureHandlersTo(controls: ContentControl[], parts
44
46
  /**
45
47
  * The reverse direction for a mapped picture control (docx4j's `UpdateXmlFromDocumentSurface`
46
48
  * skips pictures; Word 15 writes the picture back, check 38): the bytes of the image part the
47
- * first `a:blip` embeds, as base64, into the node. Nothing is written when the node already holds
49
+ * first `a:blip` shows, as base64, into the node: its `asvg:svgBlip`'s SVG where it has one, as
50
+ * `InlinePicture.getBase64` gives (CR-002 section 52), else its `r:embed`'s image. Nothing is written when the node already holds
48
51
  * those bytes (compared decoded, so Word's line-wrapped base64 counts as the same), when the
49
52
  * control shows no picture, or when the blip's part is not an image part. Asynchronous, since a
50
53
  * part's bytes may still be in the container.
@@ -1,5 +1,6 @@
1
1
  import { find } from '../content/tree.mjs';
2
- import { addImage, addImagePart, writableWidthEmu } from '../content/InlinePicture.mjs';
2
+ import { addImage, addImagePart, writableWidthEmu, setBlipImage, svgBlipOf } from '../content/InlinePicture.mjs';
3
+ import { ContentTypes } from '../../opc/ContentTypes.mjs';
3
4
  import { ImagePart } from '../../parts/BinaryPart.mjs';
4
5
  import { base64Decode, base64Encode } from '../../xml/dom.mjs';
5
6
  import { enclosingCellOf } from '../properties/table.mjs';
@@ -73,7 +74,9 @@ function maxWidthEmu(control, width) {
73
74
  }
74
75
  /**
75
76
  * Binds one control to a value: base64 image data (a data URL accepted). With `keep`, the first
76
- * `a:blip`'s `r:embed` is pointed at a new image part and the drawing is left as it is; a picture
77
+ * `a:blip` is pointed at a new image part and the drawing is left as it is, as Word binds a picture
78
+ * control (`setBlipImage`: a raster image in `r:embed`, the `asvg:svgBlip` taken away; an SVG under
79
+ * the `asvg:svgBlip`, `r:embed` taken away; the effects kept; CR-002 section 52); a picture
77
80
  * control holding no picture gets a new inline one at its natural size instead (docx4j's pre-v3
78
81
  * fallback), a tag-bound control holding none is left and noted. Otherwise the control's content
79
82
  * becomes one run holding a new inline picture, sized as `PictureWidth` says, in the first
@@ -94,7 +97,8 @@ export function bindPicture(control, value, width, label) {
94
97
  const blip = firstBlipOf(control);
95
98
  if (blip) {
96
99
  try {
97
- blip.embed = addImagePart(source, base64).relId;
100
+ const added = addImagePart(source, base64);
101
+ setBlipImage(blip, added.relId, added.info.contentType === ContentTypes.IMAGE_SVG);
98
102
  }
99
103
  catch (e) {
100
104
  return { done: false, note: `${label}: not an image this package reads (${messageOf(e)})` };
@@ -145,13 +149,14 @@ export function applyPictureHandlersTo(controls, parts, result) {
145
149
  /**
146
150
  * The reverse direction for a mapped picture control (docx4j's `UpdateXmlFromDocumentSurface`
147
151
  * skips pictures; Word 15 writes the picture back, check 38): the bytes of the image part the
148
- * first `a:blip` embeds, as base64, into the node. Nothing is written when the node already holds
152
+ * first `a:blip` shows, as base64, into the node: its `asvg:svgBlip`'s SVG where it has one, as
153
+ * `InlinePicture.getBase64` gives (CR-002 section 52), else its `r:embed`'s image. Nothing is written when the node already holds
149
154
  * those bytes (compared decoded, so Word's line-wrapped base64 counts as the same), when the
150
155
  * control shows no picture, or when the blip's part is not an image part. Asynchronous, since a
151
156
  * part's bytes may still be in the container.
152
157
  */
153
158
  export async function updateFromPictureControl(control) {
154
- var _a;
159
+ var _a, _b;
155
160
  const mapping = control.xmlMapping;
156
161
  if (!mapping.isMapped || control.type !== 'Picture')
157
162
  return false;
@@ -160,9 +165,10 @@ export async function updateFromPictureControl(control) {
160
165
  return false;
161
166
  const blip = firstBlipOf(control);
162
167
  const source = control.parentBody.part;
163
- if (!(blip === null || blip === void 0 ? void 0 : blip.embed) || !source)
168
+ const relId = ((_a = svgBlipOf(blip)) === null || _a === void 0 ? void 0 : _a.embed) || (blip === null || blip === void 0 ? void 0 : blip.embed);
169
+ if (!relId || !source)
164
170
  return false;
165
- const part = (_a = source.relationshipsPart) === null || _a === void 0 ? void 0 : _a.getPart(blip.embed);
171
+ const part = (_b = source.relationshipsPart) === null || _b === void 0 ? void 0 : _b.getPart(relId);
166
172
  if (!(part instanceof ImagePart))
167
173
  return false;
168
174
  const bytes = await part.getBytes();
@@ -1,6 +1,6 @@
1
1
  // The font families docx4j's own tables know: which have a bold face of their own, and which have Word line metrics recorded.
2
2
  //
3
- // Generated by scripts/generate-substitutions.mjs from docx4j 7fba7a1507fc01fdd7f4dc2f79cdbd6988c044f7:
3
+ // Generated by scripts/generate-substitutions.mjs from docx4j 84d0f8a5b2f0d357b03fae151216ca0757609441:
4
4
  // org/docx4j/fonts/microsoft/MicrosoftFonts.xml (149 families)
5
5
  // org/docx4j/fonts/word-line-metrics.properties (512 families)
6
6
  // Do not edit; run `npm run generate:fonts` instead.
@@ -10,7 +10,7 @@ export const MS_FONT_NAMES = ["Arial", "Arial Black", "Comic Sans MS", "Courier
10
10
  /** Those of {@link MS_FONT_NAMES} whose entry has a `<bold>` element. A family in the
11
11
  * registry without one has no bold face of its own (Franklin Gothic Book), which is what
12
12
  * `Mapper.hasBoldFace` answers on. */
13
- export const MS_FONTS_WITH_BOLD = ["Arial", "Comic Sans MS", "Courier New", "Georgia", "Times New Roman", "Trebuchet MS", "Verdana", "Segoe UI", "Tahoma", "Calibri", "Cambria", "Candara", "Consolas", "Constantia", "Corbel", "Palatino Linotype", "Arial Narrow", "Bell MT", "Berlin Sans FB", "Bookman Old Style", "Californian FB", "Cambria Math", "Century Gothic", "Garamond", "Lucida Bright", "Lucida Fax", "Lucida Sans", "Malgun Gothic", "Nina", "Liberation Serif", "Liberation Sans", "Liberation Mono", "Noto Sans Symbols Regular", "DejaVu Serif", "Franklin Gothic Demi", "Rockwell", "Carlito Regular", "Caladea Regular", "Cousine Regular", "Arimo Regular", "Tinos Regular"];
13
+ export const MS_FONTS_WITH_BOLD = ["Arial", "Comic Sans MS", "Courier New", "Georgia", "Times New Roman", "Trebuchet MS", "Verdana", "Segoe UI", "Tahoma", "Calibri", "Cambria", "Candara", "Consolas", "Constantia", "Corbel", "Palatino Linotype", "Arial Narrow", "Bell MT", "Berlin Sans FB", "Book Antiqua", "Bookman Old Style", "Californian FB", "Cambria Math", "Century Gothic", "Garamond", "Lucida Bright", "Lucida Fax", "Lucida Sans", "Malgun Gothic", "Nina", "Liberation Serif", "Liberation Sans", "Liberation Mono", "Noto Sans Symbols Regular", "DejaVu Serif", "Franklin Gothic Demi", "Rockwell", "Carlito Regular", "Caladea Regular", "Cousine Regular", "Arimo Regular", "Tinos Regular"];
14
14
  /** The families `word-line-metrics.properties` holds, lower-cased. */
15
15
  export const LINE_METRIC_FAMILIES = ["abhaya libre", "agency fb", "aharoni", "algerian", "aller", "aller light", "amasis mt pro", "amasis mt pro black", "amasis mt pro medium", "amienne", "angsana new", "aptos", "aptos display", "aptos light", "aptos narrow", "archivo narrow", "arial", "arial black", "arial narrow", "arial nova", "arial nova cond", "arial nova light", "arial rounded mt bold", "arial unicode ms", "arnprior", "avenir next lt pro", "avenir next lt pro light", "bahnschrift", "barlow", "barts and the london logo", "baskerville old face", "batang", "batangche", "bauhaus 93", "baveuse", "bell mt", "bella donna", "bembo", "berlin sans fb", "berlin sans fb demi", "bernard mt condensed", "berylium", "bierstadt", "biondi", "blackadder itc", "blue highway", "blue highway condensed", "blue highway d type", "blue highway linocut", "bodoni mt", "bodoni mt black", "bodoni mt condensed", "bodoni mt poster compressed", "book antiqua", "bookman old style", "bookshelf symbol 7", "boopee", "bradley hand itc", "britannic bold", "broadway", "brush script mt", "burnstown dam", "buxton sketch", "byington", "calibri", "calibri light", "californian fb", "calisto mt", "cambria", "cambria math", "candara", "candara light", "carbon block", "carlito", "castellar", "catholicschoolgirls intl bb", "catriel", "cavolini", "centaur", "century", "century gothic", "century schoolbook", "chiller", "colonna mt", "comic sans ms", "consolas", "constantia", "cooper black", "copperplate gothic bold", "copperplate gothic light", "corbel", "corbel light", "cordia new", "courier new", "credit valley", "curlz mt", "dante", "dejavu sans", "dengxian", "dengxian light", "dokchampa", "dotum", "dotumche", "dubai", "dubai light", "dubai medium", "earwig factory", "ebrima", "edwardian script itc", "elephant", "engravers mt", "eras bold itc", "eras demi itc", "eras light itc", "eras medium itc", "euclid", "euclid extra", "euclid fraktur", "euclid math one", "euclid math two", "euclid symbol", "euphorigenic s", "felix titling", "fences", "fira sans", "footlight mt light", "forte", "franklin gothic book", "franklin gothic demi", "franklin gothic demi cond", "franklin gothic heavy", "franklin gothic medium", "franklin gothic medium cond", "free 3 of 9", "free 3 of 9 extended", "freestyle script", "french script mt", "gabriola", "gadugi", "garamond", "gautami", "geeznewa", "georgia", "georgia pro", "georgia pro cond black", "georgia pro cond light", "georgia pro light", "georgia pro semibold", "gigi", "gill sans mt", "gill sans mt condensed", "gill sans mt ext condensed bold", "gill sans nova", "gill sans ultra bold", "gill sans ultra bold condensed", "gloucester mt extra condensed", "goudy old style", "goudy stout", "grad", "grandview", "grandview display", "gulim", "gulimche", "gungsuh", "gungsuhche", "haettenschweiler", "harlow solid italic", "harrington", "heavy heap", "hggothice", "hggothicm", "hggyoshotai", "hgkyokashotai", "hgmarugothicmpro", "hgminchob", "hgminchoe", "hgpgothice", "hgpgothicm", "hgpgyoshotai", "hgpkyokashotai", "hgpminchob", "hgpminchoe", "hgpsoeikakugothicub", "hgpsoeikakupoptai", "hgpsoeipresenceeb", "hgseikaishotaipro", "hgsgothice", "hgsgothicm", "hgsgyoshotai", "hgskyokashotai", "hgsminchob", "hgsminchoe", "hgsoeikakugothicub", "hgsoeikakupoptai", "hgsoeipresenceeb", "hgssoeikakugothicub", "hgssoeikakupoptai", "hgssoeipresenceeb", "high tower text", "hololens mdl2 assets", "hp simplified", "hp simplified light", "hurry up", "huxtable", "impact", "imprint mt shadow", "informal roman", "ink free", "iskoola pota", "javanese text", "jokerman", "juice itc", "kaiti", "kredit", "kristen itc", "kunstler script", "latha", "leelawadee ui", "leelawadee ui semilight", "liberation sans", "liberation serif", "ligurino", "ligurino condensed", "lucida bright", "lucida calligraphy", "lucida console", "lucida fax", "lucida handwriting", "lucida sans", "lucida sans typewriter", "lucida sans unicode", "magneto", "maiandra gd", "malgun gothic", "malgun gothic semilight", "mangal", "marlett", "matura mt script capitals", "meiryo", "merriweather", "microsoft gothicneo", "microsoft himalaya", "microsoft jhenghei", "microsoft jhenghei ui", "microsoft mhei", "microsoft neogothic", "microsoft new tai lue", "microsoft phagspa", "microsoft sans serif", "microsoft tai le", "microsoft yahei", "microsoft yahei ui", "microsoft yi baiti", "mingliu", "mingliu-extb", "mingliu_hkscs-extb", "minya nouvelle", "mistral", "modern love", "modern no. 20", "mongolian baiti", "monotype corsiva", "montserrat", "ms gothic", "ms mincho", "ms outlook", "ms pgothic", "ms pmincho", "ms reference sans serif", "ms reference specialty", "ms ui gothic", "mt extra", "mt extra tiger", "mufferaw", "mv boli", "myanmar text", "neue haas grotesk text pro", "neuropol", "niagara engraved", "niagara solid", "nimbus sans narrow", "nina", "nirmala ui", "nirmala ui semilight", "noto sans", "noto sans black", "noto sans condensed", "noto sans condensed black", "noto sans condensed extrabold", "noto sans condensed extralight", "noto sans condensed light", "noto sans condensed medium", "noto sans condensed semibold", "noto sans condensed thin", "noto sans extrabold", "noto sans extracondensed", "noto sans extracondensed black", "noto sans extracondensed extrabold", "noto sans extracondensed extralight", "noto sans extracondensed light", "noto sans extracondensed medium", "noto sans extracondensed semibold", "noto sans extracondensed thin", "noto sans extralight", "noto sans light", "noto sans medium", "noto sans semibold", "noto sans semicondensed", "noto sans semicondensed black", "noto sans semicondensed extrabold", "noto sans semicondensed extralight", "noto sans semicondensed light", "noto sans semicondensed medium", "noto sans semicondensed semibold", "noto sans semicondensed thin", "noto sans sinhala", "noto sans sinhala blk", "noto sans sinhala cond", "noto sans sinhala cond blk", "noto sans sinhala cond extbd", "noto sans sinhala cond extlt", "noto sans sinhala cond light", "noto sans sinhala cond med", "noto sans sinhala cond sembd", "noto sans sinhala cond thin", "noto sans sinhala extbd", "noto sans sinhala extcond", "noto sans sinhala extcond blk", "noto sans sinhala extcond extbd", "noto sans sinhala extcond extlt", "noto sans sinhala extcond light", "noto sans sinhala extcond med", "noto sans sinhala extcond sembd", "noto sans sinhala extcond thin", "noto sans sinhala extlt", "noto sans sinhala light", "noto sans sinhala med", "noto sans sinhala sembd", "noto sans sinhala semcond", "noto sans sinhala semcond blk", "noto sans sinhala semcond extbd", "noto sans sinhala semcond extlt", "noto sans sinhala semcond light", "noto sans sinhala semcond med", "noto sans sinhala semcond sembd", "noto sans sinhala semcond thin", "noto sans sinhala thin", "noto sans sinhala ui", "noto sans symbols", "noto sans thin", "noto serif sinhala", "noto serif sinhala black", "noto serif sinhala condensed", "noto serif sinhala condensed black", "noto serif sinhala condensed extrabold", "noto serif sinhala condensed extralight", "noto serif sinhala condensed light", "noto serif sinhala condensed medium", "noto serif sinhala condensed semibold", "noto serif sinhala condensed thin", "noto serif sinhala extrabold", "noto serif sinhala extracondensed", "noto serif sinhala extracondensed black", "noto serif sinhala extracondensed extrabold", "noto serif sinhala extracondensed extralight", "noto serif sinhala extracondensed light", "noto serif sinhala extracondensed medium", "noto serif sinhala extracondensed semibold", "noto serif sinhala extracondensed thin", "noto serif sinhala extralight", "noto serif sinhala light", "noto serif sinhala medium", "noto serif sinhala semibold", "noto serif sinhala semicondensed", "noto serif sinhala semicondensed black", "noto serif sinhala semicondensed extrabold", "noto serif sinhala semicondensed extralight", "noto serif sinhala semicondensed light", "noto serif sinhala semicondensed medium", "noto serif sinhala semicondensed semibold", "noto serif sinhala semicondensed thin", "noto serif sinhala thin", "nsimsun", "nunito sans", "ocr a extended", "ocrb", "old english text mt", "onyx", "open sans", "oswald", "pacifico", "palace script mt", "palatino linotype", "papyrus", "parchment", "perpetua", "perpetua titling mt", "planet benson 2", "playbill", "playfair display", "pmingliu", "pmingliu-extb", "poor richard", "posterama", "pristina", "pupcat", "raavi", "rage italic", "ravie", "roboto", "roboto condensed", "rockwell", "rockwell condensed", "rockwell extra bold", "rockwell nova", "rockwell nova light", "sabon next lt", "sagona", "sagona book", "sagona extralight", "sans serif collection", "script mt bold", "seaford", "seaford display", "segoe marker", "segoe mdl2 assets", "segoe print", "segoe script", "segoe ui", "segoe ui black", "segoe ui emoji", "segoe ui historic", "segoe ui light", "segoe ui semibold", "segoe ui semilight", "segoe ui symbol", "segoe wp", "segoe wp black", "segoe wp light", "segoe wp semibold", "segoe wp semilight", "shell", "showcard gothic", "shruti", "simhei", "simsun", "simsun-extb", "simsun-extg", "sitka", "sketchflow print", "snap itc", "source han serif cn", "source sans pro", "source sans pro semibold", "speak pro", "srisakdi", "stencil", "stereofidelic", "stzhongsong", "sybil green", "sylfaen", "symbol", "symbol tiger", "symbol tiger expert", "tahoma", "tandelle", "teen", "teen light", "tempus sans itc", "tenorite", "the hand", "the hand extrablack", "the serif hand", "the serif hand black", "think nothing", "tiger expert", "times new roman", "trade gothic next", "trade gothic next cond", "trade gothic next light", "trebuchet ms", "tunga", "tw cen mt", "tw cen mt condensed", "tw cen mt condensed extra bold", "ubuntu", "univers", "univers condensed", "univers condensed light", "univers light", "velvenda cooler", "verdana", "verdana pro", "verdana pro cond semibold", "vijaya", "viner hand itc", "vivaldi", "vladimir script", "waker", "walbaum", "walbaum display", "walbaum display light", "webdings", "wickenden cafe ndp", "wide latin", "wingdings", "wingdings 2", "wingdings 3", "yu gothic", "yu gothic ui", "yu mincho", "yu mincho demibold"];
16
16
  /** Those of {@link LINE_METRIC_FAMILIES} the table's optional field 7 flags East Asian. */
@@ -46,7 +46,9 @@ export const EMPTY_FONT_REGISTRY = new SimpleFontRegistry();
46
46
  * classpath): Liberation's croscore metric clones, crosextra's Carlito and Caladea, the
47
47
  * theme2023 stand-ins for Word 365's Aptos, and the symbol jar's DejaVu Serif and Noto
48
48
  * Sans Symbols. This is the environment CR-016 phase 0c measured and the parity goldens
49
- * record, so the default mapping here is reproducible against them.
49
+ * record, so the default mapping here is reproducible against them. The four Intos Narrow faces,
50
+ * theme2023's stand-in for Aptos Narrow, came with docx4j 17.3.3 (`1af3088b3`); their names are
51
+ * the name table's full name and family, laid out as Intos Display's are.
50
52
  */
51
53
  const JAR_FONTS = [
52
54
  ['Akasia Black', 'Akasia'],
@@ -85,6 +87,10 @@ const JAR_FONTS = [
85
87
  ['Intos Display Bold Italic', 'Intos Display'],
86
88
  ['Intos Display Italic', 'Intos Display'],
87
89
  ['Intos Display Regular', 'Intos Display'],
90
+ ['Intos Narrow Bold', 'Intos Narrow'],
91
+ ['Intos Narrow Bold Italic', 'Intos Narrow'],
92
+ ['Intos Narrow Italic', 'Intos Narrow'],
93
+ ['Intos Narrow Regular', 'Intos Narrow'],
88
94
  ['Noto Sans Symbols 2 Regular', 'Noto Sans Symbols 2'],
89
95
  ['Noto Sans Symbols Bold', 'Noto Sans Symbols'],
90
96
  ['Noto Sans Symbols Regular', 'Noto Sans Symbols'],