reamkit 1.29.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.
- package/README.md +60 -24
- package/dist/esm/core/converter/project.js +3 -1
- 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 +65 -0
- package/dist/esm/core/drawingml/shape-render.js +13 -1
- package/dist/esm/core/font/index.d.ts +2 -0
- 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/index.d.ts +1 -1
- 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.d.ts +8 -0
- package/dist/esm/core/fonts/remote-fonts.js +108 -18
- package/dist/esm/core/ir/flow.d.ts +88 -1
- 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/style-cascade/resolver.js +35 -4
- package/dist/esm/core/style-cascade/types.d.ts +19 -1
- package/dist/esm/core/style-cascade/types.js +3 -0
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/layout/page-doc.d.ts +10 -3
- package/dist/esm/layout/styled-layout.d.ts +48 -7
- package/dist/esm/layout/styled-layout.js +881 -119
- package/dist/esm/layout/turned-section.d.ts +38 -0
- package/dist/esm/layout/turned-section.js +193 -0
- package/dist/esm/pdf/styled-page-emitter.js +78 -2
- package/dist/esm/pdf-reader/annot-draw.js +93 -1
- package/dist/esm/pdf-reader/annots.d.ts +18 -0
- package/dist/esm/pdf-reader/annots.js +86 -9
- 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/cmap.js +5 -2
- package/dist/esm/pdf-reader/content.d.ts +70 -4
- package/dist/esm/pdf-reader/content.js +172 -12
- package/dist/esm/pdf-reader/display.d.ts +36 -0
- package/dist/esm/pdf-reader/display.js +82 -1
- package/dist/esm/pdf-reader/document.js +5 -1
- package/dist/esm/pdf-reader/embedded-fonts.d.ts +25 -0
- package/dist/esm/pdf-reader/embedded-fonts.js +78 -9
- 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 +224 -7
- package/dist/esm/pdf-reader/flow-build.js +545 -39
- package/dist/esm/pdf-reader/font.d.ts +27 -1
- package/dist/esm/pdf-reader/font.js +632 -63
- package/dist/esm/pdf-reader/glyf-outline.d.ts +33 -0
- package/dist/esm/pdf-reader/glyf-outline.js +148 -3
- package/dist/esm/pdf-reader/glyph-names.js +154 -1
- package/dist/esm/pdf-reader/glyph-shapes.d.ts +18 -0
- package/dist/esm/pdf-reader/glyph-shapes.js +57 -0
- package/dist/esm/pdf-reader/image-decode.js +70 -4
- package/dist/esm/pdf-reader/images.d.ts +5 -0
- package/dist/esm/pdf-reader/images.js +4 -2
- package/dist/esm/pdf-reader/jbig2.d.ts +40 -1
- package/dist/esm/pdf-reader/jbig2.js +78 -16
- package/dist/esm/pdf-reader/jpeg.d.ts +6 -3
- package/dist/esm/pdf-reader/jpeg.js +21 -1
- package/dist/esm/pdf-reader/layout.d.ts +119 -2
- package/dist/esm/pdf-reader/layout.js +2219 -184
- package/dist/esm/pdf-reader/lexer.d.ts +10 -0
- package/dist/esm/pdf-reader/lexer.js +17 -0
- 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/pattern-tint.d.ts +11 -1
- package/dist/esm/pdf-reader/pattern-tint.js +21 -3
- package/dist/esm/pdf-reader/regions.d.ts +25 -0
- package/dist/esm/pdf-reader/regions.js +167 -0
- package/dist/esm/pdf-reader/shading.d.ts +58 -2
- package/dist/esm/pdf-reader/shading.js +181 -11
- package/dist/esm/pdf-reader/struct-tree.js +112 -8
- package/dist/esm/pdf-reader/tagged.js +207 -28
- package/dist/esm/pdf-reader/text-rules.js +1 -1
- package/dist/esm/pdf-reader/text.d.ts +6 -3
- package/dist/esm/pdf-reader/text.js +106 -22
- 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.d.ts +8 -2
- package/dist/esm/pdf-reader/vector.js +105 -6
- 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 +341 -54
- package/dist/esm/word/drawing-parser.d.ts +5 -3
- package/dist/esm/word/drawing-parser.js +56 -10
- 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 +16 -2
- package/dist/esm/word/run-properties.js +26 -0
- package/package.json +12 -5
|
@@ -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);
|
|
@@ -17,6 +18,15 @@ var REL_NUMBERING = "http://schemas.openxmlformats.org/officeDocument/2006/relat
|
|
|
17
18
|
var REL_HYPERLINK = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
|
18
19
|
var REL_IMAGE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
|
19
20
|
var NUMBERING_PART = "word/numbering.xml";
|
|
21
|
+
var REL_FONT_TABLE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
|
|
22
|
+
var FONT_TABLE_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml";
|
|
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";
|
|
20
30
|
var REL_FOOTNOTES = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
|
|
21
31
|
var REL_ENDNOTES = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes";
|
|
22
32
|
var FOOTNOTES_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml";
|
|
@@ -30,6 +40,20 @@ var REL_COMMENTS_EXTENDED = "http://schemas.microsoft.com/office/2011/relationsh
|
|
|
30
40
|
var COMMENTS_EXTENDED_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml";
|
|
31
41
|
var COMMENTS_EXTENDED_PART = "word/commentsExtended.xml";
|
|
32
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
|
+
}
|
|
33
57
|
var W15_NS = "http://schemas.microsoft.com/office/word/2012/wordml";
|
|
34
58
|
var REL_CHART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
|
|
35
59
|
var CHART_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml";
|
|
@@ -127,7 +151,12 @@ function writeDocx(flow) {
|
|
|
127
151
|
drawingSeq: 0,
|
|
128
152
|
chartParts: [],
|
|
129
153
|
chartSeq: 0,
|
|
130
|
-
...flow.charts ? { charts: flow.charts } : {}
|
|
154
|
+
...flow.charts ? { charts: flow.charts } : {},
|
|
155
|
+
...flow.faceFamilies ? { faceFamilies: flow.faceFamilies } : {},
|
|
156
|
+
familiesUsed: /* @__PURE__ */ new Map(),
|
|
157
|
+
...flow.faceOutlines ? { faceOutlines: flow.faceOutlines } : {},
|
|
158
|
+
facesUsed: /* @__PURE__ */ new Set(),
|
|
159
|
+
zRanks: zRanksOf(flow)
|
|
131
160
|
};
|
|
132
161
|
const docScope = newScope();
|
|
133
162
|
const extraParts = [];
|
|
@@ -147,7 +176,8 @@ function writeDocx(flow) {
|
|
|
147
176
|
});
|
|
148
177
|
emitBody(body, flow.body, losses, state, docScope, sectPrByClosingIndex);
|
|
149
178
|
if (finalSectPr) body.push(finalSectPr);
|
|
150
|
-
const
|
|
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>`;
|
|
151
181
|
const numberingPart = flow.body.some((el) => el.kind === "paragraph" && el.paragraph.properties.numbering !== void 0) && flow.numbering ? {
|
|
152
182
|
path: NUMBERING_PART,
|
|
153
183
|
data: encoder.encode(numberingXml(flow.numbering)),
|
|
@@ -179,6 +209,45 @@ function writeDocx(flow) {
|
|
|
179
209
|
}, state, losses, docScope, extraParts, extraPartRels);
|
|
180
210
|
const commentParaIds = emitComments(flow.comments, state, losses, docScope, extraParts, extraPartRels);
|
|
181
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
|
+
});
|
|
217
|
+
const fontTablePart = state.familiesUsed.size > 0 ? {
|
|
218
|
+
path: FONT_TABLE_PART,
|
|
219
|
+
data: encoder.encode(fontTableXml(state.familiesUsed, embedded?.elements)),
|
|
220
|
+
contentType: FONT_TABLE_CONTENT_TYPE
|
|
221
|
+
} : void 0;
|
|
222
|
+
if (fontTablePart) docScope.rels.push({
|
|
223
|
+
id: `rId${++docScope.relSeq}`,
|
|
224
|
+
type: REL_FONT_TABLE,
|
|
225
|
+
target: "fontTable.xml",
|
|
226
|
+
targetMode: "Internal"
|
|
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
|
+
});
|
|
182
251
|
const partRelationships = [...docScope.rels.length > 0 ? [{
|
|
183
252
|
sourcePart: "word/document.xml",
|
|
184
253
|
relationships: docScope.rels
|
|
@@ -191,11 +260,16 @@ function writeDocx(flow) {
|
|
|
191
260
|
data: encoder.encode(documentXml),
|
|
192
261
|
contentType: DOC_CONTENT_TYPE
|
|
193
262
|
},
|
|
263
|
+
stylesPart,
|
|
194
264
|
...numberingPart ? [numberingPart] : [],
|
|
265
|
+
...fontTablePart ? [fontTablePart] : [],
|
|
266
|
+
...settingsPart ? [settingsPart] : [],
|
|
195
267
|
...extraParts,
|
|
196
268
|
...state.chartParts,
|
|
197
|
-
...state.mediaParts
|
|
269
|
+
...state.mediaParts,
|
|
270
|
+
...embedded?.parts ?? []
|
|
198
271
|
],
|
|
272
|
+
...(embedded?.parts.length ?? 0) > 0 ? { defaultsByExtension: { odttf: OBFUSCATED_FONT_CONTENT_TYPE } } : {},
|
|
199
273
|
rootRelationships: [{
|
|
200
274
|
id: "rId1",
|
|
201
275
|
type: REL_OFFICE_DOCUMENT,
|
|
@@ -207,6 +281,89 @@ function writeDocx(flow) {
|
|
|
207
281
|
losses
|
|
208
282
|
};
|
|
209
283
|
}
|
|
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>`;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* §20.4.2.3 `relativeHeight` — a float's z-order, written the way Word writes
|
|
331
|
+
* it: a rank over every z-order the document states, counted up from Word's
|
|
332
|
+
* own floor.
|
|
333
|
+
*
|
|
334
|
+
* The model's z-order is an ORDER, and may be any number. Written as it stood,
|
|
335
|
+
* a PDF's first two marks got 0 and 1 — which Word, and LibreOffice after it,
|
|
336
|
+
* read as "above everything": an "APPROVED" stamp's blue box came back over
|
|
337
|
+
* its own lettering. A tagged reading counts up from minus a million, and a
|
|
338
|
+
* negative number is not a value the attribute admits at all.
|
|
339
|
+
*/
|
|
340
|
+
function relativeHeight(zOrder, state) {
|
|
341
|
+
const at = (zOrder !== void 0 ? state.zRanks.get(zOrder) : void 0) ?? state.zRanks.size + ++state.drawingSeq;
|
|
342
|
+
const step = Math.max(1, Math.min(Z_STEP, Math.floor((Z_CEILING - Z_FLOOR) / Z_ROOM)));
|
|
343
|
+
return Math.min(Z_FLOOR + at * step, Z_CEILING);
|
|
344
|
+
}
|
|
345
|
+
/** Word's first float, and the highest value §20.4.2.3 lets a float take. */
|
|
346
|
+
var Z_FLOOR = 251658240;
|
|
347
|
+
var Z_CEILING = 503316479;
|
|
348
|
+
/** …and the step Word counts up in, while there is room for it. */
|
|
349
|
+
var Z_STEP = 1024;
|
|
350
|
+
var Z_ROOM = 1 << 17;
|
|
351
|
+
/** Every z-order the document's floats state, and each one's rank among them. */
|
|
352
|
+
function zRanksOf(flow) {
|
|
353
|
+
const seen = /* @__PURE__ */ new Set();
|
|
354
|
+
const visit = (blocks) => {
|
|
355
|
+
for (const el of blocks) {
|
|
356
|
+
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;
|
|
357
|
+
if (z !== void 0 && Number.isFinite(z)) seen.add(z);
|
|
358
|
+
if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
visit(flow.body);
|
|
362
|
+
for (const band of flow.headersFooters?.values() ?? []) visit(band);
|
|
363
|
+
for (const note of flow.footnotes?.values() ?? []) visit(note);
|
|
364
|
+
for (const note of flow.endnotes?.values() ?? []) visit(note);
|
|
365
|
+
return new Map([...seen].sort((a, b) => a - b).map((z, i) => [z, i]));
|
|
366
|
+
}
|
|
210
367
|
function emitNotes(notes, cfg, state, losses, docScope, extraParts, extraPartRels) {
|
|
211
368
|
if (!notes || notes.size === 0) return;
|
|
212
369
|
const scope = newScope();
|
|
@@ -218,7 +375,8 @@ function emitNotes(notes, cfg, state, losses, docScope, extraParts, extraPartRel
|
|
|
218
375
|
for (const el of content) emitBlock(inner, el, losses, state, scope);
|
|
219
376
|
noteXmls.push(`<${cfg.noteTag} w:id="${escapeAttr(id)}">${inner.join("") || "<w:p/>"}</${cfg.noteTag}>`);
|
|
220
377
|
}
|
|
221
|
-
const
|
|
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}>`;
|
|
222
380
|
extraParts.push({
|
|
223
381
|
path: cfg.partPath,
|
|
224
382
|
data: encoder.encode(xml),
|
|
@@ -324,7 +482,8 @@ function emitHeadersFooters(flow, section, state, docScope, extraParts, extraPar
|
|
|
324
482
|
const scope = newScope();
|
|
325
483
|
const inner = [];
|
|
326
484
|
for (const el of content) emitBlock(inner, el, losses, state, scope);
|
|
327
|
-
const
|
|
485
|
+
const bandXml = inner.join("");
|
|
486
|
+
const xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><${root}${rootNamespaces(bandXml)}>${bandXml}</${root}>`;
|
|
328
487
|
extraParts.push({
|
|
329
488
|
path,
|
|
330
489
|
data: encoder.encode(xml),
|
|
@@ -368,7 +527,7 @@ function emitHeadersFooters(flow, section, state, docScope, extraParts, extraPar
|
|
|
368
527
|
var docxWriter = {
|
|
369
528
|
id: "docx",
|
|
370
529
|
consumes: "flow",
|
|
371
|
-
supports: new Set([FEATURES.text]),
|
|
530
|
+
supports: new Set([FEATURES.text, FEATURES.fontsEmbedding]),
|
|
372
531
|
write: (doc) => writeDocx(doc)
|
|
373
532
|
};
|
|
374
533
|
/**
|
|
@@ -388,14 +547,17 @@ var docxWriter = {
|
|
|
388
547
|
*/
|
|
389
548
|
function emitBody(out, blocks, losses, state, scope, sectPrByClosingIndex) {
|
|
390
549
|
let carried = [];
|
|
550
|
+
let carrier;
|
|
391
551
|
const flush = () => {
|
|
392
|
-
if (carried.length > 0) out.push(`<w:p>${carried.join("")}</w:p>`);
|
|
552
|
+
if (carried.length > 0) out.push(`<w:p>${pPrWithSect(carrier ?? {})}${carried.join("")}</w:p>`);
|
|
393
553
|
carried = [];
|
|
554
|
+
carrier = void 0;
|
|
394
555
|
};
|
|
395
556
|
blocks.forEach((el, idx) => {
|
|
396
557
|
const closing = sectPrByClosingIndex.get(idx);
|
|
397
558
|
const anchored = closing === void 0 ? floatingDrawingRun(el, losses, state, scope) : void 0;
|
|
398
559
|
if (anchored !== void 0) {
|
|
560
|
+
carrier ??= el.kind === "image" ? el.image.paragraphProperties : el.kind === "shape" ? el.shape.paragraphProperties : void 0;
|
|
399
561
|
carried.push(anchored);
|
|
400
562
|
return;
|
|
401
563
|
}
|
|
@@ -411,7 +573,7 @@ function emitBody(out, blocks, losses, state, scope, sectPrByClosingIndex) {
|
|
|
411
573
|
*/
|
|
412
574
|
function floatingDrawingRun(el, losses, state, scope) {
|
|
413
575
|
if (el.kind === "image" && el.image.float) {
|
|
414
|
-
const drawing = drawingXml(el.image.resource, el.image.width, el.image.height, el.image.altText, state, scope, el.image.float);
|
|
576
|
+
const drawing = drawingXml(el.image.resource, el.image.width, el.image.height, el.image.altText, state, scope, el.image.float, el.image);
|
|
415
577
|
if (drawing === "") {
|
|
416
578
|
losses.push({
|
|
417
579
|
severity: "dropped",
|
|
@@ -435,7 +597,7 @@ function emitBlock(out, el, losses, state, scope, closingSectPr) {
|
|
|
435
597
|
return;
|
|
436
598
|
}
|
|
437
599
|
if (el.kind === "image") {
|
|
438
|
-
const drawing = drawingXml(el.image.resource, el.image.width, el.image.height, el.image.altText, state, scope, el.image.float);
|
|
600
|
+
const drawing = drawingXml(el.image.resource, el.image.width, el.image.height, el.image.altText, state, scope, el.image.float, el.image);
|
|
439
601
|
if (drawing) out.push(`<w:p>${pPrWithSect(el.image.paragraphProperties, closingSectPr)}<w:r>${drawing}</w:r></w:p>`);
|
|
440
602
|
else {
|
|
441
603
|
losses.push({
|
|
@@ -514,7 +676,7 @@ function drawingFrame(float, cx, cy, head, graphic, state, rotation60k) {
|
|
|
514
676
|
const emu = (pt) => Number.isFinite(pt) ? Math.round((pt ?? 0) * EMU_PER_PT) : 0;
|
|
515
677
|
const d = float.wrapDist;
|
|
516
678
|
const dist = ` distT="${String(emu(d?.topPt))}" distB="${String(emu(d?.bottomPt))}" distL="${String(emu(d?.leftPt))}" distR="${String(emu(d?.rightPt))}"`;
|
|
517
|
-
const z = float.zOrder
|
|
679
|
+
const z = relativeHeight(float.zOrder, state);
|
|
518
680
|
const attrs = `${dist} simplePos="0" relativeHeight="${String(z)}" behindDoc="${float.behind ? "1" : "0"}" locked="0" layoutInCell="${float.inCell === false ? "0" : "1"}" allowOverlap="1"`;
|
|
519
681
|
const pos = (tag, p, fallback) => {
|
|
520
682
|
const from = p?.relativeFrom ?? fallback;
|
|
@@ -550,7 +712,7 @@ function effectExtentXml(cx, cy, rotation60k) {
|
|
|
550
712
|
const v = overhang(cy, cx * s + cy * c);
|
|
551
713
|
return h === 0 && v === 0 ? none : `<wp:effectExtent l="${String(h)}" t="${String(v)}" r="${String(h)}" b="${String(v)}"/>`;
|
|
552
714
|
}
|
|
553
|
-
function drawingXml(resource, widthPt, heightPt, altText, state, scope, float) {
|
|
715
|
+
function drawingXml(resource, widthPt, heightPt, altText, state, scope, float, look) {
|
|
554
716
|
if (resource === void 0) return "";
|
|
555
717
|
const relId = mediaRelId(resource, state, scope);
|
|
556
718
|
if (relId === void 0) return "";
|
|
@@ -558,8 +720,15 @@ function drawingXml(resource, widthPt, heightPt, altText, state, scope, float) {
|
|
|
558
720
|
const cy = Math.round(heightPt * EMU_PER_PT);
|
|
559
721
|
const id = ++state.drawingSeq;
|
|
560
722
|
const descr = altText ? ` descr="${escapeAttr(altText)}"` : "";
|
|
561
|
-
const graphic = `<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><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}"
|
|
562
|
-
return drawingFrame(float, cx, cy, `<wp:docPr id="${id}" name="Image ${id}"${descr}/>`, graphic, state);
|
|
723
|
+
const graphic = `<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><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}">${look?.alpha !== void 0 && look.alpha < 1 ? `<a:alphaModFix amt="${String(Math.round(Math.max(0, look.alpha) * 1e5))}"/>` : ""}</a:blip>${srcRectXml(look?.crop)}<a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr>${xfrmXml(look, cx, cy)}<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic>`;
|
|
724
|
+
return drawingFrame(float, cx, cy, `<wp:docPr id="${id}" name="Image ${id}"${descr}/>`, graphic, state, look?.rotation60k);
|
|
725
|
+
}
|
|
726
|
+
/** §20.1.8.55 `a:srcRect` — each edge cut away, in thousandths of a percent. */
|
|
727
|
+
function srcRectXml(crop) {
|
|
728
|
+
if (!crop) return "";
|
|
729
|
+
const edge = (name, v) => v > 0 ? ` ${name}="${String(Math.round(v * 1e5))}"` : "";
|
|
730
|
+
const attrs = edge("l", crop.left) + edge("t", crop.top) + edge("r", crop.right) + edge("b", crop.bottom);
|
|
731
|
+
return attrs === "" ? "" : `<a:srcRect${attrs}/>`;
|
|
563
732
|
}
|
|
564
733
|
var WPS_URI = "http://schemas.microsoft.com/office/word/2010/wordprocessingShape";
|
|
565
734
|
function shapeDrawingXml(shape, losses, state, scope) {
|
|
@@ -567,13 +736,76 @@ function shapeDrawingXml(shape, losses, state, scope) {
|
|
|
567
736
|
const cy = Math.round(shape.height * EMU_PER_PT);
|
|
568
737
|
const id = ++state.drawingSeq;
|
|
569
738
|
const descr = shape.altText ? ` descr="${escapeAttr(shape.altText)}"` : "";
|
|
570
|
-
const
|
|
571
|
-
const
|
|
572
|
-
|
|
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>";
|
|
573
746
|
return drawingFrame(shape.float, cx, cy, `<wp:docPr id="${id}" name="Shape ${id}"${descr}/>`, graphic, state, shape.transform?.rotation60k);
|
|
574
747
|
}
|
|
575
|
-
|
|
576
|
-
|
|
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>`;
|
|
577
809
|
}
|
|
578
810
|
/**
|
|
579
811
|
* The factor that carries a path into whole units, and the space it lands in.
|
|
@@ -599,7 +831,7 @@ function pathScale(g) {
|
|
|
599
831
|
else if (c.cmd === "quad") values.push(c.x1, c.y1, c.x, c.y);
|
|
600
832
|
else if (c.cmd === "arc") values.push(c.wR, c.hR);
|
|
601
833
|
if (values.every((v) => Number.isInteger(v))) return 1;
|
|
602
|
-
const span =
|
|
834
|
+
const span = values.reduce((most, v) => Number.isFinite(v) ? Math.max(most, Math.abs(v)) : most, 1);
|
|
603
835
|
return Math.max(1, Math.floor(PATH_SPACE / span));
|
|
604
836
|
}
|
|
605
837
|
function geomXml(g) {
|
|
@@ -624,13 +856,24 @@ function geomXml(g) {
|
|
|
624
856
|
return `<a:prstGeom prst="${escapeAttr(g.preset ?? "rect")}"><a:avLst>${gds}</a:avLst></a:prstGeom>`;
|
|
625
857
|
}
|
|
626
858
|
function fillXml(f) {
|
|
627
|
-
if (f.kind === "solid" && f.colorHex) return `<a:solidFill
|
|
628
|
-
if (f.kind === "gradient" && f.gradient) return gradFillXml(f.gradient);
|
|
859
|
+
if (f.kind === "solid" && f.colorHex) return `<a:solidFill>${srgbXml(f.colorHex, f.alpha)}</a:solidFill>`;
|
|
860
|
+
if (f.kind === "gradient" && f.gradient) return gradFillXml(f.gradient, f.alpha);
|
|
629
861
|
return "<a:noFill/>";
|
|
630
862
|
}
|
|
631
|
-
|
|
863
|
+
/**
|
|
864
|
+
* §20.1.2.3.19 `a:srgbClr`, with the §20.1.2.3.1 `a:alpha` of a fill that is
|
|
865
|
+
* seen through. The model carried the opacity and the writer dropped it:
|
|
866
|
+
* bug1755507.pdf lays a card on a shadow painted at a fifth of full strength,
|
|
867
|
+
* and the shadow came back as a solid black slab around the card.
|
|
868
|
+
*/
|
|
869
|
+
function srgbXml(colorHex, alpha) {
|
|
870
|
+
if (alpha === void 0 || !(alpha < 1)) return `<a:srgbClr val="${colorHex}"/>`;
|
|
871
|
+
const val = Math.round(Math.max(0, alpha) * 1e5);
|
|
872
|
+
return `<a:srgbClr val="${colorHex}"><a:alpha val="${String(val)}"/></a:srgbClr>`;
|
|
873
|
+
}
|
|
874
|
+
function gradFillXml(g, alpha) {
|
|
632
875
|
return `<a:gradFill><a:gsLst>${g.stops.map((s) => {
|
|
633
|
-
return `<a:gs pos="${Math.round(Math.max(0, Math.min(1, s.offset)) * 1e5)}"
|
|
876
|
+
return `<a:gs pos="${Math.round(Math.max(0, Math.min(1, s.offset)) * 1e5)}">${srgbXml(s.colorHex, alpha)}</a:gs>`;
|
|
634
877
|
}).join("")}</a:gsLst>${g.kind === "radial" ? "<a:path path=\"circle\"/>" : `<a:lin ang="${Math.round(((g.angle ?? 0) % 360 + 360) % 360 * 6e4)}" scaled="1"/>`}</a:gradFill>`;
|
|
635
878
|
}
|
|
636
879
|
function lineXml(l) {
|
|
@@ -638,8 +881,13 @@ function lineXml(l) {
|
|
|
638
881
|
const cap = l.cap === "round" ? " cap=\"rnd\"" : l.cap === "square" ? " cap=\"sq\"" : l.cap === "flat" ? " cap=\"flat\"" : "";
|
|
639
882
|
const inner = [];
|
|
640
883
|
if (l.fill === "none") inner.push("<a:noFill/>");
|
|
641
|
-
else if (l.colorHex) inner.push(`<a:solidFill
|
|
642
|
-
|
|
884
|
+
else if (l.colorHex) inner.push(`<a:solidFill>${srgbXml(l.colorHex, l.alpha)}</a:solidFill>`);
|
|
885
|
+
const custom = l.customDash ?? [];
|
|
886
|
+
if (custom.length >= 2) {
|
|
887
|
+
const pairs = [];
|
|
888
|
+
for (let i = 0; i + 1 < custom.length; i += 2) pairs.push(`<a:ds d="${Math.round(custom[i] * 1e5)}" sp="${Math.round(custom[i + 1] * 1e5)}"/>`);
|
|
889
|
+
inner.push(`<a:custDash>${pairs.join("")}</a:custDash>`);
|
|
890
|
+
} else if (l.dash) inner.push(`<a:prstDash val="${l.dash}"/>`);
|
|
643
891
|
return `<a:ln${w}${cap}>${inner.join("")}</a:ln>`;
|
|
644
892
|
}
|
|
645
893
|
function txbxXml(text, losses, state, scope) {
|
|
@@ -651,7 +899,7 @@ function bodyPrXml(text) {
|
|
|
651
899
|
if (!text) return "<wps:bodyPr/>";
|
|
652
900
|
const ins = (v, name) => v !== void 0 ? ` ${name}="${Math.round(v * EMU_PER_PT)}"` : "";
|
|
653
901
|
const anchor = text.anchor ? ` anchor="${text.anchor}"` : "";
|
|
654
|
-
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 + "/>";
|
|
655
903
|
}
|
|
656
904
|
function mediaRelId(resource, state, scope) {
|
|
657
905
|
const existingRel = scope.relIdByResource.get(resource);
|
|
@@ -702,8 +950,10 @@ function tblPrXml(p) {
|
|
|
702
950
|
out.push(`<w:tblW w:w="${w}" w:type="${p.widthType}"/>`);
|
|
703
951
|
}
|
|
704
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"/>`);
|
|
705
954
|
const borders = bordersXml("w:tblBorders", p.borders);
|
|
706
955
|
if (borders) out.push(borders);
|
|
956
|
+
if (p.layout === "fixed") out.push("<w:tblLayout w:type=\"fixed\"/>");
|
|
707
957
|
const margins = cellMarginsXml("w:tblCellMar", p.defaultCellMargins);
|
|
708
958
|
if (margins) out.push(margins);
|
|
709
959
|
return `<w:tblPr>${out.join("")}</w:tblPr>`;
|
|
@@ -747,15 +997,20 @@ var BORDER_SIDES = [
|
|
|
747
997
|
];
|
|
748
998
|
function bordersXml(tag, borders) {
|
|
749
999
|
if (!borders) return "";
|
|
750
|
-
const sides = BORDER_SIDES.map(([key,
|
|
1000
|
+
const sides = BORDER_SIDES.map(([key, name]) => {
|
|
751
1001
|
const b = borders[key];
|
|
752
1002
|
if (!b) return "";
|
|
1003
|
+
if (tag === "w:pBdr" && key === "insideV") return "";
|
|
1004
|
+
const el = tag === "w:pBdr" && key === "insideH" ? "w:between" : name;
|
|
753
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)}"` : "";
|
|
754
1007
|
const color = b.colorHex !== void 0 ? ` w:color="${b.colorHex}"` : "";
|
|
755
|
-
return `<${el} w:val="${b.style}"${sz}${color}/>`;
|
|
1008
|
+
return `<${el} w:val="${b.style}"${sz}${space}${color}/>`;
|
|
756
1009
|
}).join("");
|
|
757
1010
|
return sides ? `<${tag}>${sides}</${tag}>` : "";
|
|
758
1011
|
}
|
|
1012
|
+
/** §17.3.4 — the farthest a border may stand off its text, in points. */
|
|
1013
|
+
var MOST_BORDER_SPACE_PT = 31;
|
|
759
1014
|
function cellMarginsXml(tag, margins) {
|
|
760
1015
|
if (!margins) return "";
|
|
761
1016
|
const inner = [
|
|
@@ -809,10 +1064,10 @@ function hyperlinkXml(run, inner, _state, scope) {
|
|
|
809
1064
|
}
|
|
810
1065
|
function runXml(run, state, scope) {
|
|
811
1066
|
if (run.math !== void 0) return `<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">${omathXml(run.math)}</m:oMath>`;
|
|
812
|
-
const rPr = rPrXml(run.properties);
|
|
1067
|
+
const rPr = rPrXml(run.properties, state);
|
|
813
1068
|
if (run.inlineImage !== void 0) {
|
|
814
1069
|
const img = run.inlineImage;
|
|
815
|
-
const drawing = drawingXml(img.resource, img.width, img.height, void 0, state, scope);
|
|
1070
|
+
const drawing = drawingXml(img.resource, img.width, img.height, void 0, state, scope, void 0, img);
|
|
816
1071
|
if (drawing) return `<w:r>${rPr}${drawing}</w:r>`;
|
|
817
1072
|
if (run.text === "" && !run.pageBreak) return "";
|
|
818
1073
|
}
|
|
@@ -822,27 +1077,41 @@ function runXml(run, state, scope) {
|
|
|
822
1077
|
if (run.commentRef !== void 0) return `<w:r>${rPr}<w:commentReference w:id="${escapeAttr(run.commentRef)}"/></w:r>`;
|
|
823
1078
|
const brk = run.pageBreak ? "<w:br w:type=\"page\"/>" : "";
|
|
824
1079
|
if (run.field !== void 0 && run.text !== "") {
|
|
825
|
-
const
|
|
826
|
-
return
|
|
1080
|
+
const piece = (inner) => `<w:r>${rPr}${inner}</w:r>`;
|
|
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;
|
|
827
1082
|
}
|
|
828
1083
|
if (run.text === "") return brk ? `<w:r>${rPr}${brk}</w:r>` : "";
|
|
829
|
-
|
|
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>`;
|
|
830
1086
|
}
|
|
831
|
-
function rPrXml(r) {
|
|
1087
|
+
function rPrXml(r, state) {
|
|
832
1088
|
const out = [];
|
|
833
1089
|
const states = (key) => r[key] !== void 0 && r[key] !== DEFAULT_RUN[key];
|
|
834
|
-
const fonts = rFontsXml(r.fontFamily);
|
|
1090
|
+
const fonts = rFontsXml(r.fontFamily, state);
|
|
835
1091
|
if (fonts) out.push(fonts);
|
|
836
|
-
if (states("bold")) out.push(toggle("w:b", r.bold));
|
|
837
|
-
if (states("italic")) out.push(toggle("w:i", r.italic));
|
|
1092
|
+
if (states("bold")) out.push(toggle("w:b", r.bold), toggle("w:bCs", r.bold));
|
|
1093
|
+
if (states("italic")) out.push(toggle("w:i", r.italic), toggle("w:iCs", r.italic));
|
|
838
1094
|
if (states("strike")) out.push(toggle("w:strike", r.strike));
|
|
839
1095
|
if (states("colorHex")) out.push(`<w:color w:val="${r.colorHex}"/>`);
|
|
840
|
-
if (
|
|
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)}"/>`);
|
|
1105
|
+
if (states("fontSizePt")) {
|
|
1106
|
+
const half = Math.round(r.fontSizePt * 2);
|
|
1107
|
+
out.push(`<w:sz w:val="${half}"/>`, `<w:szCs w:val="${half}"/>`);
|
|
1108
|
+
}
|
|
841
1109
|
if (states("underline")) out.push(underlineXml(r));
|
|
842
1110
|
if (r.shadingColorHex !== void 0) out.push(runShdXml(r.shadingColorHex));
|
|
843
1111
|
if (states("verticalAlign")) out.push(`<w:vertAlign w:val="${r.verticalAlign}"/>`);
|
|
844
1112
|
if (states("rtl")) out.push(toggle("w:rtl", r.rtl));
|
|
845
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}"/>`);
|
|
846
1115
|
return out.length > 0 ? `<w:rPr>${out.join("")}</w:rPr>` : "";
|
|
847
1116
|
}
|
|
848
1117
|
function underlineXml(r) {
|
|
@@ -854,17 +1123,14 @@ function runShdXml(fill) {
|
|
|
854
1123
|
}
|
|
855
1124
|
function pPrBody(p) {
|
|
856
1125
|
const out = [];
|
|
857
|
-
if (p.
|
|
858
|
-
if (p.
|
|
1126
|
+
if (p.keepNext) out.push("<w:keepNext/>");
|
|
1127
|
+
if (p.keepLines) out.push("<w:keepLines/>");
|
|
859
1128
|
if (p.pageBreakBefore) out.push("<w:pageBreakBefore/>");
|
|
860
|
-
if (p.
|
|
861
|
-
|
|
862
|
-
if (ind) out.push(ind);
|
|
863
|
-
const spacing = spacingXml(p);
|
|
864
|
-
if (spacing) out.push(spacing);
|
|
865
|
-
if (JC.has(p.alignment) && p.alignment !== DEFAULT_PARA.alignment) out.push(`<w:jc w:val="${p.alignment}"/>`);
|
|
1129
|
+
if (p.widowControl === false) out.push("<w:widowControl w:val=\"0\"/>");
|
|
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>`);
|
|
866
1131
|
const pBdr = bordersXml("w:pBdr", p.borders);
|
|
867
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}"/>`);
|
|
868
1134
|
const tabs = p.tabs ?? [];
|
|
869
1135
|
if (tabs.length > 0) {
|
|
870
1136
|
const stops = tabs.map((t) => {
|
|
@@ -874,6 +1140,13 @@ function pPrBody(p) {
|
|
|
874
1140
|
}).join("");
|
|
875
1141
|
out.push(`<w:tabs>${stops}</w:tabs>`);
|
|
876
1142
|
}
|
|
1143
|
+
if (p.bidi !== void 0 && p.bidi !== DEFAULT_PARA.bidi) out.push(toggle("w:bidi", p.bidi));
|
|
1144
|
+
const spacing = spacingXml(p);
|
|
1145
|
+
if (spacing) out.push(spacing);
|
|
1146
|
+
const ind = indXml(p);
|
|
1147
|
+
if (ind) out.push(ind);
|
|
1148
|
+
if (JC.has(p.alignment) && p.alignment !== DEFAULT_PARA.alignment) out.push(`<w:jc w:val="${p.alignment}"/>`);
|
|
1149
|
+
if (p.outlineLevel !== void 0) out.push(`<w:outlineLvl w:val="${p.outlineLevel}"/>`);
|
|
877
1150
|
return out.join("");
|
|
878
1151
|
}
|
|
879
1152
|
function pPrWithSect(p, closingSectPr) {
|
|
@@ -914,18 +1187,26 @@ function spacingXml(p) {
|
|
|
914
1187
|
const attrs = [];
|
|
915
1188
|
if (stated(p.spacingBefore) && p.spacingBefore !== DEFAULT_PARA.spacingBefore) attrs.push(`w:before="${twips(p.spacingBefore)}"`);
|
|
916
1189
|
if (stated(p.spacingAfter) && p.spacingAfter !== DEFAULT_PARA.spacingAfter) attrs.push(`w:after="${twips(p.spacingAfter)}"`);
|
|
917
|
-
if ((p.spacingLineRule !== DEFAULT_PARA.spacingLineRule || p.spacingLine !== DEFAULT_PARA.spacingLine) && p.spacingLine > 0) {
|
|
918
|
-
const lineVal = p.spacingLineRule === "auto" ? Math.round(p.spacingLine * 12) : twips(p.spacingLine);
|
|
919
|
-
attrs.push(`w:line="${lineVal}"`, `w:lineRule="${p.spacingLineRule}"`);
|
|
920
|
-
}
|
|
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}"`);
|
|
921
1191
|
return attrs.length > 0 ? `<w:spacing ${attrs.join(" ")}/>` : "";
|
|
922
1192
|
}
|
|
923
|
-
function rFontsXml(fonts) {
|
|
1193
|
+
function rFontsXml(fonts, state) {
|
|
1194
|
+
if (fonts === void 0) return "";
|
|
924
1195
|
const d = DEFAULT_RUN.fontFamily;
|
|
1196
|
+
const family = (name) => {
|
|
1197
|
+
const known = state?.faceFamilies?.get(name);
|
|
1198
|
+
if (known === void 0) return name;
|
|
1199
|
+
state?.familiesUsed.set(known.family, known);
|
|
1200
|
+
if (state?.faceOutlines?.has(name) === true) state.facesUsed.add(name);
|
|
1201
|
+
return known.family;
|
|
1202
|
+
};
|
|
925
1203
|
const attrs = [];
|
|
926
|
-
if (fonts.ascii && fonts.ascii !== d.ascii) attrs.push(`w:ascii="${escapeAttr(fonts.ascii)}"`);
|
|
927
|
-
if (fonts.hAnsi && fonts.hAnsi !== d.hAnsi) attrs.push(`w:hAnsi="${escapeAttr(fonts.hAnsi)}"`);
|
|
928
|
-
|
|
1204
|
+
if (fonts.ascii && fonts.ascii !== d.ascii) attrs.push(`w:ascii="${escapeAttr(family(fonts.ascii))}"`);
|
|
1205
|
+
if (fonts.hAnsi && fonts.hAnsi !== d.hAnsi) attrs.push(`w:hAnsi="${escapeAttr(family(fonts.hAnsi))}"`);
|
|
1206
|
+
const face = fonts.ascii !== void 0 && state?.faceFamilies?.has(fonts.ascii) === true ? family(fonts.ascii) : void 0;
|
|
1207
|
+
if (face !== void 0 && fonts.eastAsia === void 0) attrs.push(`w:eastAsia="${escapeAttr(face)}"`);
|
|
1208
|
+
if (fonts.cs && fonts.cs !== d.cs) attrs.push(`w:cs="${escapeAttr(family(fonts.cs))}"`);
|
|
1209
|
+
else if (face !== void 0) attrs.push(`w:cs="${escapeAttr(face)}"`);
|
|
929
1210
|
return attrs.length > 0 ? `<w:rFonts ${attrs.join(" ")}/>` : "";
|
|
930
1211
|
}
|
|
931
1212
|
function toggle(tag, on) {
|
|
@@ -1003,8 +1284,14 @@ function sectPrXml(s, hf) {
|
|
|
1003
1284
|
const footer = m.footer !== void 0 ? ` w:footer="${twips(m.footer)}"` : "";
|
|
1004
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}/>`);
|
|
1005
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
|
+
}
|
|
1006
1292
|
if (s.columns) parts.push(colsXml(s.columns));
|
|
1007
1293
|
if (s.titlePg) parts.push("<w:titlePg/>");
|
|
1294
|
+
if (s.textDirection) parts.push(`<w:textDirection w:val="${s.textDirection}"/>`);
|
|
1008
1295
|
if (parts.length === 0) return "";
|
|
1009
1296
|
return `<w:sectPr>${parts.join("")}</w:sectPr>`;
|
|
1010
1297
|
}
|