reamkit 1.30.0 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -24
- package/dist/esm/core/bidi/index.d.ts +10 -0
- package/dist/esm/core/bidi/index.js +18 -2
- package/dist/esm/core/converter/facade.js +10 -5
- package/dist/esm/core/converter/project.js +4 -1
- package/dist/esm/core/converter/ream.js +17 -6
- package/dist/esm/core/converter/sheet-images.d.ts +17 -0
- package/dist/esm/core/converter/sheet-images.js +33 -0
- package/dist/esm/core/crypto/offcrypto.js +1 -1
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +175 -0
- package/dist/esm/core/drawingml/chart-geometry.d.ts +21 -8
- package/dist/esm/core/drawingml/chart-geometry.js +198 -108
- package/dist/esm/core/drawingml/chart-parser.js +73 -2
- package/dist/esm/core/drawingml/colors.d.ts +6 -0
- package/dist/esm/core/drawingml/colors.js +23 -3
- package/dist/esm/core/drawingml/shape-render.d.ts +3 -1
- package/dist/esm/core/drawingml/shape-render.js +4 -2
- package/dist/esm/core/font/index.d.ts +2 -0
- package/dist/esm/core/font/measure.d.ts +9 -0
- package/dist/esm/core/font/measure.js +9 -1
- package/dist/esm/core/font/ttf-build.d.ts +113 -0
- package/dist/esm/core/font/ttf-build.js +1224 -0
- package/dist/esm/core/font/ttf-subset.d.ts +19 -0
- package/dist/esm/core/font/ttf-subset.js +14 -1
- package/dist/esm/core/fonts/families.js +4 -2
- package/dist/esm/core/fonts/provider.d.ts +17 -0
- package/dist/esm/core/fonts/provider.js +27 -2
- package/dist/esm/core/fonts/remote-fonts.js +8 -1
- package/dist/esm/core/fonts/scripts.js +4 -2
- package/dist/esm/core/ir/flow.d.ts +77 -1
- package/dist/esm/core/ir/sheet.d.ts +43 -0
- package/dist/esm/core/number-format.js +16 -11
- package/dist/esm/core/numbering/index.d.ts +1 -1
- package/dist/esm/core/numbering/state.d.ts +11 -1
- package/dist/esm/core/numbering/state.js +10 -1
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +96 -0
- package/dist/esm/core/style-cascade/resolver.js +39 -6
- package/dist/esm/core/style-cascade/types.d.ts +19 -1
- package/dist/esm/core/style-cascade/types.js +3 -0
- package/dist/esm/excel/column-bands.d.ts +39 -6
- package/dist/esm/excel/column-bands.js +41 -17
- package/dist/esm/excel/comments-parser.js +19 -0
- package/dist/esm/excel/conditional-format.d.ts +7 -3
- package/dist/esm/excel/conditional-format.js +77 -39
- package/dist/esm/excel/formula/context.d.ts +18 -0
- package/dist/esm/excel/formula/eval.js +51 -0
- package/dist/esm/excel/formula/index.d.ts +2 -2
- package/dist/esm/excel/formula/lexer.d.ts +1 -1
- package/dist/esm/excel/formula/lexer.js +41 -0
- package/dist/esm/excel/formula/parser.d.ts +25 -0
- package/dist/esm/excel/formula/parser.js +95 -0
- package/dist/esm/excel/print-model.d.ts +38 -1
- package/dist/esm/excel/print-model.js +522 -80
- package/dist/esm/excel/shared-strings-parser.d.ts +9 -0
- package/dist/esm/excel/shared-strings-parser.js +11 -1
- package/dist/esm/excel/sheet-drawing.d.ts +38 -2
- package/dist/esm/excel/sheet-drawing.js +47 -13
- package/dist/esm/excel/sheet-shape-parser.d.ts +6 -2
- package/dist/esm/excel/sheet-shape-parser.js +18 -6
- package/dist/esm/excel/sheet-to-flow.d.ts +17 -0
- package/dist/esm/excel/sheet-to-flow.js +434 -47
- package/dist/esm/excel/styles-parser.d.ts +9 -0
- package/dist/esm/excel/styles-parser.js +80 -26
- package/dist/esm/excel/table-parser.js +5 -0
- package/dist/esm/excel/table-style-presets.d.ts +26 -0
- package/dist/esm/excel/table-style-presets.js +1555 -0
- package/dist/esm/excel/table-style.d.ts +13 -0
- package/dist/esm/excel/table-style.js +75 -0
- package/dist/esm/excel/tint.d.ts +10 -0
- package/dist/esm/excel/tint.js +75 -0
- package/dist/esm/excel/vml-drawing.d.ts +41 -3
- package/dist/esm/excel/vml-drawing.js +143 -10
- package/dist/esm/excel/worksheet-parser.js +89 -15
- package/dist/esm/excel/xls/biff-reader.js +10 -2
- package/dist/esm/excel/xlsx-reader.js +195 -14
- package/dist/esm/excel/xlsx-writer.js +8 -7
- package/dist/esm/html/html-writer.js +202 -20
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/layout/fit-pages.d.ts +11 -0
- package/dist/esm/layout/fit-pages.js +86 -0
- package/dist/esm/layout/line-paint.d.ts +58 -0
- package/dist/esm/layout/line-paint.js +107 -0
- package/dist/esm/layout/page-doc.d.ts +61 -3
- package/dist/esm/layout/page-doc.js +141 -1
- package/dist/esm/layout/styled-layout.d.ts +55 -7
- package/dist/esm/layout/styled-layout.js +1154 -169
- package/dist/esm/layout/turned-section.d.ts +38 -0
- package/dist/esm/layout/turned-section.js +205 -0
- package/dist/esm/markdown/markdown-writer.js +17 -6
- package/dist/esm/pdf/styled-page-emitter.js +114 -60
- package/dist/esm/pdf/styled-page-renderer.js +1 -1
- package/dist/esm/pdf-reader/cff-outline.d.ts +27 -0
- package/dist/esm/pdf-reader/cff-outline.js +169 -21
- package/dist/esm/pdf-reader/content.d.ts +53 -0
- package/dist/esm/pdf-reader/content.js +9 -1
- package/dist/esm/pdf-reader/display.d.ts +36 -0
- package/dist/esm/pdf-reader/display.js +66 -1
- package/dist/esm/pdf-reader/document.js +5 -1
- package/dist/esm/pdf-reader/embedded-fonts.d.ts +2 -1
- package/dist/esm/pdf-reader/embedded-fonts.js +32 -2
- package/dist/esm/pdf-reader/encodings.d.ts +8 -0
- package/dist/esm/pdf-reader/encodings.js +25 -3
- package/dist/esm/pdf-reader/face-outlines.d.ts +78 -0
- package/dist/esm/pdf-reader/face-outlines.js +362 -0
- package/dist/esm/pdf-reader/figures.d.ts +52 -0
- package/dist/esm/pdf-reader/figures.js +433 -0
- package/dist/esm/pdf-reader/flow-build.d.ts +131 -5
- package/dist/esm/pdf-reader/flow-build.js +345 -26
- package/dist/esm/pdf-reader/font.js +321 -36
- package/dist/esm/pdf-reader/glyf-outline.d.ts +33 -0
- package/dist/esm/pdf-reader/glyf-outline.js +135 -1
- package/dist/esm/pdf-reader/glyph-names.js +154 -1
- package/dist/esm/pdf-reader/layout.d.ts +93 -0
- package/dist/esm/pdf-reader/layout.js +1703 -214
- package/dist/esm/pdf-reader/page-numbers.d.ts +53 -0
- package/dist/esm/pdf-reader/page-numbers.js +167 -0
- package/dist/esm/pdf-reader/tagged.js +182 -23
- package/dist/esm/pdf-reader/text.d.ts +6 -3
- package/dist/esm/pdf-reader/text.js +98 -9
- package/dist/esm/pdf-reader/type1-outline.d.ts +11 -0
- package/dist/esm/pdf-reader/type1-outline.js +63 -8
- package/dist/esm/pdf-reader/vector.js +71 -1
- package/dist/esm/svg/svg-text.d.ts +58 -0
- package/dist/esm/svg/svg-text.js +322 -0
- package/dist/esm/svg/svg-writer.js +135 -71
- package/dist/esm/word/doc/doc-reader.js +6 -2
- package/dist/esm/word/doc/doc-text.d.ts +6 -0
- package/dist/esm/word/doc/doc-text.js +19 -1
- package/dist/esm/word/document-parser.d.ts +2 -2
- package/dist/esm/word/document-parser.js +11 -1
- package/dist/esm/word/docx-reader.js +5 -3
- package/dist/esm/word/docx-writer.js +218 -23
- package/dist/esm/word/drawing-parser.d.ts +5 -3
- package/dist/esm/word/drawing-parser.js +49 -8
- package/dist/esm/word/font-embed.d.ts +30 -0
- package/dist/esm/word/font-embed.js +173 -0
- package/dist/esm/word/font-table.d.ts +10 -0
- package/dist/esm/word/font-table.js +13 -1
- package/dist/esm/word/index.js +1 -1
- package/dist/esm/word/numbering-parser.d.ts +3 -1
- package/dist/esm/word/numbering-parser.js +2 -1
- package/dist/esm/word/paragraph-properties.d.ts +7 -6
- package/dist/esm/word/paragraph-properties.js +14 -2
- package/dist/esm/word/run-properties.js +26 -0
- package/package.json +12 -3
|
@@ -40,6 +40,9 @@ var SPRM_P_DYA_BEFORE = 42003;
|
|
|
40
40
|
var SPRM_P_DYA_AFTER = 42004;
|
|
41
41
|
var SPRM_P_F_IN_TABLE = 9238;
|
|
42
42
|
var SPRM_P_F_TTP = 9239;
|
|
43
|
+
var SPRM_P_F_WIDOW_CONTROL = 9265;
|
|
44
|
+
var SPRM_P_F_KEEP = 9221;
|
|
45
|
+
var SPRM_P_F_KEEP_FOLLOW = 9222;
|
|
43
46
|
var SPRM_T_DEF_TABLE = 54792;
|
|
44
47
|
var SPRM_T_DEF_TABLE_SHD = 54802;
|
|
45
48
|
var MAX_ROW_CELLS = 256;
|
|
@@ -433,6 +436,9 @@ function decodePapxGrpprl(d) {
|
|
|
433
436
|
let cellShadings;
|
|
434
437
|
let listIlfo;
|
|
435
438
|
let listIlvl;
|
|
439
|
+
let widowControl;
|
|
440
|
+
let keepNext;
|
|
441
|
+
let keepLines;
|
|
436
442
|
for (const s of sprms(d)) switch (s.sprm) {
|
|
437
443
|
case SPRM_P_JC:
|
|
438
444
|
jc = d[s.op];
|
|
@@ -458,6 +464,15 @@ function decodePapxGrpprl(d) {
|
|
|
458
464
|
case SPRM_P_F_TTP:
|
|
459
465
|
rowEnd = d[s.op] !== 0;
|
|
460
466
|
break;
|
|
467
|
+
case SPRM_P_F_WIDOW_CONTROL:
|
|
468
|
+
widowControl = d[s.op] !== 0;
|
|
469
|
+
break;
|
|
470
|
+
case SPRM_P_F_KEEP_FOLLOW:
|
|
471
|
+
keepNext = d[s.op] !== 0;
|
|
472
|
+
break;
|
|
473
|
+
case SPRM_P_F_KEEP:
|
|
474
|
+
keepLines = d[s.op] !== 0;
|
|
475
|
+
break;
|
|
461
476
|
case SPRM_T_DEF_TABLE: {
|
|
462
477
|
const cols = d[s.op] ?? 0;
|
|
463
478
|
const edges = [];
|
|
@@ -498,7 +513,10 @@ function decodePapxGrpprl(d) {
|
|
|
498
513
|
...cellDescriptors ? { cellDescriptors } : {},
|
|
499
514
|
...cellShadings ? { cellShadings } : {},
|
|
500
515
|
...listIlfo !== void 0 ? { listIlfo } : {},
|
|
501
|
-
...listIlvl !== void 0 ? { listIlvl } : {}
|
|
516
|
+
...listIlvl !== void 0 ? { listIlvl } : {},
|
|
517
|
+
...widowControl !== void 0 ? { widowControl } : {},
|
|
518
|
+
...keepNext !== void 0 ? { keepNext } : {},
|
|
519
|
+
...keepLines !== void 0 ? { keepLines } : {}
|
|
502
520
|
};
|
|
503
521
|
}
|
|
504
522
|
function* sprms(d) {
|
|
@@ -80,8 +80,8 @@ export interface ParseContext {
|
|
|
80
80
|
readonly openCommentRanges?: Set<string>;
|
|
81
81
|
/**
|
|
82
82
|
* §17.3.1.1/§17.3.1.3 — what `w:beforeAutospacing`/`w:afterAutospacing`
|
|
83
|
-
* resolve to
|
|
84
|
-
*
|
|
83
|
+
* resolve to: HTML's 14pt for a Word document, nothing (the default) where
|
|
84
|
+
* the caller gives none.
|
|
85
85
|
*/
|
|
86
86
|
readonly autoSpacingPt?: number;
|
|
87
87
|
}
|
|
@@ -9,6 +9,7 @@ import { parseRunProperties } from "./run-properties.js";
|
|
|
9
9
|
import { parseParagraphProperties } from "./paragraph-properties.js";
|
|
10
10
|
import { poElementToFlat } from "./po-to-flat.js";
|
|
11
11
|
import { parseBorders, parseTable } from "./table-parser.js";
|
|
12
|
+
import { FORMATS } from "./numbering-parser.js";
|
|
12
13
|
import { XMLParser } from "fast-xml-parser";
|
|
13
14
|
//#region src/word/document-parser.ts
|
|
14
15
|
var decoder = new TextDecoder("utf-8");
|
|
@@ -199,11 +200,13 @@ function parseSectPrNode(sectPr) {
|
|
|
199
200
|
let margins;
|
|
200
201
|
let titlePg = false;
|
|
201
202
|
let pageNumberStart;
|
|
203
|
+
let pageNumberFormat;
|
|
202
204
|
let lineNumbering;
|
|
203
205
|
let columns;
|
|
204
206
|
let sectionStart;
|
|
205
207
|
let pageBorders;
|
|
206
208
|
let gridLinePitchPt;
|
|
209
|
+
let textDirection;
|
|
207
210
|
const headers = [];
|
|
208
211
|
const footers = [];
|
|
209
212
|
for (const child of poChildren(sectPr)) if (poIs(child, "w:pgSz")) {
|
|
@@ -251,6 +254,8 @@ function parseSectPrNode(sectPr) {
|
|
|
251
254
|
} else if (poIs(child, "w:pgNumType")) {
|
|
252
255
|
const start = poIntAttr(child, "start");
|
|
253
256
|
if (start !== void 0) pageNumberStart = start;
|
|
257
|
+
const fmt = poAttr(child, "fmt");
|
|
258
|
+
if (fmt !== void 0 && FORMATS.has(fmt) && fmt !== "decimal") pageNumberFormat = fmt;
|
|
254
259
|
} else if (poIs(child, "w:cols")) columns = parseColumns(child);
|
|
255
260
|
else if (poIs(child, "w:pgBorders")) {
|
|
256
261
|
const borders = parseBorders(child);
|
|
@@ -265,6 +270,9 @@ function parseSectPrNode(sectPr) {
|
|
|
265
270
|
} else if (poIs(child, "w:type")) {
|
|
266
271
|
const val = poAttr(child, "val");
|
|
267
272
|
sectionStart = val === "continuous" || val === "oddPage" || val === "evenPage" ? val : "nextPage";
|
|
273
|
+
} else if (poIs(child, "w:textDirection")) {
|
|
274
|
+
const val = poAttr(child, "val");
|
|
275
|
+
if (val === "tbRl" || val === "btLr") textDirection = val;
|
|
268
276
|
}
|
|
269
277
|
return {
|
|
270
278
|
pageSize,
|
|
@@ -273,11 +281,13 @@ function parseSectPrNode(sectPr) {
|
|
|
273
281
|
footers,
|
|
274
282
|
...titlePg ? { titlePg: true } : {},
|
|
275
283
|
...pageNumberStart !== void 0 ? { pageNumberStart } : {},
|
|
284
|
+
...pageNumberFormat !== void 0 ? { pageNumberFormat } : {},
|
|
276
285
|
...lineNumbering ? { lineNumbering } : {},
|
|
277
286
|
...columns ? { columns } : {},
|
|
278
287
|
...sectionStart ? { sectionStart } : {},
|
|
279
288
|
...pageBorders ? { pageBorders } : {},
|
|
280
|
-
...gridLinePitchPt !== void 0 ? { gridLinePitchPt } : {}
|
|
289
|
+
...gridLinePitchPt !== void 0 ? { gridLinePitchPt } : {},
|
|
290
|
+
...textDirection ? { textDirection } : {}
|
|
281
291
|
};
|
|
282
292
|
}
|
|
283
293
|
function parseColumns(cols) {
|
|
@@ -15,10 +15,10 @@ import { OpcPackage } from "../core/opc/package.js";
|
|
|
15
15
|
import { parseCoreProperties } from "../core/opc/core-properties.js";
|
|
16
16
|
import "../core/opc/index.js";
|
|
17
17
|
import { parseXml } from "../pptx/pptx-reader.js";
|
|
18
|
+
import { EMPTY_NUMBERING, parseNumbering } from "./numbering-parser.js";
|
|
18
19
|
import { EMPTY_SECTION, applyAuthorIds, bodyIndexForBlock, newBlockCounter, parseBackgroundColor, parseBackgroundFill, parseCommentThreads, parseDocument, parseHeaderFooter, parseNotes, parsePeople, parseSections } from "./document-parser.js";
|
|
19
20
|
import { parseStyles } from "./styles-parser.js";
|
|
20
21
|
import { loadEmbeddedFonts } from "./font-table.js";
|
|
21
|
-
import { EMPTY_NUMBERING, parseNumbering } from "./numbering-parser.js";
|
|
22
22
|
import { EMPTY_SETTINGS, parseSettings } from "./settings-parser.js";
|
|
23
23
|
import "./index.js";
|
|
24
24
|
//#region src/word/docx-reader.ts
|
|
@@ -66,7 +66,7 @@ function readDocx(docx) {
|
|
|
66
66
|
const settings = settingsData ? parseSettings(settingsData) : EMPTY_SETTINGS;
|
|
67
67
|
const ctx = {
|
|
68
68
|
resolveColor,
|
|
69
|
-
|
|
69
|
+
autoSpacingPt: 14,
|
|
70
70
|
...themeLineWidths && themeLineWidths.length > 0 ? { themeLineWidths } : {},
|
|
71
71
|
...themeStyles ? { themeStyles } : {},
|
|
72
72
|
...themeFonts ? { themeFonts } : {},
|
|
@@ -142,7 +142,9 @@ function readDocx(docx) {
|
|
|
142
142
|
...settings.doNotExpandShiftReturn ? { doNotExpandShiftReturn: true } : {},
|
|
143
143
|
...settings.displayBackgroundShape && backgroundFill ? { pageBackgroundFill: backgroundFill } : {},
|
|
144
144
|
...settings.displayBackgroundShape && backgroundColorHex ? { pageBackgroundColorHex: backgroundColorHex } : {},
|
|
145
|
-
...settings.gutterAtTop ? { gutterAtTop: true } : {}
|
|
145
|
+
...settings.gutterAtTop ? { gutterAtTop: true } : {},
|
|
146
|
+
...settings.compatibilityMode !== void 0 ? { compatibilityMode: settings.compatibilityMode } : {},
|
|
147
|
+
typesetBy: "word"
|
|
146
148
|
},
|
|
147
149
|
losses
|
|
148
150
|
};
|
|
@@ -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,7 +154,10 @@ function writeDocx(flow) {
|
|
|
133
154
|
...flow.charts ? { charts: flow.charts } : {},
|
|
134
155
|
...flow.faceFamilies ? { faceFamilies: flow.faceFamilies } : {},
|
|
135
156
|
familiesUsed: /* @__PURE__ */ new Map(),
|
|
136
|
-
|
|
157
|
+
...flow.faceOutlines ? { faceOutlines: flow.faceOutlines } : {},
|
|
158
|
+
facesUsed: /* @__PURE__ */ new Set(),
|
|
159
|
+
zRanks: zRanksOf(flow),
|
|
160
|
+
overlaid: /* @__PURE__ */ new Set()
|
|
137
161
|
};
|
|
138
162
|
const docScope = newScope();
|
|
139
163
|
const extraParts = [];
|
|
@@ -153,7 +177,8 @@ function writeDocx(flow) {
|
|
|
153
177
|
});
|
|
154
178
|
emitBody(body, flow.body, losses, state, docScope, sectPrByClosingIndex);
|
|
155
179
|
if (finalSectPr) body.push(finalSectPr);
|
|
156
|
-
const
|
|
180
|
+
const bodyXml = body.join("");
|
|
181
|
+
const documentXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:document${rootNamespaces(bodyXml)}><w:body>${bodyXml}</w:body></w:document>`;
|
|
157
182
|
const numberingPart = flow.body.some((el) => el.kind === "paragraph" && el.paragraph.properties.numbering !== void 0) && flow.numbering ? {
|
|
158
183
|
path: NUMBERING_PART,
|
|
159
184
|
data: encoder.encode(numberingXml(flow.numbering)),
|
|
@@ -185,9 +210,14 @@ function writeDocx(flow) {
|
|
|
185
210
|
}, state, losses, docScope, extraParts, extraPartRels);
|
|
186
211
|
const commentParaIds = emitComments(flow.comments, state, losses, docScope, extraParts, extraPartRels);
|
|
187
212
|
emitCommentsExtended(flow.comments, commentParaIds, docScope, extraParts);
|
|
213
|
+
const embedded = state.faceOutlines && state.faceFamilies ? embedFaces(state.facesUsed, state.faceOutlines, state.faceFamilies, losses) : void 0;
|
|
214
|
+
if (embedded && embedded.relationships.length > 0) extraPartRels.push({
|
|
215
|
+
sourcePart: FONT_TABLE_PART,
|
|
216
|
+
relationships: [...embedded.relationships]
|
|
217
|
+
});
|
|
188
218
|
const fontTablePart = state.familiesUsed.size > 0 ? {
|
|
189
219
|
path: FONT_TABLE_PART,
|
|
190
|
-
data: encoder.encode(fontTableXml(state.familiesUsed)),
|
|
220
|
+
data: encoder.encode(fontTableXml(state.familiesUsed, embedded?.elements)),
|
|
191
221
|
contentType: FONT_TABLE_CONTENT_TYPE
|
|
192
222
|
} : void 0;
|
|
193
223
|
if (fontTablePart) docScope.rels.push({
|
|
@@ -196,6 +226,29 @@ function writeDocx(flow) {
|
|
|
196
226
|
target: "fontTable.xml",
|
|
197
227
|
targetMode: "Internal"
|
|
198
228
|
});
|
|
229
|
+
const settings = settingsXml(flow, sections, (embedded?.parts.length ?? 0) > 0);
|
|
230
|
+
const settingsPart = settings !== void 0 ? {
|
|
231
|
+
path: SETTINGS_PART,
|
|
232
|
+
data: encoder.encode(settings),
|
|
233
|
+
contentType: SETTINGS_CONTENT_TYPE
|
|
234
|
+
} : void 0;
|
|
235
|
+
if (settingsPart) docScope.rels.push({
|
|
236
|
+
id: `rId${++docScope.relSeq}`,
|
|
237
|
+
type: REL_SETTINGS,
|
|
238
|
+
target: "settings.xml",
|
|
239
|
+
targetMode: "Internal"
|
|
240
|
+
});
|
|
241
|
+
const stylesPart = {
|
|
242
|
+
path: STYLES_PART,
|
|
243
|
+
data: encoder.encode(stylesXml()),
|
|
244
|
+
contentType: STYLES_CONTENT_TYPE
|
|
245
|
+
};
|
|
246
|
+
docScope.rels.push({
|
|
247
|
+
id: `rId${++docScope.relSeq}`,
|
|
248
|
+
type: REL_STYLES,
|
|
249
|
+
target: "styles.xml",
|
|
250
|
+
targetMode: "Internal"
|
|
251
|
+
});
|
|
199
252
|
const partRelationships = [...docScope.rels.length > 0 ? [{
|
|
200
253
|
sourcePart: "word/document.xml",
|
|
201
254
|
relationships: docScope.rels
|
|
@@ -208,12 +261,16 @@ function writeDocx(flow) {
|
|
|
208
261
|
data: encoder.encode(documentXml),
|
|
209
262
|
contentType: DOC_CONTENT_TYPE
|
|
210
263
|
},
|
|
264
|
+
stylesPart,
|
|
211
265
|
...numberingPart ? [numberingPart] : [],
|
|
212
266
|
...fontTablePart ? [fontTablePart] : [],
|
|
267
|
+
...settingsPart ? [settingsPart] : [],
|
|
213
268
|
...extraParts,
|
|
214
269
|
...state.chartParts,
|
|
215
|
-
...state.mediaParts
|
|
270
|
+
...state.mediaParts,
|
|
271
|
+
...embedded?.parts ?? []
|
|
216
272
|
],
|
|
273
|
+
...(embedded?.parts.length ?? 0) > 0 ? { defaultsByExtension: { odttf: OBFUSCATED_FONT_CONTENT_TYPE } } : {},
|
|
217
274
|
rootRelationships: [{
|
|
218
275
|
id: "rId1",
|
|
219
276
|
type: REL_OFFICE_DOCUMENT,
|
|
@@ -225,8 +282,50 @@ function writeDocx(flow) {
|
|
|
225
282
|
losses
|
|
226
283
|
};
|
|
227
284
|
}
|
|
228
|
-
|
|
229
|
-
|
|
285
|
+
/**
|
|
286
|
+
* §17.15.1.78 `w:settings` — the document-wide settings the model carries, in
|
|
287
|
+
* the order CT_Settings declares them: `w:embedTrueTypeFonts` and
|
|
288
|
+
* `w:saveSubsetFonts` (§17.15.1.42, .74) where the package embeds its faces,
|
|
289
|
+
* `w:gutterAtTop` (§17.15.1.49), `w:evenAndOddHeaders` (§17.15.1.36, which a
|
|
290
|
+
* section carries in the model), and inside `w:compat` §17.15.3.4's
|
|
291
|
+
* `w:doNotExpandShiftReturn` before the version of Word the document is laid
|
|
292
|
+
* out for ([MS-DOCX] `w:compatSetting` `compatibilityMode`), which CT_Compat
|
|
293
|
+
* keeps last.
|
|
294
|
+
*
|
|
295
|
+
* @param flow The document.
|
|
296
|
+
* @param sections The sections being written.
|
|
297
|
+
* @param embedsFonts Whether the package embeds fonts — which then stay
|
|
298
|
+
* embedded, as subsets, when the document is saved again.
|
|
299
|
+
* @returns The part's XML, or undefined where the document states none.
|
|
300
|
+
*/
|
|
301
|
+
function settingsXml(flow, sections, embedsFonts) {
|
|
302
|
+
const parts = [];
|
|
303
|
+
if (embedsFonts) parts.push("<w:embedTrueTypeFonts/><w:saveSubsetFonts/>");
|
|
304
|
+
if (flow.gutterAtTop === true) parts.push("<w:gutterAtTop/>");
|
|
305
|
+
if (sections.some((sec) => sec.properties.evenAndOddHeaders === true)) parts.push("<w:evenAndOddHeaders/>");
|
|
306
|
+
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)}"/>`] : []];
|
|
307
|
+
if (compat.length > 0) parts.push(`<w:compat>${compat.join("")}</w:compat>`);
|
|
308
|
+
if (parts.length === 0) return void 0;
|
|
309
|
+
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>`;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* §17.7.2 `w:styles` — what a property the document states nowhere IS: the
|
|
313
|
+
* values the model resolves an empty sheet to (`DEFAULT_RUN`, `DEFAULT_PARA`
|
|
314
|
+
* — the very values a run or paragraph is written without), as §17.7.5
|
|
315
|
+
* `w:docDefaults`, under an empty default paragraph style (§17.7.4.17).
|
|
316
|
+
*
|
|
317
|
+
* A package with no styles part leaves them to its reader, and Word fills
|
|
318
|
+
* them from its own template's Normal: 8pt after every paragraph, lines 1.08
|
|
319
|
+
* apart, runs in 12pt — so every paragraph of a reconstruction stood 8pt
|
|
320
|
+
* further down than its page set it, and a run of the model's own 11pt, which
|
|
321
|
+
* states no size, was set in 12.
|
|
322
|
+
*/
|
|
323
|
+
function stylesXml() {
|
|
324
|
+
const size = Math.round(DEFAULT_RUN.fontSizePt * 2);
|
|
325
|
+
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>`;
|
|
326
|
+
}
|
|
327
|
+
function fontTableXml(families, embeds) {
|
|
328
|
+
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
329
|
}
|
|
231
330
|
/**
|
|
232
331
|
* §20.4.2.3 `relativeHeight` — a float's z-order, written the way Word writes
|
|
@@ -257,7 +356,10 @@ function zRanksOf(flow) {
|
|
|
257
356
|
for (const el of blocks) {
|
|
258
357
|
const z = el.kind === "image" ? el.image.float?.zOrder : el.kind === "shape" ? el.shape.float?.zOrder : el.kind === "chart" ? el.chart.float?.zOrder : void 0;
|
|
259
358
|
if (z !== void 0 && Number.isFinite(z)) seen.add(z);
|
|
260
|
-
if (el.kind === "table")
|
|
359
|
+
if (el.kind === "table") {
|
|
360
|
+
for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
|
|
361
|
+
visit(el.table.overlay?.drawings ?? []);
|
|
362
|
+
}
|
|
261
363
|
}
|
|
262
364
|
};
|
|
263
365
|
visit(flow.body);
|
|
@@ -277,7 +379,8 @@ function emitNotes(notes, cfg, state, losses, docScope, extraParts, extraPartRel
|
|
|
277
379
|
for (const el of content) emitBlock(inner, el, losses, state, scope);
|
|
278
380
|
noteXmls.push(`<${cfg.noteTag} w:id="${escapeAttr(id)}">${inner.join("") || "<w:p/>"}</${cfg.noteTag}>`);
|
|
279
381
|
}
|
|
280
|
-
const
|
|
382
|
+
const notesXml = noteXmls.join("");
|
|
383
|
+
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
384
|
extraParts.push({
|
|
282
385
|
path: cfg.partPath,
|
|
283
386
|
data: encoder.encode(xml),
|
|
@@ -383,7 +486,8 @@ function emitHeadersFooters(flow, section, state, docScope, extraParts, extraPar
|
|
|
383
486
|
const scope = newScope();
|
|
384
487
|
const inner = [];
|
|
385
488
|
for (const el of content) emitBlock(inner, el, losses, state, scope);
|
|
386
|
-
const
|
|
489
|
+
const bandXml = inner.join("");
|
|
490
|
+
const xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><${root}${rootNamespaces(bandXml)}>${bandXml}</${root}>`;
|
|
387
491
|
extraParts.push({
|
|
388
492
|
path,
|
|
389
493
|
data: encoder.encode(xml),
|
|
@@ -427,7 +531,7 @@ function emitHeadersFooters(flow, section, state, docScope, extraParts, extraPar
|
|
|
427
531
|
var docxWriter = {
|
|
428
532
|
id: "docx",
|
|
429
533
|
consumes: "flow",
|
|
430
|
-
supports: new Set([FEATURES.text]),
|
|
534
|
+
supports: new Set([FEATURES.text, FEATURES.fontsEmbedding]),
|
|
431
535
|
write: (doc) => writeDocx(doc)
|
|
432
536
|
};
|
|
433
537
|
/**
|
|
@@ -493,6 +597,11 @@ function emitBlock(out, el, losses, state, scope, closingSectPr) {
|
|
|
493
597
|
}
|
|
494
598
|
if (el.kind === "table") {
|
|
495
599
|
out.push(tableXml(el.table, losses, state, scope));
|
|
600
|
+
for (const drawing of el.table.overlay?.drawings ?? []) {
|
|
601
|
+
if (state.overlaid.has(drawing)) continue;
|
|
602
|
+
state.overlaid.add(drawing);
|
|
603
|
+
emitBlock(out, drawing, losses, state, scope);
|
|
604
|
+
}
|
|
496
605
|
if (closingSectPr) out.push(`<w:p><w:pPr>${closingSectPr}</w:pPr></w:p>`);
|
|
497
606
|
return;
|
|
498
607
|
}
|
|
@@ -636,13 +745,76 @@ function shapeDrawingXml(shape, losses, state, scope) {
|
|
|
636
745
|
const cy = Math.round(shape.height * EMU_PER_PT);
|
|
637
746
|
const id = ++state.drawingSeq;
|
|
638
747
|
const descr = shape.altText ? ` descr="${escapeAttr(shape.altText)}"` : "";
|
|
639
|
-
const
|
|
640
|
-
const
|
|
641
|
-
|
|
748
|
+
const members = shape.children ?? [];
|
|
749
|
+
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, {
|
|
750
|
+
x: 0,
|
|
751
|
+
y: 0,
|
|
752
|
+
cx,
|
|
753
|
+
cy
|
|
754
|
+
}, losses, state, scope) : `<a:graphicData uri="${WPS_URI}">` + wspXml(shape, cx, cy, void 0, losses, state, scope)) + "</a:graphicData></a:graphic>";
|
|
642
755
|
return drawingFrame(shape.float, cx, cy, `<wp:docPr id="${id}" name="Shape ${id}"${descr}/>`, graphic, state, shape.transform?.rotation60k);
|
|
643
756
|
}
|
|
644
|
-
|
|
645
|
-
|
|
757
|
+
/**
|
|
758
|
+
* `wps:wsp` — one shape: its box, geometry, fill and outline, and the text it
|
|
759
|
+
* holds. `id` is its own `wps:cNvPr` inside a group, where the members name
|
|
760
|
+
* themselves; a shape alone is named by the frame's `wp:docPr`.
|
|
761
|
+
*/
|
|
762
|
+
function wspXml(shape, cx, cy, member, losses, state, scope) {
|
|
763
|
+
const spPr = `<wps:spPr>${xfrmXml(shape.transform, cx, cy, member)}${geomXml(shape.geometry)}${fillXml(shape.fill)}${shape.line ? lineXml(shape.line) : ""}</wps:spPr>`;
|
|
764
|
+
const txbx = shape.text ? txbxXml(shape.text, losses, state, scope) : "";
|
|
765
|
+
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>";
|
|
766
|
+
}
|
|
767
|
+
var WPG_URI = "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup";
|
|
768
|
+
/**
|
|
769
|
+
* §20.5.2.17 `wpg:wgp` / `wpg:grpSp` — a group: its box, and its members in
|
|
770
|
+
* the order they are painted. The members are placed in a child space the
|
|
771
|
+
* same as the box, so a member's offset from the group's corner is its offset
|
|
772
|
+
* in the file. The inverse of drawing-parser's `groupChildren`.
|
|
773
|
+
*
|
|
774
|
+
* Written as one shape, the group came back an empty box: a figure's paths
|
|
775
|
+
* and labels were thrown away with it.
|
|
776
|
+
*/
|
|
777
|
+
function groupXml(tag, members, box, losses, state, scope) {
|
|
778
|
+
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}>`;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* One member of a group: a group of its own, a picture (`pic:pic`, a shape
|
|
782
|
+
* whose fill is the picture — how the reader brings one in), or a shape.
|
|
783
|
+
*/
|
|
784
|
+
function memberXml(member, losses, state, scope) {
|
|
785
|
+
const s = member.shape;
|
|
786
|
+
const x = Math.round(member.xPt * EMU_PER_PT);
|
|
787
|
+
const y = Math.round(member.yPt * EMU_PER_PT);
|
|
788
|
+
const cx = Math.round(s.width * EMU_PER_PT);
|
|
789
|
+
const cy = Math.round(s.height * EMU_PER_PT);
|
|
790
|
+
if (s.children !== void 0 && s.children.length > 0) return groupXml("wpg:grpSp", s.children, {
|
|
791
|
+
x,
|
|
792
|
+
y,
|
|
793
|
+
cx,
|
|
794
|
+
cy
|
|
795
|
+
}, losses, state, scope);
|
|
796
|
+
const id = ++state.drawingSeq;
|
|
797
|
+
if (s.fill.kind !== "picture") return wspXml(s, cx, cy, {
|
|
798
|
+
id,
|
|
799
|
+
x,
|
|
800
|
+
y
|
|
801
|
+
}, losses, state, scope);
|
|
802
|
+
const relId = s.fill.imageResource !== void 0 ? mediaRelId(s.fill.imageResource, state, scope) : void 0;
|
|
803
|
+
if (relId === void 0) {
|
|
804
|
+
losses.push({
|
|
805
|
+
severity: "dropped",
|
|
806
|
+
feature: FEATURES.images,
|
|
807
|
+
detail: imageRefusal(s.fill.imageResource, state)
|
|
808
|
+
});
|
|
809
|
+
return "";
|
|
810
|
+
}
|
|
811
|
+
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, {
|
|
812
|
+
x,
|
|
813
|
+
y
|
|
814
|
+
})}<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic>`;
|
|
815
|
+
}
|
|
816
|
+
function xfrmXml(t, cx, cy, at) {
|
|
817
|
+
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
818
|
}
|
|
647
819
|
/**
|
|
648
820
|
* The factor that carries a path into whole units, and the space it lands in.
|
|
@@ -668,7 +840,7 @@ function pathScale(g) {
|
|
|
668
840
|
else if (c.cmd === "quad") values.push(c.x1, c.y1, c.x, c.y);
|
|
669
841
|
else if (c.cmd === "arc") values.push(c.wR, c.hR);
|
|
670
842
|
if (values.every((v) => Number.isInteger(v))) return 1;
|
|
671
|
-
const span =
|
|
843
|
+
const span = values.reduce((most, v) => Number.isFinite(v) ? Math.max(most, Math.abs(v)) : most, 1);
|
|
672
844
|
return Math.max(1, Math.floor(PATH_SPACE / span));
|
|
673
845
|
}
|
|
674
846
|
function geomXml(g) {
|
|
@@ -736,7 +908,7 @@ function bodyPrXml(text) {
|
|
|
736
908
|
if (!text) return "<wps:bodyPr/>";
|
|
737
909
|
const ins = (v, name) => v !== void 0 ? ` ${name}="${Math.round(v * EMU_PER_PT)}"` : "";
|
|
738
910
|
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 + "/>";
|
|
911
|
+
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
912
|
}
|
|
741
913
|
function mediaRelId(resource, state, scope) {
|
|
742
914
|
const existingRel = scope.relIdByResource.get(resource);
|
|
@@ -787,6 +959,7 @@ function tblPrXml(p) {
|
|
|
787
959
|
out.push(`<w:tblW w:w="${w}" w:type="${p.widthType}"/>`);
|
|
788
960
|
}
|
|
789
961
|
if (p.alignment && p.alignment !== "left") out.push(`<w:jc w:val="${p.alignment}"/>`);
|
|
962
|
+
if (p.indentPt !== void 0 && p.indentPt !== 0) out.push(`<w:tblInd w:w="${twips(p.indentPt)}" w:type="dxa"/>`);
|
|
790
963
|
const borders = bordersXml("w:tblBorders", p.borders);
|
|
791
964
|
if (borders) out.push(borders);
|
|
792
965
|
if (p.layout === "fixed") out.push("<w:tblLayout w:type=\"fixed\"/>");
|
|
@@ -839,11 +1012,14 @@ function bordersXml(tag, borders) {
|
|
|
839
1012
|
if (tag === "w:pBdr" && key === "insideV") return "";
|
|
840
1013
|
const el = tag === "w:pBdr" && key === "insideH" ? "w:between" : name;
|
|
841
1014
|
const sz = b.width !== void 0 ? ` w:sz="${Math.round(b.width * 8)}"` : "";
|
|
1015
|
+
const space = b.spacePt !== void 0 && Math.round(b.spacePt) > 0 ? ` w:space="${Math.min(Math.round(b.spacePt), MOST_BORDER_SPACE_PT)}"` : "";
|
|
842
1016
|
const color = b.colorHex !== void 0 ? ` w:color="${b.colorHex}"` : "";
|
|
843
|
-
return `<${el} w:val="${b.style}"${sz}${color}/>`;
|
|
1017
|
+
return `<${el} w:val="${b.style}"${sz}${space}${color}/>`;
|
|
844
1018
|
}).join("");
|
|
845
1019
|
return sides ? `<${tag}>${sides}</${tag}>` : "";
|
|
846
1020
|
}
|
|
1021
|
+
/** §17.3.4 — the farthest a border may stand off its text, in points. */
|
|
1022
|
+
var MOST_BORDER_SPACE_PT = 31;
|
|
847
1023
|
function cellMarginsXml(tag, margins) {
|
|
848
1024
|
if (!margins) return "";
|
|
849
1025
|
const inner = [
|
|
@@ -914,7 +1090,8 @@ function runXml(run, state, scope) {
|
|
|
914
1090
|
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
1091
|
}
|
|
916
1092
|
if (run.text === "") return brk ? `<w:r>${rPr}${brk}</w:r>` : "";
|
|
917
|
-
|
|
1093
|
+
const lineBreak = run.columnBreak ? "<w:br w:type=\"column\"/>" : "<w:br/>";
|
|
1094
|
+
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
1095
|
}
|
|
919
1096
|
function rPrXml(r, state) {
|
|
920
1097
|
const out = [];
|
|
@@ -925,6 +1102,15 @@ function rPrXml(r, state) {
|
|
|
925
1102
|
if (states("italic")) out.push(toggle("w:i", r.italic), toggle("w:iCs", r.italic));
|
|
926
1103
|
if (states("strike")) out.push(toggle("w:strike", r.strike));
|
|
927
1104
|
if (states("colorHex")) out.push(`<w:color w:val="${r.colorHex}"/>`);
|
|
1105
|
+
if (r.letterSpacingPt !== void 0 && r.letterSpacingPt !== 0) {
|
|
1106
|
+
const twips = Math.round(r.letterSpacingPt * 20);
|
|
1107
|
+
if (twips !== 0) out.push(`<w:spacing w:val="${String(twips)}"/>`);
|
|
1108
|
+
}
|
|
1109
|
+
if (r.widthScale !== void 0) {
|
|
1110
|
+
const percent = Math.min(600, Math.max(1, Math.round(r.widthScale * 100)));
|
|
1111
|
+
if (percent !== 100) out.push(`<w:w w:val="${String(percent)}"/>`);
|
|
1112
|
+
}
|
|
1113
|
+
if (r.kerningMinPt !== void 0 && states("kerningMinPt")) out.push(`<w:kern w:val="${Math.round(r.kerningMinPt * 2)}"/>`);
|
|
928
1114
|
if (states("fontSizePt")) {
|
|
929
1115
|
const half = Math.round(r.fontSizePt * 2);
|
|
930
1116
|
out.push(`<w:sz w:val="${half}"/>`, `<w:szCs w:val="${half}"/>`);
|
|
@@ -934,6 +1120,7 @@ function rPrXml(r, state) {
|
|
|
934
1120
|
if (states("verticalAlign")) out.push(`<w:vertAlign w:val="${r.verticalAlign}"/>`);
|
|
935
1121
|
if (states("rtl")) out.push(toggle("w:rtl", r.rtl));
|
|
936
1122
|
if (r.lang !== void 0) out.push(`<w:lang w:val="${escapeAttr(r.lang)}"/>`);
|
|
1123
|
+
if (r.ligatures !== void 0 && states("ligatures")) out.push(`<w14:ligatures w14:val="${r.ligatures}"/>`);
|
|
937
1124
|
return out.length > 0 ? `<w:rPr>${out.join("")}</w:rPr>` : "";
|
|
938
1125
|
}
|
|
939
1126
|
function underlineXml(r) {
|
|
@@ -945,10 +1132,14 @@ function runShdXml(fill) {
|
|
|
945
1132
|
}
|
|
946
1133
|
function pPrBody(p) {
|
|
947
1134
|
const out = [];
|
|
1135
|
+
if (p.keepNext) out.push("<w:keepNext/>");
|
|
1136
|
+
if (p.keepLines) out.push("<w:keepLines/>");
|
|
948
1137
|
if (p.pageBreakBefore) out.push("<w:pageBreakBefore/>");
|
|
1138
|
+
if (p.widowControl === false) out.push("<w:widowControl w:val=\"0\"/>");
|
|
949
1139
|
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
1140
|
const pBdr = bordersXml("w:pBdr", p.borders);
|
|
951
1141
|
if (pBdr) out.push(pBdr);
|
|
1142
|
+
if (p.shading) out.push(`<w:shd w:val="clear" w:color="auto" w:fill="${p.shading.colorHex}"/>`);
|
|
952
1143
|
const tabs = p.tabs ?? [];
|
|
953
1144
|
if (tabs.length > 0) {
|
|
954
1145
|
const stops = tabs.map((t) => {
|
|
@@ -1005,10 +1196,7 @@ function spacingXml(p) {
|
|
|
1005
1196
|
const attrs = [];
|
|
1006
1197
|
if (stated(p.spacingBefore) && p.spacingBefore !== DEFAULT_PARA.spacingBefore) attrs.push(`w:before="${twips(p.spacingBefore)}"`);
|
|
1007
1198
|
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
|
-
}
|
|
1199
|
+
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
1200
|
return attrs.length > 0 ? `<w:spacing ${attrs.join(" ")}/>` : "";
|
|
1013
1201
|
}
|
|
1014
1202
|
function rFontsXml(fonts, state) {
|
|
@@ -1018,6 +1206,7 @@ function rFontsXml(fonts, state) {
|
|
|
1018
1206
|
const known = state?.faceFamilies?.get(name);
|
|
1019
1207
|
if (known === void 0) return name;
|
|
1020
1208
|
state?.familiesUsed.set(known.family, known);
|
|
1209
|
+
if (state?.faceOutlines?.has(name) === true) state.facesUsed.add(name);
|
|
1021
1210
|
return known.family;
|
|
1022
1211
|
};
|
|
1023
1212
|
const attrs = [];
|
|
@@ -1104,8 +1293,14 @@ function sectPrXml(s, hf) {
|
|
|
1104
1293
|
const footer = m.footer !== void 0 ? ` w:footer="${twips(m.footer)}"` : "";
|
|
1105
1294
|
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
1295
|
}
|
|
1296
|
+
if (s.pageNumberFormat !== void 0 || s.pageNumberStart !== void 0) {
|
|
1297
|
+
const fmt = s.pageNumberFormat !== void 0 ? ` w:fmt="${s.pageNumberFormat}"` : "";
|
|
1298
|
+
const start = s.pageNumberStart !== void 0 ? ` w:start="${String(s.pageNumberStart)}"` : "";
|
|
1299
|
+
parts.push(`<w:pgNumType${fmt}${start}/>`);
|
|
1300
|
+
}
|
|
1107
1301
|
if (s.columns) parts.push(colsXml(s.columns));
|
|
1108
1302
|
if (s.titlePg) parts.push("<w:titlePg/>");
|
|
1303
|
+
if (s.textDirection) parts.push(`<w:textDirection w:val="${s.textDirection}"/>`);
|
|
1109
1304
|
if (parts.length === 0) return "";
|
|
1110
1305
|
return `<w:sectPr>${parts.join("")}</w:sectPr>`;
|
|
1111
1306
|
}
|
|
@@ -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
|
|
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(
|
|
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
|