reamkit 1.1.0 → 1.2.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 +9 -4
- package/dist/esm/{layout → core}/arc-to-bezier.d.ts +1 -1
- package/dist/esm/{layout → core}/arc-to-bezier.js +2 -2
- package/dist/esm/core/converter/project.js +2 -0
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +58 -0
- package/dist/esm/{layout → core/drawingml}/chart-geometry.d.ts +1 -1
- package/dist/esm/{layout → core/drawingml}/preset-geometry.d.ts +2 -2
- package/dist/esm/{layout → core/drawingml}/preset-geometry.js +3 -3
- package/dist/esm/core/drawingml/shape-render.d.ts +8 -0
- package/dist/esm/core/drawingml/shape-render.js +71 -0
- package/dist/esm/core/ir/features.d.ts +1 -0
- package/dist/esm/core/ir/features.js +1 -0
- package/dist/esm/core/ir/flow.d.ts +3 -0
- package/dist/esm/core/links.d.ts +6 -0
- package/dist/esm/core/links.js +19 -0
- package/dist/esm/core/numbering/apply.js +3 -1
- package/dist/esm/core/style-cascade/index.d.ts +1 -0
- package/dist/esm/core/style-cascade/index.js +1 -0
- package/dist/esm/core/style-cascade/table.d.ts +2 -0
- package/dist/esm/core/style-cascade/table.js +161 -0
- package/dist/esm/core/vector.d.ts +2 -0
- package/dist/esm/core/vector.js +19 -1
- package/dist/esm/html/html-writer.js +188 -16
- package/dist/esm/layout/page-doc.d.ts +3 -0
- package/dist/esm/layout/styled-layout.d.ts +19 -3
- package/dist/esm/layout/styled-layout.js +533 -197
- package/dist/esm/pdf/struct-tree.d.ts +7 -1
- package/dist/esm/pdf/struct-tree.js +22 -6
- package/dist/esm/pdf/styled-page-emitter.d.ts +1 -1
- package/dist/esm/pdf/styled-page-emitter.js +161 -29
- package/dist/esm/pdf/xmp.d.ts +1 -0
- package/dist/esm/pdf/xmp.js +4 -0
- package/dist/esm/svg/svg-writer.js +2 -6
- package/dist/esm/word/document-parser.d.ts +3 -0
- package/dist/esm/word/document-parser.js +210 -23
- package/dist/esm/word/docx-reader.js +30 -4
- package/dist/esm/word/drawing-parser.d.ts +4 -1
- package/dist/esm/word/drawing-parser.js +53 -2
- package/dist/esm/word/index.d.ts +2 -2
- package/dist/esm/word/styles-parser.js +134 -1
- package/dist/esm/word/table-parser.js +35 -0
- package/package.json +1 -1
- /package/dist/esm/{layout → core/drawingml}/chart-geometry.js +0 -0
|
@@ -11,11 +11,12 @@ import { applyNumbering, applyNumberingToHeadersFooters } from "../core/numberin
|
|
|
11
11
|
import { DEFAULT_RESOLVED_PARAGRAPH, DEFAULT_RESOLVED_RUN } from "../core/style-cascade/types.js";
|
|
12
12
|
import { resolveParagraphProperties, resolveRunProperties } from "../core/style-cascade/resolver.js";
|
|
13
13
|
import "../core/style-cascade/index.js";
|
|
14
|
-
import { PathBuilder } from "../core/vector.js";
|
|
15
|
-
import { arcPoint, arcToBeziers } from "
|
|
16
|
-
import { buildChartScene } from "
|
|
14
|
+
import { PathBuilder, flipTransform } from "../core/vector.js";
|
|
15
|
+
import { arcPoint, arcToBeziers } from "../core/arc-to-bezier.js";
|
|
16
|
+
import { buildChartScene } from "../core/drawingml/chart-geometry.js";
|
|
17
17
|
import { layoutMath, mathGlyphSegments, variantStyle } from "./math-layout.js";
|
|
18
|
-
import {
|
|
18
|
+
import { rectPath } from "../core/drawingml/preset-geometry.js";
|
|
19
|
+
import { buildShapePaths, buildShapeTransform, buildStroke } from "../core/drawingml/shape-render.js";
|
|
19
20
|
import { StructTreeBuilder } from "../pdf/struct-tree.js";
|
|
20
21
|
//#region src/layout/styled-layout.ts
|
|
21
22
|
function parsePdfAProfile(pdfA) {
|
|
@@ -32,23 +33,199 @@ var TWIP_TO_PT = 1 / 20;
|
|
|
32
33
|
var EIGHTH_PT = 1 / 8;
|
|
33
34
|
var DEFAULT_CELL_PADDING_TWIPS = 108;
|
|
34
35
|
var DEFAULT_BORDER_SIZE_EIGHTH = 4;
|
|
36
|
+
var FOOTNOTE_RULE_PT = .75;
|
|
37
|
+
var FOOTNOTE_RULE_GAP_ABOVE = 4;
|
|
38
|
+
var FOOTNOTE_SEPARATOR_HEIGHT = 10;
|
|
39
|
+
var FOOTNOTE_RULE_WIDTH = 144;
|
|
40
|
+
function assignNoteNumbers(body) {
|
|
41
|
+
const footnotes = /* @__PURE__ */ new Map();
|
|
42
|
+
const endnotes = /* @__PURE__ */ new Map();
|
|
43
|
+
const paragraphFootnotes = /* @__PURE__ */ new Set();
|
|
44
|
+
const numberRun = (run, n) => ({
|
|
45
|
+
...run,
|
|
46
|
+
text: String(n),
|
|
47
|
+
properties: {
|
|
48
|
+
...run.properties,
|
|
49
|
+
verticalAlign: "superscript"
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
const mapParagraph = (paragraph) => {
|
|
53
|
+
if (!paragraph.runs.some((r) => r.footnoteRef !== void 0 || r.endnoteRef !== void 0)) return paragraph;
|
|
54
|
+
return {
|
|
55
|
+
...paragraph,
|
|
56
|
+
runs: paragraph.runs.map((run) => {
|
|
57
|
+
if (run.footnoteRef !== void 0) {
|
|
58
|
+
let n = footnotes.get(run.footnoteRef);
|
|
59
|
+
if (n === void 0) {
|
|
60
|
+
n = footnotes.size + 1;
|
|
61
|
+
footnotes.set(run.footnoteRef, n);
|
|
62
|
+
}
|
|
63
|
+
return numberRun(run, n);
|
|
64
|
+
}
|
|
65
|
+
if (run.endnoteRef !== void 0) {
|
|
66
|
+
let n = endnotes.get(run.endnoteRef);
|
|
67
|
+
if (n === void 0) {
|
|
68
|
+
n = endnotes.size + 1;
|
|
69
|
+
endnotes.set(run.endnoteRef, n);
|
|
70
|
+
}
|
|
71
|
+
return numberRun(run, n);
|
|
72
|
+
}
|
|
73
|
+
return run;
|
|
74
|
+
})
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
const mapElement = (el, topLevel) => {
|
|
78
|
+
if (el.kind === "paragraph") {
|
|
79
|
+
if (topLevel) {
|
|
80
|
+
for (const r of el.paragraph.runs) if (r.footnoteRef !== void 0) paragraphFootnotes.add(r.footnoteRef);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
kind: "paragraph",
|
|
84
|
+
paragraph: mapParagraph(el.paragraph)
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
if (el.kind === "table") return {
|
|
88
|
+
kind: "table",
|
|
89
|
+
table: {
|
|
90
|
+
...el.table,
|
|
91
|
+
rows: el.table.rows.map((row) => ({
|
|
92
|
+
...row,
|
|
93
|
+
cells: row.cells.map((cell) => ({
|
|
94
|
+
...cell,
|
|
95
|
+
content: cell.content.map((c) => mapElement(c, false))
|
|
96
|
+
}))
|
|
97
|
+
}))
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
if (el.kind === "shape" && el.shape.text) return {
|
|
101
|
+
kind: "shape",
|
|
102
|
+
shape: {
|
|
103
|
+
...el.shape,
|
|
104
|
+
text: {
|
|
105
|
+
...el.shape.text,
|
|
106
|
+
content: el.shape.text.content.map((c) => mapElement(c, false))
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
return el;
|
|
111
|
+
};
|
|
112
|
+
const hasRefs = (els) => els.some((el) => {
|
|
113
|
+
if (el.kind === "paragraph") return el.paragraph.runs.some((r) => r.footnoteRef !== void 0 || r.endnoteRef !== void 0);
|
|
114
|
+
if (el.kind === "table") return el.table.rows.some((row) => row.cells.some((c) => hasRefs(c.content)));
|
|
115
|
+
if (el.kind === "shape" && el.shape.text) return hasRefs(el.shape.text.content);
|
|
116
|
+
return false;
|
|
117
|
+
});
|
|
118
|
+
if (!hasRefs(body)) return {
|
|
119
|
+
body,
|
|
120
|
+
footnotes,
|
|
121
|
+
endnotes,
|
|
122
|
+
deferredFootnotes: []
|
|
123
|
+
};
|
|
124
|
+
return {
|
|
125
|
+
body: body.map((el) => mapElement(el, true)),
|
|
126
|
+
footnotes,
|
|
127
|
+
endnotes,
|
|
128
|
+
deferredFootnotes: [...footnotes.keys()].filter((id) => !paragraphFootnotes.has(id))
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function substituteNoteNumber(content, n) {
|
|
132
|
+
const hasPlaceholder = content.some((el) => el.kind === "paragraph" && el.paragraph.runs.some((r) => r.noteNumber));
|
|
133
|
+
const out = content.map((el) => {
|
|
134
|
+
if (el.kind !== "paragraph") return el;
|
|
135
|
+
if (!el.paragraph.runs.some((r) => r.noteNumber)) return el;
|
|
136
|
+
return {
|
|
137
|
+
kind: "paragraph",
|
|
138
|
+
paragraph: {
|
|
139
|
+
...el.paragraph,
|
|
140
|
+
runs: el.paragraph.runs.map((r) => r.noteNumber ? {
|
|
141
|
+
...r,
|
|
142
|
+
text: String(n),
|
|
143
|
+
properties: {
|
|
144
|
+
...r.properties,
|
|
145
|
+
verticalAlign: "superscript"
|
|
146
|
+
}
|
|
147
|
+
} : r)
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
if (hasPlaceholder || out.length === 0) return out;
|
|
152
|
+
const first = out[0];
|
|
153
|
+
if (first.kind !== "paragraph") return out;
|
|
154
|
+
return [{
|
|
155
|
+
kind: "paragraph",
|
|
156
|
+
paragraph: {
|
|
157
|
+
...first.paragraph,
|
|
158
|
+
runs: [{
|
|
159
|
+
text: `${n} `,
|
|
160
|
+
properties: { verticalAlign: "superscript" }
|
|
161
|
+
}, ...first.paragraph.runs]
|
|
162
|
+
}
|
|
163
|
+
}, ...out.slice(1)];
|
|
164
|
+
}
|
|
35
165
|
function layoutStyledDocument(body, options) {
|
|
36
166
|
const sectionList = resolveSectionList(body, options);
|
|
37
|
-
const
|
|
167
|
+
const noteAssigned = assignNoteNumbers(applyNumbering(body, options.numbering));
|
|
168
|
+
const numberedBody = noteAssigned.body;
|
|
38
169
|
const numberedHeadersFooters = applyNumberingToHeadersFooters(options.headersFooters, options.numbering);
|
|
39
170
|
const pdfaProfile = options.pdfA ? parsePdfAProfile(options.pdfA) : void 0;
|
|
40
|
-
const tagged = options.tagged === true || (pdfaProfile?.tagged ?? false);
|
|
171
|
+
const tagged = options.tagged === true || options.pdfUA === true || (pdfaProfile?.tagged ?? false);
|
|
41
172
|
const structBuilder = tagged ? new StructTreeBuilder() : void 0;
|
|
42
173
|
const fontResources = collectFontResources(numberedBody, numberedHeadersFooters, options);
|
|
43
174
|
const imageResources = collectImageResources(numberedBody, numberedHeadersFooters, options);
|
|
44
175
|
const sectionCtxs = sectionList.map((s) => buildSectionContext(s, options, numberedHeadersFooters, fontResources));
|
|
45
176
|
let sectionIdx = 0;
|
|
177
|
+
const blocks = numberedBody.map((el, idx) => {
|
|
178
|
+
while (sectionIdx < sectionCtxs.length - 1 && idx >= sectionCtxs[sectionIdx].endIndex) sectionIdx++;
|
|
179
|
+
const ctx = sectionCtxs[sectionIdx];
|
|
180
|
+
return layoutBodyElement(el, options, fontResources, imageResources, ctx.columns ? ctx.columns[0].widthPt : ctx.contentWidth, ctx.pageContentHeight);
|
|
181
|
+
});
|
|
182
|
+
const noteBlockCache = /* @__PURE__ */ new Map();
|
|
183
|
+
const notePlan = options.footnotes && noteAssigned.footnotes.size > 0 ? {
|
|
184
|
+
numbers: noteAssigned.footnotes,
|
|
185
|
+
layout: (sectionCtx, id) => {
|
|
186
|
+
let byId = noteBlockCache.get(sectionCtx);
|
|
187
|
+
if (!byId) {
|
|
188
|
+
byId = /* @__PURE__ */ new Map();
|
|
189
|
+
noteBlockCache.set(sectionCtx, byId);
|
|
190
|
+
}
|
|
191
|
+
if (byId.has(id)) return byId.get(id);
|
|
192
|
+
const content = options.footnotes?.get(id);
|
|
193
|
+
const n = noteAssigned.footnotes.get(id);
|
|
194
|
+
let laid = void 0;
|
|
195
|
+
if (content && n !== void 0 && !noteAssigned.deferredFootnotes.includes(id)) {
|
|
196
|
+
const noteBlocks = substituteNoteNumber(content, n).map((el) => layoutBodyElement(el, options, fontResources, imageResources, sectionCtx.contentWidth, sectionCtx.pageContentHeight));
|
|
197
|
+
laid = {
|
|
198
|
+
blocks: noteBlocks,
|
|
199
|
+
heightPt: noteBlocks.reduce((sum, b) => sum + (b.kind === "paragraph" ? b.spacingBeforePt + b.heightPt + b.spacingAfterPt : 0), 0)
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
byId.set(id, laid);
|
|
203
|
+
return laid;
|
|
204
|
+
}
|
|
205
|
+
} : void 0;
|
|
206
|
+
const lastCtx = sectionCtxs[sectionCtxs.length - 1];
|
|
207
|
+
if (lastCtx) {
|
|
208
|
+
const tailNotes = [];
|
|
209
|
+
for (const id of noteAssigned.deferredFootnotes) {
|
|
210
|
+
const content = options.footnotes?.get(id);
|
|
211
|
+
const n = noteAssigned.footnotes.get(id);
|
|
212
|
+
if (content && n !== void 0) tailNotes.push({
|
|
213
|
+
content,
|
|
214
|
+
n
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
for (const [id, n] of noteAssigned.endnotes) {
|
|
218
|
+
const content = options.endnotes?.get(id);
|
|
219
|
+
if (content) tailNotes.push({
|
|
220
|
+
content,
|
|
221
|
+
n
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
for (const note of tailNotes.sort((a, b) => a.n - b.n)) for (const el of substituteNoteNumber(note.content, note.n)) blocks.push(layoutBodyElement(el, options, fontResources, imageResources, lastCtx.contentWidth, lastCtx.pageContentHeight));
|
|
225
|
+
}
|
|
226
|
+
const bookmarks = /* @__PURE__ */ new Map();
|
|
46
227
|
return {
|
|
47
|
-
pages: paginateSections(
|
|
48
|
-
while (sectionIdx < sectionCtxs.length - 1 && idx >= sectionCtxs[sectionIdx].endIndex) sectionIdx++;
|
|
49
|
-
const ctx = sectionCtxs[sectionIdx];
|
|
50
|
-
return layoutBodyElement(el, options, fontResources, imageResources, ctx.contentWidth, ctx.pageContentHeight);
|
|
51
|
-
}), sectionCtxs, structBuilder, options.language ?? "en-US"),
|
|
228
|
+
pages: paginateSections(blocks, sectionCtxs, structBuilder, options.language ?? "en-US", notePlan, bookmarks),
|
|
52
229
|
resources: options.resources ?? new ResourceStore(),
|
|
53
230
|
fontResources,
|
|
54
231
|
imageResources,
|
|
@@ -56,7 +233,8 @@ function layoutStyledDocument(body, options) {
|
|
|
56
233
|
structBuilder,
|
|
57
234
|
sectionCtxs,
|
|
58
235
|
pdfaProfile,
|
|
59
|
-
tagged
|
|
236
|
+
tagged,
|
|
237
|
+
bookmarks
|
|
60
238
|
}
|
|
61
239
|
};
|
|
62
240
|
}
|
|
@@ -99,6 +277,7 @@ function buildSectionContext(section, options, headersFooters, fontResources) {
|
|
|
99
277
|
const contentWidth = dims.pageWidth - dims.marginLeft - dims.marginRight;
|
|
100
278
|
const headerSet = layoutHeaderSet(section.properties, headersFooters, options, fontResources, contentWidth, dims.marginLeft, dims.pageHeight, dims.headerOffsetPt);
|
|
101
279
|
const footerSet = layoutFooterSet(section.properties, headersFooters, options, fontResources, contentWidth, dims.marginLeft, dims.pageHeight, dims.footerOffsetPt);
|
|
280
|
+
const columns = buildColumnGeometry(section.properties.columns, contentWidth);
|
|
102
281
|
return {
|
|
103
282
|
endIndex: section.endIndex,
|
|
104
283
|
properties: section.properties,
|
|
@@ -109,12 +288,35 @@ function buildSectionContext(section, options, headersFooters, fontResources) {
|
|
|
109
288
|
marginBottom: dims.marginBottom,
|
|
110
289
|
contentWidth,
|
|
111
290
|
pageContentHeight: dims.pageHeight - dims.marginTop - dims.marginBottom,
|
|
291
|
+
...columns ? { columns } : {},
|
|
112
292
|
headerSet,
|
|
113
293
|
footerSet,
|
|
114
294
|
titlePg: section.properties.titlePg === true,
|
|
115
295
|
evenAndOddHeaders: section.properties.evenAndOddHeaders === true
|
|
116
296
|
};
|
|
117
297
|
}
|
|
298
|
+
function buildColumnGeometry(cols, contentWidth) {
|
|
299
|
+
if (!cols || cols.count <= 1) return void 0;
|
|
300
|
+
const out = [];
|
|
301
|
+
if (cols.explicit && cols.explicit.length > 1) {
|
|
302
|
+
let x = 0;
|
|
303
|
+
for (const c of cols.explicit) {
|
|
304
|
+
out.push({
|
|
305
|
+
xOffsetPt: x,
|
|
306
|
+
widthPt: c.widthPt
|
|
307
|
+
});
|
|
308
|
+
x += c.widthPt + c.spacePt;
|
|
309
|
+
}
|
|
310
|
+
return out;
|
|
311
|
+
}
|
|
312
|
+
const width = (contentWidth - cols.spacePt * (cols.count - 1)) / cols.count;
|
|
313
|
+
if (width <= 0) return void 0;
|
|
314
|
+
for (let i = 0; i < cols.count; i++) out.push({
|
|
315
|
+
xOffsetPt: i * (width + cols.spacePt),
|
|
316
|
+
widthPt: width
|
|
317
|
+
});
|
|
318
|
+
return out;
|
|
319
|
+
}
|
|
118
320
|
function refByType(refs, type) {
|
|
119
321
|
if (!refs || refs.length === 0) return void 0;
|
|
120
322
|
return refs.find((r) => r.type === type);
|
|
@@ -128,10 +330,17 @@ function markPagination(cmds) {
|
|
|
128
330
|
function layoutHeaderSet(section, headersFooters, options, fontResources, contentWidth, marginLeft, pageHeight, headerOffsetPt) {
|
|
129
331
|
const band = (type) => {
|
|
130
332
|
const ref = refByType(section.headers, type);
|
|
131
|
-
if (!ref) return [];
|
|
333
|
+
if (!ref) return { commands: [] };
|
|
132
334
|
const content = headersFooters.get(ref.relationshipId);
|
|
133
|
-
if (!content) return [];
|
|
134
|
-
|
|
335
|
+
if (!content) return { commands: [] };
|
|
336
|
+
const render = (c) => {
|
|
337
|
+
return markPagination(drawBlocksSequentially(laidOutBlocksFor(c, options, fontResources, contentWidth), marginLeft, pageHeight - headerOffsetPt, pageHeight));
|
|
338
|
+
};
|
|
339
|
+
if (contentHasPageFields(content)) return {
|
|
340
|
+
commands: [],
|
|
341
|
+
renderDynamic: (n, total) => render(substitutePageFields(content, n, total))
|
|
342
|
+
};
|
|
343
|
+
return { commands: render(content) };
|
|
135
344
|
};
|
|
136
345
|
return {
|
|
137
346
|
default: band("default"),
|
|
@@ -142,11 +351,18 @@ function layoutHeaderSet(section, headersFooters, options, fontResources, conten
|
|
|
142
351
|
function layoutFooterSet(section, headersFooters, options, fontResources, contentWidth, marginLeft, pageHeight, footerOffsetPt) {
|
|
143
352
|
const band = (type) => {
|
|
144
353
|
const ref = refByType(section.footers, type);
|
|
145
|
-
if (!ref) return [];
|
|
354
|
+
if (!ref) return { commands: [] };
|
|
146
355
|
const content = headersFooters.get(ref.relationshipId);
|
|
147
|
-
if (!content) return [];
|
|
148
|
-
const
|
|
149
|
-
|
|
356
|
+
if (!content) return { commands: [] };
|
|
357
|
+
const render = (c) => {
|
|
358
|
+
const blocks = laidOutBlocksFor(c, options, fontResources, contentWidth);
|
|
359
|
+
return markPagination(drawBlocksSequentially(blocks, marginLeft, footerOffsetPt + blocks.reduce((sum, b) => sum + (b.kind === "paragraph" ? b.spacingBeforePt + b.heightPt + b.spacingAfterPt : b.heightPt), 0), pageHeight));
|
|
360
|
+
};
|
|
361
|
+
if (contentHasPageFields(content)) return {
|
|
362
|
+
commands: [],
|
|
363
|
+
renderDynamic: (n, total) => render(substitutePageFields(content, n, total))
|
|
364
|
+
};
|
|
365
|
+
return { commands: render(content) };
|
|
150
366
|
};
|
|
151
367
|
return {
|
|
152
368
|
default: band("default"),
|
|
@@ -154,9 +370,30 @@ function layoutFooterSet(section, headersFooters, options, fontResources, conten
|
|
|
154
370
|
even: band("even")
|
|
155
371
|
};
|
|
156
372
|
}
|
|
373
|
+
function contentHasPageFields(content) {
|
|
374
|
+
for (const el of content) if (el.kind === "paragraph" && el.paragraph.runs.some((r) => r.field !== void 0)) return true;
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
function substitutePageFields(content, pageNumber, totalPages) {
|
|
378
|
+
return content.map((el) => {
|
|
379
|
+
if (el.kind !== "paragraph") return el;
|
|
380
|
+
if (!el.paragraph.runs.some((r) => r.field !== void 0)) return el;
|
|
381
|
+
return {
|
|
382
|
+
kind: "paragraph",
|
|
383
|
+
paragraph: {
|
|
384
|
+
...el.paragraph,
|
|
385
|
+
runs: el.paragraph.runs.map((r) => r.field === void 0 ? r : {
|
|
386
|
+
...r,
|
|
387
|
+
text: String(r.field === "PAGE" ? pageNumber : totalPages)
|
|
388
|
+
})
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
});
|
|
392
|
+
}
|
|
157
393
|
function pickBand(set, band) {
|
|
158
|
-
|
|
159
|
-
if (band === "
|
|
394
|
+
const has = (e) => e.commands.length > 0 || e.renderDynamic !== void 0;
|
|
395
|
+
if (band === "first") return has(set.first) ? set.first : set.default;
|
|
396
|
+
if (band === "even") return has(set.even) ? set.even : set.default;
|
|
160
397
|
return set.default;
|
|
161
398
|
}
|
|
162
399
|
function bandForPage(pageInSection, globalPageIdx, titlePg, evenAndOddHeaders) {
|
|
@@ -174,7 +411,6 @@ function layoutBodyElement(el, options, fontResources, imageResources, contentWi
|
|
|
174
411
|
if (el.kind === "chart") return layoutChartBlock(el.chart, options, fontResources, contentWidth, maxHeight);
|
|
175
412
|
return layoutShapeBlock(el.shape, options, fontResources, imageResources, contentWidth, maxHeight);
|
|
176
413
|
}
|
|
177
|
-
var EMU_PER_PT = 12700;
|
|
178
414
|
function layoutImageBlock(image, imageResources, contentWidth) {
|
|
179
415
|
let widthPt = image.width;
|
|
180
416
|
let heightPt = image.height;
|
|
@@ -193,12 +429,10 @@ function layoutImageBlock(image, imageResources, contentWidth) {
|
|
|
193
429
|
resourceName: res?.resourceName ?? "",
|
|
194
430
|
spacingBeforePt: image.paragraphProperties.spacingBefore ?? 0,
|
|
195
431
|
spacingAfterPt: image.paragraphProperties.spacingAfter ?? 0,
|
|
196
|
-
...image.altText ? { altText: image.altText } : {}
|
|
432
|
+
...image.altText ? { altText: image.altText } : {},
|
|
433
|
+
...image.float ? { float: image.float } : {}
|
|
197
434
|
};
|
|
198
435
|
}
|
|
199
|
-
var DEFAULT_LINE_WIDTH_EMU = 9525;
|
|
200
|
-
var DEFAULT_INSET_LR_EMU = 91440;
|
|
201
|
-
var DEFAULT_INSET_TB_EMU = 45720;
|
|
202
436
|
function layoutShapeBlock(shape, options, fontResources, imageResources, contentWidth, maxHeight) {
|
|
203
437
|
let widthPt = shape.width;
|
|
204
438
|
let heightPt = shape.height;
|
|
@@ -218,10 +452,10 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
218
452
|
const t = shape.transform;
|
|
219
453
|
const pp = shape.paragraphProperties;
|
|
220
454
|
const text = shape.text;
|
|
221
|
-
const insetLeftPt = text?.insetLeft ??
|
|
222
|
-
const insetRightPt = text?.insetRight ??
|
|
223
|
-
const insetTopPt = text?.insetTop ??
|
|
224
|
-
const insetBottomPt = text?.insetBottom ??
|
|
455
|
+
const insetLeftPt = text?.insetLeft ?? 7.2;
|
|
456
|
+
const insetRightPt = text?.insetRight ?? 7.2;
|
|
457
|
+
const insetTopPt = text?.insetTop ?? 3.6;
|
|
458
|
+
const insetBottomPt = text?.insetBottom ?? 3.6;
|
|
225
459
|
const textLines = [];
|
|
226
460
|
let textHeightPt = 0;
|
|
227
461
|
if (text && text.content.length > 0) {
|
|
@@ -256,82 +490,10 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
256
490
|
insetTopPt,
|
|
257
491
|
insetBottomPt,
|
|
258
492
|
anchor: text?.anchor ?? "t",
|
|
259
|
-
...shape.altText ? { altText: shape.altText } : {}
|
|
493
|
+
...shape.altText ? { altText: shape.altText } : {},
|
|
494
|
+
...shape.float ? { float: shape.float } : {}
|
|
260
495
|
};
|
|
261
496
|
}
|
|
262
|
-
function buildShapePaths(geometry, widthPt, heightPt) {
|
|
263
|
-
if (geometry.kind === "preset") return presetPaths(geometry.preset ?? "rect", widthPt, heightPt, geometry.adjust ?? /* @__PURE__ */ new Map()) ?? [rectPath(widthPt, heightPt)];
|
|
264
|
-
if (geometry.custom) return customPaths(geometry.custom, widthPt, heightPt);
|
|
265
|
-
return [rectPath(widthPt, heightPt)];
|
|
266
|
-
}
|
|
267
|
-
function buildStroke(line) {
|
|
268
|
-
if (!line || line.fill === "none") return void 0;
|
|
269
|
-
const widthPt = line.width ?? DEFAULT_LINE_WIDTH_EMU / EMU_PER_PT;
|
|
270
|
-
const dash = line.dash && line.dash !== "solid" ? dashPattern(line.dash, widthPt) : void 0;
|
|
271
|
-
const cap = line.cap === "flat" ? "butt" : line.cap;
|
|
272
|
-
return {
|
|
273
|
-
colorHex: line.colorHex ?? "000000",
|
|
274
|
-
widthPt,
|
|
275
|
-
...dash ? { dash } : {},
|
|
276
|
-
...cap ? { cap } : {}
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
function dashPattern(dash, w) {
|
|
280
|
-
const u = Math.max(w, .1);
|
|
281
|
-
switch (dash) {
|
|
282
|
-
case "solid": return;
|
|
283
|
-
case "dot": return [u, 2 * u];
|
|
284
|
-
case "dash": return [4 * u, 3 * u];
|
|
285
|
-
case "dashDot": return [
|
|
286
|
-
4 * u,
|
|
287
|
-
3 * u,
|
|
288
|
-
u,
|
|
289
|
-
3 * u
|
|
290
|
-
];
|
|
291
|
-
case "lgDash": return [8 * u, 3 * u];
|
|
292
|
-
case "lgDashDot": return [
|
|
293
|
-
8 * u,
|
|
294
|
-
3 * u,
|
|
295
|
-
u,
|
|
296
|
-
3 * u
|
|
297
|
-
];
|
|
298
|
-
case "sysDash": return [3 * u, u];
|
|
299
|
-
case "sysDot": return [u, u];
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
function buildShapeTransform(pageX, pageY, widthPt, heightPt, rotation60k, flipH, flipV) {
|
|
303
|
-
const theta = -rotation60k / 6e4 * (Math.PI / 180);
|
|
304
|
-
const sx = flipH ? -1 : 1;
|
|
305
|
-
const sy = flipV ? -1 : 1;
|
|
306
|
-
const cos = Math.cos(theta);
|
|
307
|
-
const sin = Math.sin(theta);
|
|
308
|
-
const a = sx * cos;
|
|
309
|
-
const b = sx * sin;
|
|
310
|
-
const c = -sy * sin;
|
|
311
|
-
const d = sy * cos;
|
|
312
|
-
const cxL = widthPt / 2;
|
|
313
|
-
const cyL = heightPt / 2;
|
|
314
|
-
const centerX = pageX + cxL;
|
|
315
|
-
const centerY = pageY + cyL;
|
|
316
|
-
return [
|
|
317
|
-
a,
|
|
318
|
-
b,
|
|
319
|
-
c,
|
|
320
|
-
d,
|
|
321
|
-
centerX - (a * cxL + c * cyL),
|
|
322
|
-
centerY - (b * cxL + d * cyL)
|
|
323
|
-
];
|
|
324
|
-
}
|
|
325
|
-
function flipTransform(m, pageHeight) {
|
|
326
|
-
return [
|
|
327
|
-
m[0],
|
|
328
|
-
-m[1],
|
|
329
|
-
m[2],
|
|
330
|
-
-m[3],
|
|
331
|
-
m[4],
|
|
332
|
-
pageHeight - m[5]
|
|
333
|
-
];
|
|
334
|
-
}
|
|
335
497
|
function layoutChartBlock(block, options, fontResources, contentWidth, maxHeight) {
|
|
336
498
|
let widthPt = block.width;
|
|
337
499
|
let heightPt = block.height;
|
|
@@ -362,7 +524,8 @@ function layoutChartBlock(block, options, fontResources, contentWidth, maxHeight
|
|
|
362
524
|
resolvedAlignment: pp.alignment ?? "left",
|
|
363
525
|
spacingBeforePt: pp.spacingBefore ?? 0,
|
|
364
526
|
spacingAfterPt: pp.spacingAfter ?? 0,
|
|
365
|
-
...altText ? { altText } : {}
|
|
527
|
+
...altText ? { altText } : {},
|
|
528
|
+
...block.float ? { float: block.float } : {}
|
|
366
529
|
};
|
|
367
530
|
}
|
|
368
531
|
function buildChartLayout(chart, widthPt, heightPt, font) {
|
|
@@ -486,6 +649,8 @@ function collectImageResources(body, headersFooters, options) {
|
|
|
486
649
|
};
|
|
487
650
|
visit(body);
|
|
488
651
|
for (const hf of headersFooters.values()) visit(hf);
|
|
652
|
+
for (const note of options.footnotes?.values() ?? []) visit(note);
|
|
653
|
+
for (const note of options.endnotes?.values() ?? []) visit(note);
|
|
489
654
|
const flattenAlpha = options.pdfA ? parsePdfAProfile(options.pdfA).part === 1 : false;
|
|
490
655
|
let counter = 0;
|
|
491
656
|
for (const resourceId of seen) {
|
|
@@ -505,7 +670,7 @@ function collectImageResources(body, headersFooters, options) {
|
|
|
505
670
|
}
|
|
506
671
|
return out;
|
|
507
672
|
}
|
|
508
|
-
function drawBlocksSequentially(blocks, startX, startY, pageHeight) {
|
|
673
|
+
function drawBlocksSequentially(blocks, startX, startY, pageHeight, structId) {
|
|
509
674
|
const out = [];
|
|
510
675
|
let cursorY = startY;
|
|
511
676
|
for (const block of blocks) {
|
|
@@ -520,7 +685,8 @@ function drawBlocksSequentially(blocks, startX, startY, pageHeight) {
|
|
|
520
685
|
type: "line",
|
|
521
686
|
line,
|
|
522
687
|
originX: pt(startX + indentLeft + offset),
|
|
523
|
-
baselineY: pt(pageHeight - (cursorY + lineDescent(line)))
|
|
688
|
+
baselineY: pt(pageHeight - (cursorY + lineDescent(line))),
|
|
689
|
+
...structId !== void 0 ? { structId } : {}
|
|
524
690
|
});
|
|
525
691
|
}
|
|
526
692
|
cursorY -= block.spacingAfterPt;
|
|
@@ -600,6 +766,20 @@ function collectFontResources(body, headersFooters, options) {
|
|
|
600
766
|
continue;
|
|
601
767
|
}
|
|
602
768
|
if (run.inlineImage && !run.text) continue;
|
|
769
|
+
if (run.field !== void 0) {
|
|
770
|
+
addRun({
|
|
771
|
+
text: `${run.text}0123456789`,
|
|
772
|
+
properties: run.properties
|
|
773
|
+
}, el.paragraph);
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
if (run.footnoteRef !== void 0 || run.endnoteRef !== void 0 || run.noteNumber) {
|
|
777
|
+
addRun({
|
|
778
|
+
text: `${run.text}0123456789 `,
|
|
779
|
+
properties: run.properties
|
|
780
|
+
}, el.paragraph);
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
603
783
|
addRun(run, el.paragraph);
|
|
604
784
|
}
|
|
605
785
|
else if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
|
|
@@ -629,6 +809,8 @@ function collectFontResources(body, headersFooters, options) {
|
|
|
629
809
|
};
|
|
630
810
|
visit(body);
|
|
631
811
|
for (const hf of headersFooters.values()) visit(hf);
|
|
812
|
+
for (const note of options.footnotes?.values() ?? []) visit(note);
|
|
813
|
+
for (const note of options.endnotes?.values() ?? []) visit(note);
|
|
632
814
|
if (used.size === 0) {
|
|
633
815
|
const regular = options.registry.resolveByStyle(false, false);
|
|
634
816
|
used.set(regular.variant, {
|
|
@@ -672,7 +854,8 @@ function layoutParagraphBlock(paragraph, options, fontResources, imageResources,
|
|
|
672
854
|
numId: numbering.numId,
|
|
673
855
|
level: numbering.ilvl
|
|
674
856
|
} } : {},
|
|
675
|
-
...paragraph.runs.some((r) => r.pageBreak) ? { pageBreakAfter: true } : {}
|
|
857
|
+
...paragraph.runs.some((r) => r.pageBreak) ? { pageBreakAfter: true } : {},
|
|
858
|
+
...paragraph.bookmarks && paragraph.bookmarks.length > 0 ? { bookmarks: paragraph.bookmarks } : {}
|
|
676
859
|
};
|
|
677
860
|
}
|
|
678
861
|
function resolveMathItems(items, fontFor) {
|
|
@@ -801,6 +984,9 @@ function tokenizePlansLtr(plans) {
|
|
|
801
984
|
kind: "text",
|
|
802
985
|
text: t.text,
|
|
803
986
|
isSpace: t.isSpace,
|
|
987
|
+
...plan.run.href !== void 0 ? { href: plan.run.href } : {},
|
|
988
|
+
...plan.run.footnoteRef !== void 0 ? { footnoteRef: plan.run.footnoteRef } : {},
|
|
989
|
+
...plan.run.anchor !== void 0 ? { anchor: plan.run.anchor } : {},
|
|
804
990
|
resolvedRun: plan.resolvedRun,
|
|
805
991
|
font: plan.font,
|
|
806
992
|
fontSizePt: plan.fontSizePt,
|
|
@@ -851,6 +1037,9 @@ function tokenizePlansBidi(plans, realLevels) {
|
|
|
851
1037
|
kind: "text",
|
|
852
1038
|
text,
|
|
853
1039
|
isSpace: curSpace,
|
|
1040
|
+
...plan.run.href !== void 0 ? { href: plan.run.href } : {},
|
|
1041
|
+
...plan.run.footnoteRef !== void 0 ? { footnoteRef: plan.run.footnoteRef } : {},
|
|
1042
|
+
...plan.run.anchor !== void 0 ? { anchor: plan.run.anchor } : {},
|
|
854
1043
|
resolvedRun: plan.resolvedRun,
|
|
855
1044
|
font: plan.font,
|
|
856
1045
|
fontSizePt: plan.fontSizePt,
|
|
@@ -1368,7 +1557,7 @@ function listItemParagraphNode(builder, stack, list) {
|
|
|
1368
1557
|
frame.lbody = lbody;
|
|
1369
1558
|
return builder.create("P", lbody).id;
|
|
1370
1559
|
}
|
|
1371
|
-
function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US") {
|
|
1560
|
+
function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", notes, bookmarkPositions) {
|
|
1372
1561
|
if (sectionCtxs.length === 0) return [];
|
|
1373
1562
|
const pages = [];
|
|
1374
1563
|
let ctx = sectionCtxs[0];
|
|
@@ -1378,22 +1567,121 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US") {
|
|
|
1378
1567
|
let current = [];
|
|
1379
1568
|
let pendingPageBreak = false;
|
|
1380
1569
|
let cursorY = ctx.pageHeight - ctx.marginTop;
|
|
1570
|
+
let colIdx = 0;
|
|
1571
|
+
let colStartLen = 0;
|
|
1572
|
+
const colLeft = () => ctx.marginLeft + (ctx.columns?.[colIdx]?.xOffsetPt ?? 0);
|
|
1573
|
+
const colWidth = () => ctx.columns?.[colIdx]?.widthPt ?? ctx.contentWidth;
|
|
1574
|
+
const colHasContent = () => current.length > colStartLen;
|
|
1575
|
+
const advanceColumn = () => {
|
|
1576
|
+
if (ctx.columns && colIdx + 1 < ctx.columns.length) {
|
|
1577
|
+
colIdx++;
|
|
1578
|
+
colStartLen = current.length;
|
|
1579
|
+
cursorY = ctx.pageHeight - ctx.marginTop;
|
|
1580
|
+
} else flushPage();
|
|
1581
|
+
};
|
|
1582
|
+
let floatsBehind = [];
|
|
1583
|
+
let floatsFront = [];
|
|
1584
|
+
const floatX = (f, widthPt) => {
|
|
1585
|
+
const h = f.posH;
|
|
1586
|
+
if (!h) return colLeft();
|
|
1587
|
+
const base = h.relativeFrom === "page" ? 0 : h.relativeFrom === "column" ? colLeft() : ctx.marginLeft;
|
|
1588
|
+
const span = h.relativeFrom === "page" ? ctx.pageWidth : h.relativeFrom === "column" ? colWidth() : ctx.contentWidth;
|
|
1589
|
+
if (h.align === "center") return base + (span - widthPt) / 2;
|
|
1590
|
+
if (h.align === "right") return base + span - widthPt;
|
|
1591
|
+
return base + (h.offsetPt ?? 0);
|
|
1592
|
+
};
|
|
1593
|
+
const floatTopYUp = (f) => {
|
|
1594
|
+
const v = f.posV;
|
|
1595
|
+
if (!v) return cursorY;
|
|
1596
|
+
if (v.relativeFrom === "page") return ctx.pageHeight - (v.offsetPt ?? 0);
|
|
1597
|
+
if (v.relativeFrom === "margin") return ctx.pageHeight - ctx.marginTop - (v.offsetPt ?? 0);
|
|
1598
|
+
return cursorY - (v.offsetPt ?? 0);
|
|
1599
|
+
};
|
|
1381
1600
|
const listStack = [];
|
|
1601
|
+
let pageNotes = [];
|
|
1602
|
+
let noteReserve = 0;
|
|
1603
|
+
const placedNotes = /* @__PURE__ */ new Set();
|
|
1604
|
+
const bottomLimit = () => ctx.marginBottom + noteReserve;
|
|
1605
|
+
const lineFootnotes = (line) => {
|
|
1606
|
+
if (!notes) return [];
|
|
1607
|
+
const out = [];
|
|
1608
|
+
for (const tok of line.tokens) {
|
|
1609
|
+
if (tok.kind !== "text" || tok.footnoteRef === void 0) continue;
|
|
1610
|
+
const id = tok.footnoteRef;
|
|
1611
|
+
if (placedNotes.has(id) || out.some((o) => o.id === id)) continue;
|
|
1612
|
+
const laid = notes.layout(ctx, id);
|
|
1613
|
+
const n = notes.numbers.get(id);
|
|
1614
|
+
if (!laid || n === void 0) continue;
|
|
1615
|
+
out.push({
|
|
1616
|
+
id,
|
|
1617
|
+
n,
|
|
1618
|
+
blocks: laid.blocks,
|
|
1619
|
+
heightPt: laid.heightPt
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
return out;
|
|
1623
|
+
};
|
|
1624
|
+
const renderNotesBand = () => {
|
|
1625
|
+
if (pageNotes.length === 0) return [];
|
|
1626
|
+
const out = [];
|
|
1627
|
+
const top = ctx.marginBottom + noteReserve;
|
|
1628
|
+
out.push({
|
|
1629
|
+
type: "fill",
|
|
1630
|
+
x: pt(ctx.marginLeft),
|
|
1631
|
+
y: pt(ctx.pageHeight - (top - FOOTNOTE_RULE_GAP_ABOVE)),
|
|
1632
|
+
width: pt(FOOTNOTE_RULE_WIDTH),
|
|
1633
|
+
height: pt(FOOTNOTE_RULE_PT),
|
|
1634
|
+
fillColorHex: "000000"
|
|
1635
|
+
});
|
|
1636
|
+
let cursor = top - FOOTNOTE_SEPARATOR_HEIGHT;
|
|
1637
|
+
for (const note of pageNotes.sort((a, b) => a.n - b.n)) {
|
|
1638
|
+
let structId;
|
|
1639
|
+
if (builder) {
|
|
1640
|
+
const noteNode = builder.create("Note", builder.root);
|
|
1641
|
+
structId = builder.create("P", noteNode).id;
|
|
1642
|
+
}
|
|
1643
|
+
out.push(...drawBlocksSequentially(note.blocks, ctx.marginLeft, cursor, ctx.pageHeight, structId));
|
|
1644
|
+
cursor -= note.heightPt;
|
|
1645
|
+
}
|
|
1646
|
+
return out;
|
|
1647
|
+
};
|
|
1648
|
+
const dynBands = [];
|
|
1382
1649
|
const flushPage = (force = false) => {
|
|
1383
1650
|
if (current.length === 0 && !force) return;
|
|
1384
1651
|
const band = bandForPage(pageInSection, globalPageIdx, ctx.titlePg, ctx.evenAndOddHeaders);
|
|
1385
1652
|
const header = pickBand(ctx.headerSet, band);
|
|
1386
1653
|
const footer = pickBand(ctx.footerSet, band);
|
|
1654
|
+
if (header.renderDynamic) dynBands.push({
|
|
1655
|
+
pageIdx: pages.length,
|
|
1656
|
+
pageNumber: globalPageIdx + 1,
|
|
1657
|
+
position: "header",
|
|
1658
|
+
render: header.renderDynamic
|
|
1659
|
+
});
|
|
1660
|
+
if (footer.renderDynamic) dynBands.push({
|
|
1661
|
+
pageIdx: pages.length,
|
|
1662
|
+
pageNumber: globalPageIdx + 1,
|
|
1663
|
+
position: "footer",
|
|
1664
|
+
render: footer.renderDynamic
|
|
1665
|
+
});
|
|
1387
1666
|
pages.push({
|
|
1388
1667
|
commands: [
|
|
1389
|
-
...header,
|
|
1668
|
+
...header.commands,
|
|
1669
|
+
...floatsBehind,
|
|
1390
1670
|
...current,
|
|
1391
|
-
...
|
|
1671
|
+
...floatsFront,
|
|
1672
|
+
...renderNotesBand(),
|
|
1673
|
+
...footer.commands
|
|
1392
1674
|
],
|
|
1393
1675
|
width: pt(ctx.pageWidth),
|
|
1394
1676
|
height: pt(ctx.pageHeight)
|
|
1395
1677
|
});
|
|
1396
1678
|
current = [];
|
|
1679
|
+
floatsBehind = [];
|
|
1680
|
+
floatsFront = [];
|
|
1681
|
+
pageNotes = [];
|
|
1682
|
+
noteReserve = 0;
|
|
1683
|
+
colIdx = 0;
|
|
1684
|
+
colStartLen = 0;
|
|
1397
1685
|
pageInSection++;
|
|
1398
1686
|
globalPageIdx++;
|
|
1399
1687
|
cursorY = ctx.pageHeight - ctx.marginTop;
|
|
@@ -1421,16 +1709,42 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US") {
|
|
|
1421
1709
|
const lang = dominantParagraphLang(block.lines);
|
|
1422
1710
|
if (lang && lang !== defaultLang) builder.node(structId).lang = lang;
|
|
1423
1711
|
}
|
|
1712
|
+
let firstLineOfBlock = true;
|
|
1424
1713
|
for (const line of block.lines) {
|
|
1425
1714
|
const h = computeLineHeight(line, block.resolved);
|
|
1426
|
-
|
|
1715
|
+
let newNotes = lineFootnotes(line);
|
|
1716
|
+
const addedReserve = (sub) => sub.reduce((sum, x) => sum + x.heightPt, 0) + (pageNotes.length === 0 && sub.length > 0 ? FOOTNOTE_SEPARATOR_HEIGHT : 0);
|
|
1717
|
+
if (cursorY - h < bottomLimit() + addedReserve(newNotes) && colHasContent()) {
|
|
1718
|
+
advanceColumn();
|
|
1719
|
+
newNotes = lineFootnotes(line);
|
|
1720
|
+
}
|
|
1721
|
+
if (newNotes.length > 0) {
|
|
1722
|
+
noteReserve += addedReserve(newNotes);
|
|
1723
|
+
for (const x of newNotes) {
|
|
1724
|
+
placedNotes.add(x.id);
|
|
1725
|
+
pageNotes.push({
|
|
1726
|
+
n: x.n,
|
|
1727
|
+
blocks: x.blocks,
|
|
1728
|
+
heightPt: x.heightPt
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
if (firstLineOfBlock) {
|
|
1733
|
+
firstLineOfBlock = false;
|
|
1734
|
+
if (block.bookmarks && bookmarkPositions) {
|
|
1735
|
+
for (const bookmarkName of block.bookmarks) if (!bookmarkPositions.has(bookmarkName)) bookmarkPositions.set(bookmarkName, {
|
|
1736
|
+
pageIdx: pages.length,
|
|
1737
|
+
yTopPt: cursorY
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1427
1741
|
cursorY -= h;
|
|
1428
1742
|
const indentLeft = block.resolved.indentLeft + (line.firstLine ? block.resolved.indentFirstLine : 0);
|
|
1429
1743
|
const offset = alignmentOffset(block.resolved.alignment, line.contentWidthPt, line.availableWidthPt);
|
|
1430
1744
|
current.push({
|
|
1431
1745
|
type: "line",
|
|
1432
1746
|
line,
|
|
1433
|
-
originX: pt(
|
|
1747
|
+
originX: pt(colLeft() + indentLeft + offset),
|
|
1434
1748
|
baselineY: pt(ctx.pageHeight - (cursorY + lineDescent(line))),
|
|
1435
1749
|
...structId !== void 0 ? { structId } : {}
|
|
1436
1750
|
});
|
|
@@ -1439,93 +1753,108 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US") {
|
|
|
1439
1753
|
if (block.pageBreakAfter) pendingPageBreak = true;
|
|
1440
1754
|
} else if (block.kind === "image") {
|
|
1441
1755
|
const figId = builder ? createFigure(builder, block.altText, "Image") : void 0;
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1756
|
+
const emitImageAt = (x, topYUp, sink) => {
|
|
1757
|
+
sink.push({
|
|
1758
|
+
type: "image",
|
|
1759
|
+
x: pt(x),
|
|
1760
|
+
y: pt(ctx.pageHeight - topYUp),
|
|
1761
|
+
width: pt(block.widthPt),
|
|
1762
|
+
height: pt(block.heightPt),
|
|
1763
|
+
imageResourceName: block.resourceName,
|
|
1764
|
+
...figId !== void 0 ? { structId: figId } : {}
|
|
1765
|
+
});
|
|
1766
|
+
};
|
|
1767
|
+
if (block.float?.wrap === "none") emitImageAt(floatX(block.float, block.widthPt), floatTopYUp(block.float), block.float.behind ? floatsBehind : floatsFront);
|
|
1768
|
+
else {
|
|
1769
|
+
cursorY -= block.spacingBeforePt;
|
|
1770
|
+
if (cursorY - block.heightPt < bottomLimit() && colHasContent()) advanceColumn();
|
|
1771
|
+
cursorY -= block.heightPt;
|
|
1772
|
+
emitImageAt(colLeft(), cursorY + block.heightPt, current);
|
|
1773
|
+
cursorY -= block.spacingAfterPt;
|
|
1774
|
+
}
|
|
1455
1775
|
} else if (block.kind === "shape") {
|
|
1456
1776
|
const figId = builder ? createFigure(builder, block.altText, "Shape") : void 0;
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
...
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
baselineY: pt(ctx.pageHeight - (textY + lineDescent(line))),
|
|
1490
|
-
...figId !== void 0 ? { structId: figId } : {}
|
|
1491
|
-
});
|
|
1777
|
+
const emitShapeAt = (x, bottomYUp, sink) => {
|
|
1778
|
+
const transform = flipTransform(buildShapeTransform(x, bottomYUp, block.widthPt, block.heightPt, block.rotation60k, block.flipH, block.flipV), ctx.pageHeight);
|
|
1779
|
+
sink.push({
|
|
1780
|
+
type: "shape",
|
|
1781
|
+
shape: {
|
|
1782
|
+
paths: block.paths,
|
|
1783
|
+
...block.fillColorHex ? { fillColorHex: block.fillColorHex } : {},
|
|
1784
|
+
...block.stroke ? { stroke: block.stroke } : {},
|
|
1785
|
+
transform
|
|
1786
|
+
},
|
|
1787
|
+
...figId !== void 0 ? { structId: figId } : {}
|
|
1788
|
+
});
|
|
1789
|
+
if (block.textLines.length > 0) {
|
|
1790
|
+
const shapeBottom = bottomYUp;
|
|
1791
|
+
const shapeTop = bottomYUp + block.heightPt;
|
|
1792
|
+
const innerWidth = Math.max(1, block.widthPt - block.insetLeftPt - block.insetRightPt);
|
|
1793
|
+
let textY;
|
|
1794
|
+
if (block.anchor === "b") textY = shapeBottom + block.insetBottomPt + block.textHeightPt;
|
|
1795
|
+
else if (block.anchor === "ctr") textY = shapeBottom + (block.heightPt + block.textHeightPt) / 2;
|
|
1796
|
+
else textY = shapeTop - block.insetTopPt;
|
|
1797
|
+
for (const line of block.textLines) {
|
|
1798
|
+
const h = computeLineHeight(line, line.resolved);
|
|
1799
|
+
textY -= h;
|
|
1800
|
+
const lineOffset = alignmentOffset(line.resolved.alignment, line.contentWidthPt, innerWidth);
|
|
1801
|
+
sink.push({
|
|
1802
|
+
type: "line",
|
|
1803
|
+
line,
|
|
1804
|
+
originX: pt(x + block.insetLeftPt + lineOffset),
|
|
1805
|
+
baselineY: pt(ctx.pageHeight - (textY + lineDescent(line))),
|
|
1806
|
+
...figId !== void 0 ? { structId: figId } : {}
|
|
1807
|
+
});
|
|
1808
|
+
}
|
|
1492
1809
|
}
|
|
1810
|
+
};
|
|
1811
|
+
if (block.float?.wrap === "none") emitShapeAt(floatX(block.float, block.widthPt), floatTopYUp(block.float) - block.heightPt, block.float.behind ? floatsBehind : floatsFront);
|
|
1812
|
+
else {
|
|
1813
|
+
cursorY -= block.spacingBeforePt;
|
|
1814
|
+
if (cursorY - block.heightPt < bottomLimit() && colHasContent()) advanceColumn();
|
|
1815
|
+
cursorY -= block.heightPt;
|
|
1816
|
+
const offset = alignmentOffset(block.resolvedAlignment, block.widthPt, colWidth());
|
|
1817
|
+
emitShapeAt(colLeft() + offset, cursorY, current);
|
|
1818
|
+
cursorY -= block.spacingAfterPt;
|
|
1493
1819
|
}
|
|
1494
|
-
cursorY -= block.spacingAfterPt;
|
|
1495
1820
|
} else if (block.kind === "chart") {
|
|
1496
1821
|
const figId = builder ? createFigure(builder, block.altText, "Chart") : void 0;
|
|
1497
1822
|
const fig = figId !== void 0 ? { structId: figId } : {};
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1823
|
+
const emitChartAt = (x, bottomYUp, sink) => {
|
|
1824
|
+
for (const s of block.layout.shapes) sink.push({
|
|
1825
|
+
type: "shape",
|
|
1826
|
+
shape: {
|
|
1827
|
+
paths: s.paths,
|
|
1828
|
+
...s.fillColorHex ? { fillColorHex: s.fillColorHex } : {},
|
|
1829
|
+
...s.stroke ? { stroke: s.stroke } : {},
|
|
1830
|
+
transform: flipTransform([
|
|
1831
|
+
1,
|
|
1832
|
+
0,
|
|
1833
|
+
0,
|
|
1834
|
+
1,
|
|
1835
|
+
x,
|
|
1836
|
+
bottomYUp
|
|
1837
|
+
], ctx.pageHeight)
|
|
1838
|
+
},
|
|
1839
|
+
...fig
|
|
1840
|
+
});
|
|
1841
|
+
for (const t of block.layout.texts) sink.push({
|
|
1842
|
+
type: "line",
|
|
1843
|
+
line: t.line,
|
|
1844
|
+
originX: pt(x + t.x),
|
|
1845
|
+
baselineY: pt(ctx.pageHeight - (bottomYUp + t.y)),
|
|
1846
|
+
...fig
|
|
1847
|
+
});
|
|
1848
|
+
};
|
|
1849
|
+
if (block.float?.wrap === "none") emitChartAt(floatX(block.float, block.widthPt), floatTopYUp(block.float) - block.heightPt, block.float.behind ? floatsBehind : floatsFront);
|
|
1850
|
+
else {
|
|
1851
|
+
cursorY -= block.spacingBeforePt;
|
|
1852
|
+
if (cursorY - block.heightPt < bottomLimit() && colHasContent()) advanceColumn();
|
|
1853
|
+
cursorY -= block.heightPt;
|
|
1854
|
+
const offset = alignmentOffset(block.resolvedAlignment, block.widthPt, colWidth());
|
|
1855
|
+
emitChartAt(colLeft() + offset, cursorY, current);
|
|
1856
|
+
cursorY -= block.spacingAfterPt;
|
|
1857
|
+
}
|
|
1529
1858
|
} else {
|
|
1530
1859
|
const colCount = block.rows.reduce((max, r) => Math.max(max, r.cells.reduce((s, c) => Math.max(s, c.colStart + c.colSpan), 0)), 0);
|
|
1531
1860
|
const headerRows = [];
|
|
@@ -1533,7 +1862,7 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US") {
|
|
|
1533
1862
|
else break;
|
|
1534
1863
|
const headerHeightPt = headerRows.reduce((s, r) => s + r.heightPt, 0);
|
|
1535
1864
|
const tableNode = builder ? builder.create("Table", builder.root) : void 0;
|
|
1536
|
-
const tableX =
|
|
1865
|
+
const tableX = colLeft() + block.xOffsetPt;
|
|
1537
1866
|
for (let ri = 0; ri < block.rows.length; ri++) {
|
|
1538
1867
|
const row = block.rows[ri];
|
|
1539
1868
|
const isLeadingHeader = ri < headerRows.length;
|
|
@@ -1555,10 +1884,11 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US") {
|
|
|
1555
1884
|
for (let ci = 0; ci < chunks.length; ci++) {
|
|
1556
1885
|
const chunk = chunks[ci];
|
|
1557
1886
|
const forcedBreak = ci === 0 && row.breakBefore && !isLeadingHeader && current.length > 0;
|
|
1558
|
-
const overflow = cursorY - chunk.heightPt <
|
|
1887
|
+
const overflow = cursorY - chunk.heightPt < bottomLimit() && colHasContent();
|
|
1559
1888
|
if (forcedBreak || overflow) {
|
|
1560
|
-
flushPage();
|
|
1561
|
-
|
|
1889
|
+
if (forcedBreak) flushPage();
|
|
1890
|
+
else advanceColumn();
|
|
1891
|
+
if (!isLeadingHeader && headerRows.length > 0 && cursorY - headerHeightPt - chunk.heightPt >= bottomLimit()) for (const hr of headerRows) {
|
|
1562
1892
|
emitRowChunk(current, hr, tableX, cursorY, ctx.pageHeight, colCount, void 0);
|
|
1563
1893
|
cursorY -= hr.heightPt;
|
|
1564
1894
|
}
|
|
@@ -1571,6 +1901,12 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US") {
|
|
|
1571
1901
|
}
|
|
1572
1902
|
flushPage();
|
|
1573
1903
|
if (pages.length === 0) flushPage(true);
|
|
1904
|
+
for (const d of dynBands) {
|
|
1905
|
+
const cmds = d.render(d.pageNumber, pages.length);
|
|
1906
|
+
const page = pages[d.pageIdx];
|
|
1907
|
+
if (d.position === "header") page.commands.unshift(...cmds);
|
|
1908
|
+
else page.commands.push(...cmds);
|
|
1909
|
+
}
|
|
1574
1910
|
return pages;
|
|
1575
1911
|
}
|
|
1576
1912
|
function tableCellRowSpan(rows, startRowIdx, colStart) {
|