reamkit 1.30.0 → 1.31.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 (78) hide show
  1. package/README.md +60 -24
  2. package/dist/esm/core/converter/project.js +3 -1
  3. package/dist/esm/core/crypto/offcrypto.js +1 -1
  4. package/dist/esm/core/document-model/index.d.ts +1 -1
  5. package/dist/esm/core/document-model/types.d.ts +63 -0
  6. package/dist/esm/core/font/index.d.ts +2 -0
  7. package/dist/esm/core/font/ttf-build.d.ts +113 -0
  8. package/dist/esm/core/font/ttf-build.js +1224 -0
  9. package/dist/esm/core/font/ttf-subset.d.ts +19 -0
  10. package/dist/esm/core/font/ttf-subset.js +14 -1
  11. package/dist/esm/core/fonts/provider.d.ts +17 -0
  12. package/dist/esm/core/fonts/provider.js +27 -2
  13. package/dist/esm/core/fonts/remote-fonts.js +8 -1
  14. package/dist/esm/core/ir/flow.d.ts +71 -1
  15. package/dist/esm/core/numbering/index.d.ts +1 -1
  16. package/dist/esm/core/numbering/state.d.ts +11 -1
  17. package/dist/esm/core/numbering/state.js +10 -1
  18. package/dist/esm/core/style-cascade/resolver.js +35 -4
  19. package/dist/esm/core/style-cascade/types.d.ts +19 -1
  20. package/dist/esm/core/style-cascade/types.js +3 -0
  21. package/dist/esm/index.d.ts +2 -2
  22. package/dist/esm/layout/page-doc.d.ts +10 -3
  23. package/dist/esm/layout/styled-layout.d.ts +48 -7
  24. package/dist/esm/layout/styled-layout.js +881 -119
  25. package/dist/esm/layout/turned-section.d.ts +38 -0
  26. package/dist/esm/layout/turned-section.js +193 -0
  27. package/dist/esm/pdf/styled-page-emitter.js +78 -2
  28. package/dist/esm/pdf-reader/cff-outline.d.ts +27 -0
  29. package/dist/esm/pdf-reader/cff-outline.js +169 -21
  30. package/dist/esm/pdf-reader/content.d.ts +53 -0
  31. package/dist/esm/pdf-reader/content.js +9 -1
  32. package/dist/esm/pdf-reader/display.d.ts +36 -0
  33. package/dist/esm/pdf-reader/display.js +66 -1
  34. package/dist/esm/pdf-reader/document.js +5 -1
  35. package/dist/esm/pdf-reader/embedded-fonts.d.ts +2 -1
  36. package/dist/esm/pdf-reader/embedded-fonts.js +32 -2
  37. package/dist/esm/pdf-reader/encodings.d.ts +8 -0
  38. package/dist/esm/pdf-reader/encodings.js +25 -3
  39. package/dist/esm/pdf-reader/face-outlines.d.ts +78 -0
  40. package/dist/esm/pdf-reader/face-outlines.js +362 -0
  41. package/dist/esm/pdf-reader/figures.d.ts +52 -0
  42. package/dist/esm/pdf-reader/figures.js +433 -0
  43. package/dist/esm/pdf-reader/flow-build.d.ts +131 -5
  44. package/dist/esm/pdf-reader/flow-build.js +345 -26
  45. package/dist/esm/pdf-reader/font.js +321 -36
  46. package/dist/esm/pdf-reader/glyf-outline.d.ts +33 -0
  47. package/dist/esm/pdf-reader/glyf-outline.js +135 -1
  48. package/dist/esm/pdf-reader/glyph-names.js +154 -1
  49. package/dist/esm/pdf-reader/layout.d.ts +93 -0
  50. package/dist/esm/pdf-reader/layout.js +1703 -214
  51. package/dist/esm/pdf-reader/page-numbers.d.ts +53 -0
  52. package/dist/esm/pdf-reader/page-numbers.js +167 -0
  53. package/dist/esm/pdf-reader/tagged.js +182 -23
  54. package/dist/esm/pdf-reader/text.d.ts +6 -3
  55. package/dist/esm/pdf-reader/text.js +98 -9
  56. package/dist/esm/pdf-reader/type1-outline.d.ts +11 -0
  57. package/dist/esm/pdf-reader/type1-outline.js +63 -8
  58. package/dist/esm/pdf-reader/vector.js +71 -1
  59. package/dist/esm/word/doc/doc-reader.js +6 -2
  60. package/dist/esm/word/doc/doc-text.d.ts +6 -0
  61. package/dist/esm/word/doc/doc-text.js +19 -1
  62. package/dist/esm/word/document-parser.d.ts +2 -2
  63. package/dist/esm/word/document-parser.js +11 -1
  64. package/dist/esm/word/docx-reader.js +5 -3
  65. package/dist/esm/word/docx-writer.js +207 -21
  66. package/dist/esm/word/drawing-parser.d.ts +5 -3
  67. package/dist/esm/word/drawing-parser.js +49 -8
  68. package/dist/esm/word/font-embed.d.ts +30 -0
  69. package/dist/esm/word/font-embed.js +173 -0
  70. package/dist/esm/word/font-table.d.ts +10 -0
  71. package/dist/esm/word/font-table.js +13 -1
  72. package/dist/esm/word/index.js +1 -1
  73. package/dist/esm/word/numbering-parser.d.ts +3 -1
  74. package/dist/esm/word/numbering-parser.js +2 -1
  75. package/dist/esm/word/paragraph-properties.d.ts +7 -6
  76. package/dist/esm/word/paragraph-properties.js +14 -2
  77. package/dist/esm/word/run-properties.js +26 -0
  78. package/package.json +8 -3
@@ -6,6 +6,7 @@ import { buildOpcPackage } from "../core/opc/opc-writer.js";
6
6
  import "../core/opc/index.js";
7
7
  import { omathXml } from "./omml-serializer.js";
8
8
  import { chartSpaceXml } from "../core/drawingml/chart-serializer.js";
9
+ import { OBFUSCATED_FONT_CONTENT_TYPE, embedFaces } from "./font-embed.js";
9
10
  //#region src/word/docx-writer.ts
10
11
  var encoder = new TextEncoder();
11
12
  var DEFAULT_RUN = resolveRunProperties({}, {}, EMPTY_STYLE_SHEET);
@@ -20,6 +21,12 @@ var NUMBERING_PART = "word/numbering.xml";
20
21
  var REL_FONT_TABLE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
21
22
  var FONT_TABLE_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml";
22
23
  var FONT_TABLE_PART = "word/fontTable.xml";
24
+ var REL_SETTINGS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
25
+ var SETTINGS_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml";
26
+ var SETTINGS_PART = "word/settings.xml";
27
+ var REL_STYLES = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
28
+ var STYLES_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml";
29
+ var STYLES_PART = "word/styles.xml";
23
30
  var REL_FOOTNOTES = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
24
31
  var REL_ENDNOTES = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes";
25
32
  var FOOTNOTES_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml";
@@ -33,6 +40,20 @@ var REL_COMMENTS_EXTENDED = "http://schemas.microsoft.com/office/2011/relationsh
33
40
  var COMMENTS_EXTENDED_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml";
34
41
  var COMMENTS_EXTENDED_PART = "word/commentsExtended.xml";
35
42
  var W14_NS = "http://schemas.microsoft.com/office/word/2010/wordml";
43
+ var MC_NS = "http://schemas.openxmlformats.org/markup-compatibility/2006";
44
+ /**
45
+ * The namespaces a part's root declares: WordprocessingML's and the
46
+ * relationships', and — where the part uses one — Word 2010's `w14`, which a
47
+ * reader that does not know it is told to pass over (ECMA-376 Part 3
48
+ * `mc:Ignorable`) rather than to refuse the file.
49
+ *
50
+ * @param inner The part's content, to see whether it uses `w14`.
51
+ * @returns The attributes, each with its leading space.
52
+ */
53
+ function rootNamespaces(inner) {
54
+ const base = " xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"";
55
+ return inner.includes("<w14:") ? `${base} xmlns:w14="${W14_NS}" xmlns:mc="${MC_NS}" mc:Ignorable="w14"` : base;
56
+ }
36
57
  var W15_NS = "http://schemas.microsoft.com/office/word/2012/wordml";
37
58
  var REL_CHART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
38
59
  var CHART_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml";
@@ -133,6 +154,8 @@ function writeDocx(flow) {
133
154
  ...flow.charts ? { charts: flow.charts } : {},
134
155
  ...flow.faceFamilies ? { faceFamilies: flow.faceFamilies } : {},
135
156
  familiesUsed: /* @__PURE__ */ new Map(),
157
+ ...flow.faceOutlines ? { faceOutlines: flow.faceOutlines } : {},
158
+ facesUsed: /* @__PURE__ */ new Set(),
136
159
  zRanks: zRanksOf(flow)
137
160
  };
138
161
  const docScope = newScope();
@@ -153,7 +176,8 @@ function writeDocx(flow) {
153
176
  });
154
177
  emitBody(body, flow.body, losses, state, docScope, sectPrByClosingIndex);
155
178
  if (finalSectPr) body.push(finalSectPr);
156
- const documentXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><w:body>${body.join("")}</w:body></w:document>`;
179
+ const bodyXml = body.join("");
180
+ const documentXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:document${rootNamespaces(bodyXml)}><w:body>${bodyXml}</w:body></w:document>`;
157
181
  const numberingPart = flow.body.some((el) => el.kind === "paragraph" && el.paragraph.properties.numbering !== void 0) && flow.numbering ? {
158
182
  path: NUMBERING_PART,
159
183
  data: encoder.encode(numberingXml(flow.numbering)),
@@ -185,9 +209,14 @@ function writeDocx(flow) {
185
209
  }, state, losses, docScope, extraParts, extraPartRels);
186
210
  const commentParaIds = emitComments(flow.comments, state, losses, docScope, extraParts, extraPartRels);
187
211
  emitCommentsExtended(flow.comments, commentParaIds, docScope, extraParts);
212
+ const embedded = state.faceOutlines && state.faceFamilies ? embedFaces(state.facesUsed, state.faceOutlines, state.faceFamilies, losses) : void 0;
213
+ if (embedded && embedded.relationships.length > 0) extraPartRels.push({
214
+ sourcePart: FONT_TABLE_PART,
215
+ relationships: [...embedded.relationships]
216
+ });
188
217
  const fontTablePart = state.familiesUsed.size > 0 ? {
189
218
  path: FONT_TABLE_PART,
190
- data: encoder.encode(fontTableXml(state.familiesUsed)),
219
+ data: encoder.encode(fontTableXml(state.familiesUsed, embedded?.elements)),
191
220
  contentType: FONT_TABLE_CONTENT_TYPE
192
221
  } : void 0;
193
222
  if (fontTablePart) docScope.rels.push({
@@ -196,6 +225,29 @@ function writeDocx(flow) {
196
225
  target: "fontTable.xml",
197
226
  targetMode: "Internal"
198
227
  });
228
+ const settings = settingsXml(flow, sections, (embedded?.parts.length ?? 0) > 0);
229
+ const settingsPart = settings !== void 0 ? {
230
+ path: SETTINGS_PART,
231
+ data: encoder.encode(settings),
232
+ contentType: SETTINGS_CONTENT_TYPE
233
+ } : void 0;
234
+ if (settingsPart) docScope.rels.push({
235
+ id: `rId${++docScope.relSeq}`,
236
+ type: REL_SETTINGS,
237
+ target: "settings.xml",
238
+ targetMode: "Internal"
239
+ });
240
+ const stylesPart = {
241
+ path: STYLES_PART,
242
+ data: encoder.encode(stylesXml()),
243
+ contentType: STYLES_CONTENT_TYPE
244
+ };
245
+ docScope.rels.push({
246
+ id: `rId${++docScope.relSeq}`,
247
+ type: REL_STYLES,
248
+ target: "styles.xml",
249
+ targetMode: "Internal"
250
+ });
199
251
  const partRelationships = [...docScope.rels.length > 0 ? [{
200
252
  sourcePart: "word/document.xml",
201
253
  relationships: docScope.rels
@@ -208,12 +260,16 @@ function writeDocx(flow) {
208
260
  data: encoder.encode(documentXml),
209
261
  contentType: DOC_CONTENT_TYPE
210
262
  },
263
+ stylesPart,
211
264
  ...numberingPart ? [numberingPart] : [],
212
265
  ...fontTablePart ? [fontTablePart] : [],
266
+ ...settingsPart ? [settingsPart] : [],
213
267
  ...extraParts,
214
268
  ...state.chartParts,
215
- ...state.mediaParts
269
+ ...state.mediaParts,
270
+ ...embedded?.parts ?? []
216
271
  ],
272
+ ...(embedded?.parts.length ?? 0) > 0 ? { defaultsByExtension: { odttf: OBFUSCATED_FONT_CONTENT_TYPE } } : {},
217
273
  rootRelationships: [{
218
274
  id: "rId1",
219
275
  type: REL_OFFICE_DOCUMENT,
@@ -225,8 +281,50 @@ function writeDocx(flow) {
225
281
  losses
226
282
  };
227
283
  }
228
- function fontTableXml(families) {
229
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:fonts xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">${[...families.values()].map((f) => `<w:font w:name="${escapeAttr(f.family)}"><w:family w:val="${f.generic}"/><w:pitch w:val="${f.generic === "modern" ? "fixed" : "variable"}"/></w:font>`).join("")}</w:fonts>`;
284
+ /**
285
+ * §17.15.1.78 `w:settings` — the document-wide settings the model carries, in
286
+ * the order CT_Settings declares them: `w:embedTrueTypeFonts` and
287
+ * `w:saveSubsetFonts` (§17.15.1.42, .74) where the package embeds its faces,
288
+ * `w:gutterAtTop` (§17.15.1.49), `w:evenAndOddHeaders` (§17.15.1.36, which a
289
+ * section carries in the model), and inside `w:compat` §17.15.3.4's
290
+ * `w:doNotExpandShiftReturn` before the version of Word the document is laid
291
+ * out for ([MS-DOCX] `w:compatSetting` `compatibilityMode`), which CT_Compat
292
+ * keeps last.
293
+ *
294
+ * @param flow The document.
295
+ * @param sections The sections being written.
296
+ * @param embedsFonts Whether the package embeds fonts — which then stay
297
+ * embedded, as subsets, when the document is saved again.
298
+ * @returns The part's XML, or undefined where the document states none.
299
+ */
300
+ function settingsXml(flow, sections, embedsFonts) {
301
+ const parts = [];
302
+ if (embedsFonts) parts.push("<w:embedTrueTypeFonts/><w:saveSubsetFonts/>");
303
+ if (flow.gutterAtTop === true) parts.push("<w:gutterAtTop/>");
304
+ if (sections.some((sec) => sec.properties.evenAndOddHeaders === true)) parts.push("<w:evenAndOddHeaders/>");
305
+ const compat = [...flow.doNotExpandShiftReturn === true ? ["<w:doNotExpandShiftReturn/>"] : [], ...flow.compatibilityMode !== void 0 ? [`<w:compatSetting w:name="compatibilityMode" w:uri="http://schemas.microsoft.com/office/word" w:val="${String(flow.compatibilityMode)}"/>`] : []];
306
+ if (compat.length > 0) parts.push(`<w:compat>${compat.join("")}</w:compat>`);
307
+ if (parts.length === 0) return void 0;
308
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">${parts.join("")}</w:settings>`;
309
+ }
310
+ /**
311
+ * §17.7.2 `w:styles` — what a property the document states nowhere IS: the
312
+ * values the model resolves an empty sheet to (`DEFAULT_RUN`, `DEFAULT_PARA`
313
+ * — the very values a run or paragraph is written without), as §17.7.5
314
+ * `w:docDefaults`, under an empty default paragraph style (§17.7.4.17).
315
+ *
316
+ * A package with no styles part leaves them to its reader, and Word fills
317
+ * them from its own template's Normal: 8pt after every paragraph, lines 1.08
318
+ * apart, runs in 12pt — so every paragraph of a reconstruction stood 8pt
319
+ * further down than its page set it, and a run of the model's own 11pt, which
320
+ * states no size, was set in 12.
321
+ */
322
+ function stylesXml() {
323
+ const size = Math.round(DEFAULT_RUN.fontSizePt * 2);
324
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:docDefaults><w:rPrDefault><w:rPr><w:sz w:val="${size}"/><w:szCs w:val="${size}"/></w:rPr></w:rPrDefault><w:pPrDefault><w:pPr>${DEFAULT_PARA.widowControl ? "<w:widowControl/>" : "<w:widowControl w:val=\"0\"/>"}${`<w:spacing w:before="${twips(DEFAULT_PARA.spacingBefore)}" w:after="${twips(DEFAULT_PARA.spacingAfter)}" w:line="${twips(DEFAULT_PARA.spacingLine)}" w:lineRule="${DEFAULT_PARA.spacingLineRule}"/>`}</w:pPr></w:pPrDefault></w:docDefaults><w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/></w:style></w:styles>`;
325
+ }
326
+ function fontTableXml(families, embeds) {
327
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:fonts xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">${[...families.values()].map((f) => `<w:font w:name="${escapeAttr(f.family)}"><w:family w:val="${f.generic}"/><w:pitch w:val="${f.generic === "modern" ? "fixed" : "variable"}"/>${embeds?.get(f.family) ?? ""}</w:font>`).join("")}</w:fonts>`;
230
328
  }
231
329
  /**
232
330
  * §20.4.2.3 `relativeHeight` — a float's z-order, written the way Word writes
@@ -277,7 +375,8 @@ function emitNotes(notes, cfg, state, losses, docScope, extraParts, extraPartRel
277
375
  for (const el of content) emitBlock(inner, el, losses, state, scope);
278
376
  noteXmls.push(`<${cfg.noteTag} w:id="${escapeAttr(id)}">${inner.join("") || "<w:p/>"}</${cfg.noteTag}>`);
279
377
  }
280
- const xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><${cfg.rootTag} xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">` + stub("separator", -1, "<w:separator/>") + stub("continuationSeparator", 0, "<w:continuationSeparator/>") + noteXmls.join("") + `</${cfg.rootTag}>`;
378
+ const notesXml = noteXmls.join("");
379
+ const xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><${cfg.rootTag}${rootNamespaces(notesXml)}>` + stub("separator", -1, "<w:separator/>") + stub("continuationSeparator", 0, "<w:continuationSeparator/>") + notesXml + `</${cfg.rootTag}>`;
281
380
  extraParts.push({
282
381
  path: cfg.partPath,
283
382
  data: encoder.encode(xml),
@@ -383,7 +482,8 @@ function emitHeadersFooters(flow, section, state, docScope, extraParts, extraPar
383
482
  const scope = newScope();
384
483
  const inner = [];
385
484
  for (const el of content) emitBlock(inner, el, losses, state, scope);
386
- const xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><${root} xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">${inner.join("")}</${root}>`;
485
+ const bandXml = inner.join("");
486
+ const xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><${root}${rootNamespaces(bandXml)}>${bandXml}</${root}>`;
387
487
  extraParts.push({
388
488
  path,
389
489
  data: encoder.encode(xml),
@@ -427,7 +527,7 @@ function emitHeadersFooters(flow, section, state, docScope, extraParts, extraPar
427
527
  var docxWriter = {
428
528
  id: "docx",
429
529
  consumes: "flow",
430
- supports: new Set([FEATURES.text]),
530
+ supports: new Set([FEATURES.text, FEATURES.fontsEmbedding]),
431
531
  write: (doc) => writeDocx(doc)
432
532
  };
433
533
  /**
@@ -636,13 +736,76 @@ function shapeDrawingXml(shape, losses, state, scope) {
636
736
  const cy = Math.round(shape.height * EMU_PER_PT);
637
737
  const id = ++state.drawingSeq;
638
738
  const descr = shape.altText ? ` descr="${escapeAttr(shape.altText)}"` : "";
639
- const spPr = `<wps:spPr>${xfrmXml(shape.transform, cx, cy)}${geomXml(shape.geometry)}${fillXml(shape.fill)}${shape.line ? lineXml(shape.line) : ""}</wps:spPr>`;
640
- const txbx = shape.text ? txbxXml(shape.text, losses, state, scope) : "";
641
- const graphic = `<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="${WPS_URI}"><wps:wsp xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"><wps:cNvSpPr/>` + spPr + txbx + bodyPrXml(shape.text) + "</wps:wsp></a:graphicData></a:graphic>";
739
+ const members = shape.children ?? [];
740
+ const graphic = "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" + (members.length > 0 ? `<a:graphicData uri="${WPG_URI}">` + groupXml("wpg:wgp", members, {
741
+ x: 0,
742
+ y: 0,
743
+ cx,
744
+ cy
745
+ }, losses, state, scope) : `<a:graphicData uri="${WPS_URI}">` + wspXml(shape, cx, cy, void 0, losses, state, scope)) + "</a:graphicData></a:graphic>";
642
746
  return drawingFrame(shape.float, cx, cy, `<wp:docPr id="${id}" name="Shape ${id}"${descr}/>`, graphic, state, shape.transform?.rotation60k);
643
747
  }
644
- function xfrmXml(t, cx, cy) {
645
- return `<a:xfrm${t?.rotation60k !== void 0 ? ` rot="${t.rotation60k}"` : ""}${t?.flipH ? " flipH=\"1\"" : ""}${t?.flipV ? " flipV=\"1\"" : ""}><a:off x="0" y="0"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm>`;
748
+ /**
749
+ * `wps:wsp` — one shape: its box, geometry, fill and outline, and the text it
750
+ * holds. `id` is its own `wps:cNvPr` inside a group, where the members name
751
+ * themselves; a shape alone is named by the frame's `wp:docPr`.
752
+ */
753
+ function wspXml(shape, cx, cy, member, losses, state, scope) {
754
+ const spPr = `<wps:spPr>${xfrmXml(shape.transform, cx, cy, member)}${geomXml(shape.geometry)}${fillXml(shape.fill)}${shape.line ? lineXml(shape.line) : ""}</wps:spPr>`;
755
+ const txbx = shape.text ? txbxXml(shape.text, losses, state, scope) : "";
756
+ return `<wps:wsp xmlns:wps="${WPS_URI}">` + (member ? `<wps:cNvPr id="${member.id}" name="Shape ${member.id}"/>` : "") + "<wps:cNvSpPr/>" + spPr + txbx + bodyPrXml(shape.text) + "</wps:wsp>";
757
+ }
758
+ var WPG_URI = "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup";
759
+ /**
760
+ * §20.5.2.17 `wpg:wgp` / `wpg:grpSp` — a group: its box, and its members in
761
+ * the order they are painted. The members are placed in a child space the
762
+ * same as the box, so a member's offset from the group's corner is its offset
763
+ * in the file. The inverse of drawing-parser's `groupChildren`.
764
+ *
765
+ * Written as one shape, the group came back an empty box: a figure's paths
766
+ * and labels were thrown away with it.
767
+ */
768
+ function groupXml(tag, members, box, losses, state, scope) {
769
+ return `<${tag}${tag === "wpg:wgp" ? ` xmlns:wpg="${WPG_URI}"` : ""}><wpg:cNvGrpSpPr/><wpg:grpSpPr>${`<a:xfrm><a:off x="${box.x}" y="${box.y}"/><a:ext cx="${box.cx}" cy="${box.cy}"/><a:chOff x="0" y="0"/><a:chExt cx="${box.cx}" cy="${box.cy}"/></a:xfrm>`}</wpg:grpSpPr>${members.map((m) => memberXml(m, losses, state, scope)).join("")}</${tag}>`;
770
+ }
771
+ /**
772
+ * One member of a group: a group of its own, a picture (`pic:pic`, a shape
773
+ * whose fill is the picture — how the reader brings one in), or a shape.
774
+ */
775
+ function memberXml(member, losses, state, scope) {
776
+ const s = member.shape;
777
+ const x = Math.round(member.xPt * EMU_PER_PT);
778
+ const y = Math.round(member.yPt * EMU_PER_PT);
779
+ const cx = Math.round(s.width * EMU_PER_PT);
780
+ const cy = Math.round(s.height * EMU_PER_PT);
781
+ if (s.children !== void 0 && s.children.length > 0) return groupXml("wpg:grpSp", s.children, {
782
+ x,
783
+ y,
784
+ cx,
785
+ cy
786
+ }, losses, state, scope);
787
+ const id = ++state.drawingSeq;
788
+ if (s.fill.kind !== "picture") return wspXml(s, cx, cy, {
789
+ id,
790
+ x,
791
+ y
792
+ }, losses, state, scope);
793
+ const relId = s.fill.imageResource !== void 0 ? mediaRelId(s.fill.imageResource, state, scope) : void 0;
794
+ if (relId === void 0) {
795
+ losses.push({
796
+ severity: "dropped",
797
+ feature: FEATURES.images,
798
+ detail: imageRefusal(s.fill.imageResource, state)
799
+ });
800
+ return "";
801
+ }
802
+ return `<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="${id}" name="Image ${id}"/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip r:embed="${relId}">${s.fill.alpha !== void 0 && s.fill.alpha < 1 ? `<a:alphaModFix amt="${String(Math.round(Math.max(0, s.fill.alpha) * 1e5))}"/>` : ""}</a:blip>${srcRectXml(s.fill.imageCrop)}<a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr>${xfrmXml(s.transform, cx, cy, {
803
+ x,
804
+ y
805
+ })}<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic>`;
806
+ }
807
+ function xfrmXml(t, cx, cy, at) {
808
+ return `<a:xfrm${t?.rotation60k !== void 0 ? ` rot="${t.rotation60k}"` : ""}${t?.flipH ? " flipH=\"1\"" : ""}${t?.flipV ? " flipV=\"1\"" : ""}><a:off x="${at?.x ?? 0}" y="${at?.y ?? 0}"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm>`;
646
809
  }
647
810
  /**
648
811
  * The factor that carries a path into whole units, and the space it lands in.
@@ -668,7 +831,7 @@ function pathScale(g) {
668
831
  else if (c.cmd === "quad") values.push(c.x1, c.y1, c.x, c.y);
669
832
  else if (c.cmd === "arc") values.push(c.wR, c.hR);
670
833
  if (values.every((v) => Number.isInteger(v))) return 1;
671
- const span = Math.max(...values.map((v) => Number.isFinite(v) ? Math.abs(v) : 0), 1);
834
+ const span = values.reduce((most, v) => Number.isFinite(v) ? Math.max(most, Math.abs(v)) : most, 1);
672
835
  return Math.max(1, Math.floor(PATH_SPACE / span));
673
836
  }
674
837
  function geomXml(g) {
@@ -736,7 +899,7 @@ function bodyPrXml(text) {
736
899
  if (!text) return "<wps:bodyPr/>";
737
900
  const ins = (v, name) => v !== void 0 ? ` ${name}="${Math.round(v * EMU_PER_PT)}"` : "";
738
901
  const anchor = text.anchor ? ` anchor="${text.anchor}"` : "";
739
- return "<wps:bodyPr" + ins(text.insetLeft, "lIns") + ins(text.insetTop, "tIns") + ins(text.insetRight, "rIns") + ins(text.insetBottom, "bIns") + anchor + "/>";
902
+ return "<wps:bodyPr" + (text.noWrap === true ? " wrap=\"none\"" : "") + ins(text.insetLeft, "lIns") + ins(text.insetTop, "tIns") + ins(text.insetRight, "rIns") + ins(text.insetBottom, "bIns") + anchor + "/>";
740
903
  }
741
904
  function mediaRelId(resource, state, scope) {
742
905
  const existingRel = scope.relIdByResource.get(resource);
@@ -787,6 +950,7 @@ function tblPrXml(p) {
787
950
  out.push(`<w:tblW w:w="${w}" w:type="${p.widthType}"/>`);
788
951
  }
789
952
  if (p.alignment && p.alignment !== "left") out.push(`<w:jc w:val="${p.alignment}"/>`);
953
+ if (p.indentPt !== void 0 && p.indentPt !== 0) out.push(`<w:tblInd w:w="${twips(p.indentPt)}" w:type="dxa"/>`);
790
954
  const borders = bordersXml("w:tblBorders", p.borders);
791
955
  if (borders) out.push(borders);
792
956
  if (p.layout === "fixed") out.push("<w:tblLayout w:type=\"fixed\"/>");
@@ -839,11 +1003,14 @@ function bordersXml(tag, borders) {
839
1003
  if (tag === "w:pBdr" && key === "insideV") return "";
840
1004
  const el = tag === "w:pBdr" && key === "insideH" ? "w:between" : name;
841
1005
  const sz = b.width !== void 0 ? ` w:sz="${Math.round(b.width * 8)}"` : "";
1006
+ const space = b.spacePt !== void 0 && Math.round(b.spacePt) > 0 ? ` w:space="${Math.min(Math.round(b.spacePt), MOST_BORDER_SPACE_PT)}"` : "";
842
1007
  const color = b.colorHex !== void 0 ? ` w:color="${b.colorHex}"` : "";
843
- return `<${el} w:val="${b.style}"${sz}${color}/>`;
1008
+ return `<${el} w:val="${b.style}"${sz}${space}${color}/>`;
844
1009
  }).join("");
845
1010
  return sides ? `<${tag}>${sides}</${tag}>` : "";
846
1011
  }
1012
+ /** §17.3.4 — the farthest a border may stand off its text, in points. */
1013
+ var MOST_BORDER_SPACE_PT = 31;
847
1014
  function cellMarginsXml(tag, margins) {
848
1015
  if (!margins) return "";
849
1016
  const inner = [
@@ -914,7 +1081,8 @@ function runXml(run, state, scope) {
914
1081
  return piece("<w:fldChar w:fldCharType=\"begin\"/>") + piece(`<w:instrText xml:space="preserve"> ${run.field} </w:instrText>`) + piece("<w:fldChar w:fldCharType=\"separate\"/>") + piece(`<w:t xml:space="preserve">${escapeXml(run.text)}</w:t>`) + piece("<w:fldChar w:fldCharType=\"end\"/>") + brk;
915
1082
  }
916
1083
  if (run.text === "") return brk ? `<w:r>${rPr}${brk}</w:r>` : "";
917
- return `<w:r>${rPr}${run.text.split(" ").map((piece) => piece === "" ? "" : `<w:t xml:space="preserve">${escapeXml(piece)}</w:t>`).join("<w:tab/>")}${brk}</w:r>`;
1084
+ const lineBreak = run.columnBreak ? "<w:br w:type=\"column\"/>" : "<w:br/>";
1085
+ return `<w:r>${rPr}${run.text.split(" ").map((piece) => piece.split("\n").map((line) => line === "" ? "" : `<w:t xml:space="preserve">${escapeXml(line)}</w:t>`).join(lineBreak)).join("<w:tab/>")}${brk}</w:r>`;
918
1086
  }
919
1087
  function rPrXml(r, state) {
920
1088
  const out = [];
@@ -925,6 +1093,15 @@ function rPrXml(r, state) {
925
1093
  if (states("italic")) out.push(toggle("w:i", r.italic), toggle("w:iCs", r.italic));
926
1094
  if (states("strike")) out.push(toggle("w:strike", r.strike));
927
1095
  if (states("colorHex")) out.push(`<w:color w:val="${r.colorHex}"/>`);
1096
+ if (r.letterSpacingPt !== void 0 && r.letterSpacingPt !== 0) {
1097
+ const twips = Math.round(r.letterSpacingPt * 20);
1098
+ if (twips !== 0) out.push(`<w:spacing w:val="${String(twips)}"/>`);
1099
+ }
1100
+ if (r.widthScale !== void 0) {
1101
+ const percent = Math.min(600, Math.max(1, Math.round(r.widthScale * 100)));
1102
+ if (percent !== 100) out.push(`<w:w w:val="${String(percent)}"/>`);
1103
+ }
1104
+ if (r.kerningMinPt !== void 0 && states("kerningMinPt")) out.push(`<w:kern w:val="${Math.round(r.kerningMinPt * 2)}"/>`);
928
1105
  if (states("fontSizePt")) {
929
1106
  const half = Math.round(r.fontSizePt * 2);
930
1107
  out.push(`<w:sz w:val="${half}"/>`, `<w:szCs w:val="${half}"/>`);
@@ -934,6 +1111,7 @@ function rPrXml(r, state) {
934
1111
  if (states("verticalAlign")) out.push(`<w:vertAlign w:val="${r.verticalAlign}"/>`);
935
1112
  if (states("rtl")) out.push(toggle("w:rtl", r.rtl));
936
1113
  if (r.lang !== void 0) out.push(`<w:lang w:val="${escapeAttr(r.lang)}"/>`);
1114
+ if (r.ligatures !== void 0 && states("ligatures")) out.push(`<w14:ligatures w14:val="${r.ligatures}"/>`);
937
1115
  return out.length > 0 ? `<w:rPr>${out.join("")}</w:rPr>` : "";
938
1116
  }
939
1117
  function underlineXml(r) {
@@ -945,10 +1123,14 @@ function runShdXml(fill) {
945
1123
  }
946
1124
  function pPrBody(p) {
947
1125
  const out = [];
1126
+ if (p.keepNext) out.push("<w:keepNext/>");
1127
+ if (p.keepLines) out.push("<w:keepLines/>");
948
1128
  if (p.pageBreakBefore) out.push("<w:pageBreakBefore/>");
1129
+ if (p.widowControl === false) out.push("<w:widowControl w:val=\"0\"/>");
949
1130
  if (p.numbering) out.push(`<w:numPr><w:ilvl w:val="${p.numbering.ilvl}"/><w:numId w:val="${escapeAttr(p.numbering.numId)}"/></w:numPr>`);
950
1131
  const pBdr = bordersXml("w:pBdr", p.borders);
951
1132
  if (pBdr) out.push(pBdr);
1133
+ if (p.shading) out.push(`<w:shd w:val="clear" w:color="auto" w:fill="${p.shading.colorHex}"/>`);
952
1134
  const tabs = p.tabs ?? [];
953
1135
  if (tabs.length > 0) {
954
1136
  const stops = tabs.map((t) => {
@@ -1005,10 +1187,7 @@ function spacingXml(p) {
1005
1187
  const attrs = [];
1006
1188
  if (stated(p.spacingBefore) && p.spacingBefore !== DEFAULT_PARA.spacingBefore) attrs.push(`w:before="${twips(p.spacingBefore)}"`);
1007
1189
  if (stated(p.spacingAfter) && p.spacingAfter !== DEFAULT_PARA.spacingAfter) attrs.push(`w:after="${twips(p.spacingAfter)}"`);
1008
- if ((p.spacingLineRule !== DEFAULT_PARA.spacingLineRule || p.spacingLine !== DEFAULT_PARA.spacingLine) && p.spacingLine > 0) {
1009
- const lineVal = p.spacingLineRule === "auto" ? Math.round(p.spacingLine * 12) : twips(p.spacingLine);
1010
- attrs.push(`w:line="${lineVal}"`, `w:lineRule="${p.spacingLineRule}"`);
1011
- }
1190
+ if ((p.spacingLineRule !== DEFAULT_PARA.spacingLineRule || p.spacingLine !== DEFAULT_PARA.spacingLine) && p.spacingLine > 0) attrs.push(`w:line="${twips(p.spacingLine)}"`, `w:lineRule="${p.spacingLineRule}"`);
1012
1191
  return attrs.length > 0 ? `<w:spacing ${attrs.join(" ")}/>` : "";
1013
1192
  }
1014
1193
  function rFontsXml(fonts, state) {
@@ -1018,6 +1197,7 @@ function rFontsXml(fonts, state) {
1018
1197
  const known = state?.faceFamilies?.get(name);
1019
1198
  if (known === void 0) return name;
1020
1199
  state?.familiesUsed.set(known.family, known);
1200
+ if (state?.faceOutlines?.has(name) === true) state.facesUsed.add(name);
1021
1201
  return known.family;
1022
1202
  };
1023
1203
  const attrs = [];
@@ -1104,8 +1284,14 @@ function sectPrXml(s, hf) {
1104
1284
  const footer = m.footer !== void 0 ? ` w:footer="${twips(m.footer)}"` : "";
1105
1285
  parts.push(`<w:pgMar w:top="${twips(m.top)}" w:right="${twips(m.right)}" w:bottom="${twips(m.bottom)}" w:left="${twips(m.left)}"${header}${footer}/>`);
1106
1286
  }
1287
+ if (s.pageNumberFormat !== void 0 || s.pageNumberStart !== void 0) {
1288
+ const fmt = s.pageNumberFormat !== void 0 ? ` w:fmt="${s.pageNumberFormat}"` : "";
1289
+ const start = s.pageNumberStart !== void 0 ? ` w:start="${String(s.pageNumberStart)}"` : "";
1290
+ parts.push(`<w:pgNumType${fmt}${start}/>`);
1291
+ }
1107
1292
  if (s.columns) parts.push(colsXml(s.columns));
1108
1293
  if (s.titlePg) parts.push("<w:titlePg/>");
1294
+ if (s.textDirection) parts.push(`<w:textDirection w:val="${s.textDirection}"/>`);
1109
1295
  if (parts.length === 0) return "";
1110
1296
  return `<w:sectPr>${parts.join("")}</w:sectPr>`;
1111
1297
  }
@@ -104,7 +104,9 @@ export type DrawingContent = {
104
104
  * ECMA-376 Part 3 (Markup Compatibility) — resolve an `<mc:AlternateContent>` to
105
105
  * the children of the first `<mc:Choice>` whose `Requires` lists only namespaces
106
106
  * we understand, else the `<mc:Fallback>` children, else nothing. (`Requires`
107
- * holds space-separated namespace prefixes as declared in the document.)
107
+ * holds space-separated namespace prefixes as declared in the document.) The
108
+ * elements are known by their local names, whatever prefix the producer bound
109
+ * the namespace to: Word 2008 for Mac wrote `ve:`.
108
110
  *
109
111
  * @param altContent The `mc:AlternateContent` node.
110
112
  * @returns The chosen branch's children.
@@ -126,12 +128,12 @@ export declare function expandMcChildren(children: ReadonlyArray<PoNode>): Array
126
128
  * SmartArt diagram, or — falling through — an embedded picture from
127
129
  * `a:blip @r:embed`.
128
130
  *
129
- * @param drawing The `w:drawing` node.
131
+ * @param drawingNode The `w:drawing` node.
130
132
  * @param resolveColor Resolver for theme/scheme colours used by shape fills/lines.
131
133
  * @param parseBody Optional body parser for a shape's text box (omitted ⇒ no text).
132
134
  * @returns The parsed content, or `null` when no anchor / recognizable graphic is found.
133
135
  */
134
- export declare function parseDrawing(drawing: PoNode, resolveColor: ColorResolver, parseBody?: ParseBody, resolveImage?: (relId: string) => ResourceId | undefined, resolveChartPart?: (relId: string) => string | undefined, themeLineWidths?: ReadonlyArray<number>, themeStyles?: ThemeStyles, parseDrawingText?: ParseDrawingText): DrawingContent | null;
136
+ export declare function parseDrawing(drawingNode: PoNode, resolveColor: ColorResolver, parseBody?: ParseBody, resolveImage?: (relId: string) => ResourceId | undefined, resolveChartPart?: (relId: string) => string | undefined, themeLineWidths?: ReadonlyArray<number>, themeStyles?: ThemeStyles, parseDrawingText?: ParseDrawingText): DrawingContent | null;
135
137
  /**
136
138
  * Parse a legacy `<w:pict>`/`<w:object>` VML picture (ISO/IEC 29500-1 §14, VML
137
139
  * transitional) into an `image` {@link DrawingContent}. Modern files use
@@ -22,8 +22,6 @@ var UNDERSTOOD_NS = new Set([
22
22
  ]);
23
23
  function parseFloatAnchor(anchor) {
24
24
  if (!poIs(anchor, "wp:anchor")) return void 0;
25
- const behindRaw = poAttr(anchor, "behindDoc");
26
- const behind = behindRaw === "1" || behindRaw === "true";
27
25
  let wrap = "none";
28
26
  let wrapSide;
29
27
  for (const child of poChildren(anchor)) {
@@ -35,6 +33,8 @@ function parseFloatAnchor(anchor) {
35
33
  const side = poAttr(child, "wrapText");
36
34
  wrapSide = side === "left" || side === "right" || side === "largest" ? side : "bothSides";
37
35
  }
36
+ const behindRaw = poAttr(anchor, "behindDoc");
37
+ const behind = (behindRaw === "1" || behindRaw === "true") && wrap === "none";
38
38
  const zOrder = poIntAttr(anchor, "relativeHeight");
39
39
  const posH = parseAnchorPos(anchor, "wp:positionH", [
40
40
  "margin",
@@ -163,18 +163,20 @@ function parseAnchorPos(anchor, tag, allowed) {
163
163
  * ECMA-376 Part 3 (Markup Compatibility) — resolve an `<mc:AlternateContent>` to
164
164
  * the children of the first `<mc:Choice>` whose `Requires` lists only namespaces
165
165
  * we understand, else the `<mc:Fallback>` children, else nothing. (`Requires`
166
- * holds space-separated namespace prefixes as declared in the document.)
166
+ * holds space-separated namespace prefixes as declared in the document.) The
167
+ * elements are known by their local names, whatever prefix the producer bound
168
+ * the namespace to: Word 2008 for Mac wrote `ve:`.
167
169
  *
168
170
  * @param altContent The `mc:AlternateContent` node.
169
171
  * @returns The chosen branch's children.
170
172
  */
171
173
  function resolveMc(altContent) {
172
174
  for (const choice of poChildren(altContent)) {
173
- if (!poIs(choice, "mc:Choice")) continue;
175
+ if (!poIsLocal(choice, "Choice")) continue;
174
176
  const requires = (poAttr(choice, "Requires") ?? "").split(/\s+/).filter(Boolean);
175
177
  if (requires.length > 0 && requires.every((r) => UNDERSTOOD_NS.has(r))) return poChildren(choice);
176
178
  }
177
- const fallback = poChildren(altContent).find((c) => poIs(c, "mc:Fallback"));
179
+ const fallback = poChildren(altContent).find((c) => poIsLocal(c, "Fallback"));
178
180
  return fallback ? poChildren(fallback) : [];
179
181
  }
180
182
  /**
@@ -188,22 +190,55 @@ function resolveMc(altContent) {
188
190
  */
189
191
  function expandMcChildren(children) {
190
192
  const out = [];
191
- for (const c of children) if (poIs(c, "mc:AlternateContent")) out.push(...resolveMc(c));
193
+ for (const c of children) if (poIsLocal(c, "AlternateContent")) out.push(...resolveMc(c));
192
194
  else out.push(c);
193
195
  return out;
194
196
  }
195
197
  /**
198
+ * The node with every markup-compatibility block beneath it resolved (see
199
+ * {@link resolveMc}), so that a search through its descendants finds only
200
+ * the content a reader like this one is to take. Bug51170.docx's header offers
201
+ * its logo twice — a PDF for Word for Mac as the Choice, a PNG as the Fallback
202
+ * — and the first `a:blip` in document order was the PDF, which is not a
203
+ * picture a page can show: the logo was left out.
204
+ *
205
+ * @param node The node to resolve.
206
+ * @returns The node itself where nothing beneath it needed resolving.
207
+ */
208
+ function resolveMcTree(node) {
209
+ const tag = poTag(node);
210
+ const children = poChildren(node);
211
+ if (tag === void 0 || children.length === 0) return node;
212
+ let changed = false;
213
+ const resolved = [];
214
+ for (const child of children) {
215
+ if (poIsLocal(child, "AlternateContent")) {
216
+ changed = true;
217
+ for (const chosen of resolveMc(child)) resolved.push(resolveMcTree(chosen));
218
+ continue;
219
+ }
220
+ const inner = resolveMcTree(child);
221
+ if (inner !== child) changed = true;
222
+ resolved.push(inner);
223
+ }
224
+ return changed ? {
225
+ ...node,
226
+ [tag]: resolved
227
+ } : node;
228
+ }
229
+ /**
196
230
  * Parse a `<w:drawing>` (ECMA-376 Part 1 §20) into a {@link DrawingContent}. The
197
231
  * `a:graphicData` `@uri` selects the branch: a `wps:wsp` shape, a chart, a
198
232
  * SmartArt diagram, or — falling through — an embedded picture from
199
233
  * `a:blip @r:embed`.
200
234
  *
201
- * @param drawing The `w:drawing` node.
235
+ * @param drawingNode The `w:drawing` node.
202
236
  * @param resolveColor Resolver for theme/scheme colours used by shape fills/lines.
203
237
  * @param parseBody Optional body parser for a shape's text box (omitted ⇒ no text).
204
238
  * @returns The parsed content, or `null` when no anchor / recognizable graphic is found.
205
239
  */
206
- function parseDrawing(drawing, resolveColor, parseBody, resolveImage, resolveChartPart, themeLineWidths, themeStyles, parseDrawingText) {
240
+ function parseDrawing(drawingNode, resolveColor, parseBody, resolveImage, resolveChartPart, themeLineWidths, themeStyles, parseDrawingText) {
241
+ const drawing = resolveMcTree(drawingNode);
207
242
  const anchor = poChildren(drawing).find((c) => poIs(c, "wp:inline")) ?? poChildren(drawing).find((c) => poIs(c, "wp:anchor"));
208
243
  if (!anchor) return null;
209
244
  const extent = poFindDescendant(anchor, "wp:extent");
@@ -1083,6 +1118,12 @@ function vmlFloat(style, zIndexAttr, shape) {
1083
1118
  const zIndex = prop("z-index") ?? zIndexAttr;
1084
1119
  return {
1085
1120
  wrap: vmlWrap(shape),
1121
+ wrapDist: {
1122
+ topPt: pt(prop("mso-wrap-distance-top") ?? 0),
1123
+ bottomPt: pt(prop("mso-wrap-distance-bottom") ?? 0),
1124
+ leftPt: pt(prop("mso-wrap-distance-left") ?? 9),
1125
+ rightPt: pt(prop("mso-wrap-distance-right") ?? 9)
1126
+ },
1086
1127
  ...poAttrLocal(shape, "allowincell") === "f" ? { inCell: false } : {},
1087
1128
  ...zIndex !== void 0 && zIndex < 0 ? { behind: true } : {},
1088
1129
  ...zIndex !== void 0 ? { zOrder: Math.abs(zIndex) } : {},
@@ -0,0 +1,30 @@
1
+ import { FaceFamily, FaceOutlines } from '../core/ir/flow.js';
2
+ import { Loss } from '../core/ir/index.js';
3
+ import { OpcPart, Relationship } from '../core/opc/index.js';
4
+ /** §17.8.1 — the content type of an obfuscated embedded font. */
5
+ export declare const OBFUSCATED_FONT_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.obfuscatedFont";
6
+ /** The faces written into a package, and how the font table reaches them. */
7
+ export interface EmbeddedFaces {
8
+ /** Family → the `w:embed*` elements its `w:font` carries (§17.8.3.3–6). */
9
+ readonly elements: ReadonlyMap<string, string>;
10
+ /** The obfuscated font parts, under `word/fonts/`. */
11
+ readonly parts: ReadonlyArray<OpcPart>;
12
+ /** The font table's relationships to them. */
13
+ readonly relationships: ReadonlyArray<Relationship>;
14
+ }
15
+ /**
16
+ * Build the embedded fonts for the faces the runs name (§17.8.1).
17
+ *
18
+ * The faces are gathered by family and by slot — the style each face IS. Two
19
+ * faces in one slot (a SemiBold and a Bold, both written bold) become one font:
20
+ * the face with the most characters, and the other's characters it lacks.
21
+ *
22
+ * A face its licence keeps out is reported, not written.
23
+ *
24
+ * @param used The run font names the document's runs carry.
25
+ * @param outlines Run font name → the face's outlines.
26
+ * @param families Run font name → the family a word processor knows it by.
27
+ * @param losses Appended to for every face left out.
28
+ * @returns The fonts to write and the font table's references to them.
29
+ */
30
+ export declare function embedFaces(used: Iterable<string>, outlines: ReadonlyMap<string, FaceOutlines>, families: ReadonlyMap<string, FaceFamily>, losses: Array<Loss>): EmbeddedFaces;