reamkit 1.17.0 → 1.18.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/dist/esm/core/document-model/types.d.ts +53 -1
- package/dist/esm/core/images.d.ts +2 -2
- package/dist/esm/core/images.js +38 -0
- package/dist/esm/core/lzw.d.ts +17 -0
- package/dist/esm/core/lzw.js +83 -0
- package/dist/esm/core/metafile/emf.d.ts +16 -0
- package/dist/esm/core/metafile/emf.js +635 -0
- package/dist/esm/core/metafile/picture.d.ts +106 -0
- package/dist/esm/core/metafile/picture.js +55 -0
- package/dist/esm/core/metafile/wmf.d.ts +9 -0
- package/dist/esm/core/metafile/wmf.js +371 -0
- package/dist/esm/core/tiff.d.ts +20 -0
- package/dist/esm/core/tiff.js +339 -0
- package/dist/esm/core/vector.d.ts +5 -0
- package/dist/esm/excel/print-model.js +3 -1
- package/dist/esm/html/html-writer.js +3 -2
- package/dist/esm/layout/page-doc.d.ts +46 -3
- package/dist/esm/layout/styled-layout.js +486 -81
- package/dist/esm/pdf/styled-page-emitter.js +78 -3
- package/dist/esm/pdf/vector-graphics.d.ts +1 -1
- package/dist/esm/pdf/vector-graphics.js +2 -1
- package/dist/esm/pdf-reader/image-decode.js +7 -75
- package/dist/esm/svg/svg-writer.js +1 -1
- package/dist/esm/word/document-parser.js +3 -0
- package/dist/esm/word/drawing-parser.d.ts +5 -0
- package/dist/esm/word/drawing-parser.js +95 -12
- package/package.json +1 -1
|
@@ -4,6 +4,9 @@ import { createFontMeasure } from "../core/font/measure.js";
|
|
|
4
4
|
import { halfPtToPt, pt } from "../core/ir/units.js";
|
|
5
5
|
import { ResourceStore } from "../core/ir/resources.js";
|
|
6
6
|
import { prepareImage } from "../core/images.js";
|
|
7
|
+
import { PathBuilder, flipTransform } from "../core/vector.js";
|
|
8
|
+
import { isEmf, readEmf } from "../core/metafile/emf.js";
|
|
9
|
+
import { isWmf, readWmf } from "../core/metafile/wmf.js";
|
|
7
10
|
import { segmentLevels } from "../core/bidi/segments.js";
|
|
8
11
|
import { analyzeString, hasBidiCharacters } from "../core/bidi/index.js";
|
|
9
12
|
import { FORCED_BREAK, breakLines } from "../core/line-breaker/knuth-plass.js";
|
|
@@ -15,7 +18,6 @@ import { resolveParagraphProperties, resolveRunProperties } from "../core/style-
|
|
|
15
18
|
import "../core/style-cascade/index.js";
|
|
16
19
|
import { applyNumbering, applyNumberingToHeadersFooters } from "../core/numbering/apply.js";
|
|
17
20
|
import "../core/numbering/index.js";
|
|
18
|
-
import { PathBuilder, flipTransform } from "../core/vector.js";
|
|
19
21
|
import { buildSparkline } from "../core/drawingml/sparkline-geometry.js";
|
|
20
22
|
import { arcPoint, arcToBeziers } from "../core/arc-to-bezier.js";
|
|
21
23
|
import { buildChartScene, legendSeriesName } from "../core/drawingml/chart-geometry.js";
|
|
@@ -55,6 +57,35 @@ var MIN_WRAP_WIDTH = 36;
|
|
|
55
57
|
function isOutOfFlowFloat(f) {
|
|
56
58
|
return f !== void 0 && f.wrap !== "topAndBottom";
|
|
57
59
|
}
|
|
60
|
+
/** The float's left edge, resolved from its horizontal anchor (§20.4.3.3). */
|
|
61
|
+
function floatXIn(frame, f, widthPt) {
|
|
62
|
+
const h = f.posH;
|
|
63
|
+
if (!h) return frame.columnLeft;
|
|
64
|
+
const textRight = frame.marginLeft + frame.contentWidth;
|
|
65
|
+
const pageRight = frame.pageLeft + frame.pageWidth;
|
|
66
|
+
const base = h.relativeFrom === "page" || h.relativeFrom === "leftMargin" ? frame.pageLeft : h.relativeFrom === "column" ? frame.columnLeft : h.relativeFrom === "rightMargin" ? textRight : frame.marginLeft;
|
|
67
|
+
const span = h.relativeFrom === "page" ? frame.pageWidth : h.relativeFrom === "column" ? frame.columnWidth : h.relativeFrom === "leftMargin" ? frame.marginLeft - frame.pageLeft : h.relativeFrom === "rightMargin" ? pageRight - textRight : frame.contentWidth;
|
|
68
|
+
if (h.align === "center") return base + (span - widthPt) / 2;
|
|
69
|
+
if (h.align === "right") return base + span - widthPt;
|
|
70
|
+
return base + (h.offsetPt ?? 0);
|
|
71
|
+
}
|
|
72
|
+
/** The float's TOP, y-up, resolved from its vertical anchor (§20.4.3.4). */
|
|
73
|
+
function floatTopYUpIn(frame, f, heightPt = 0) {
|
|
74
|
+
const v = f.posV;
|
|
75
|
+
if (!v) return frame.anchorY;
|
|
76
|
+
if (v.align !== void 0) {
|
|
77
|
+
const page = v.relativeFrom === "page";
|
|
78
|
+
const topYUp = page ? frame.pageTopYUp : frame.marginTopYUp;
|
|
79
|
+
const bottomYUp = page ? frame.pageBottomYUp : frame.marginBottomYUp;
|
|
80
|
+
if (v.align === "top") return topYUp;
|
|
81
|
+
if (v.align === "bottom") return bottomYUp + heightPt;
|
|
82
|
+
return bottomYUp + (topYUp - bottomYUp + heightPt) / 2;
|
|
83
|
+
}
|
|
84
|
+
if (v.relativeFrom === "page" || v.relativeFrom === "topMargin") return frame.pageTopYUp - (v.offsetPt ?? 0);
|
|
85
|
+
if (v.relativeFrom === "bottomMargin") return frame.marginBottomYUp - (v.offsetPt ?? 0);
|
|
86
|
+
if (v.relativeFrom === "margin") return frame.marginTopYUp - (v.offsetPt ?? 0);
|
|
87
|
+
return frame.anchorY - (v.offsetPt ?? 0);
|
|
88
|
+
}
|
|
58
89
|
var FOOTNOTE_RULE_WIDTH = 144;
|
|
59
90
|
function assignNoteNumbers(body, commentIds) {
|
|
60
91
|
const footnotes = /* @__PURE__ */ new Map();
|
|
@@ -273,8 +304,8 @@ function layoutStyledDocument(body, options) {
|
|
|
273
304
|
const pdfaProfile = options.pdfA ? parsePdfAProfile(options.pdfA) : void 0;
|
|
274
305
|
const tagged = options.tagged === true || options.pdfUA === true || (pdfaProfile?.tagged ?? false);
|
|
275
306
|
const structBuilder = tagged ? new StructTreeBuilder() : void 0;
|
|
276
|
-
const fontResources = collectFontResources(numberedBody, numberedHeadersFooters, options);
|
|
277
307
|
const imageResources = collectImageResources(numberedBody, numberedHeadersFooters, options);
|
|
308
|
+
const fontResources = collectFontResources(numberedBody, numberedHeadersFooters, options, imageResources);
|
|
278
309
|
const sectionCtxs = sectionList.map((s) => buildSectionContext(s, options, numberedHeadersFooters, fontResources, imageResources));
|
|
279
310
|
let sectionIdx = 0;
|
|
280
311
|
const bodyFrames = frameGroups(numberedBody);
|
|
@@ -309,6 +340,7 @@ function layoutStyledDocument(body, options) {
|
|
|
309
340
|
spacingBeforePt: 0
|
|
310
341
|
};
|
|
311
342
|
}
|
|
343
|
+
flowLinkedTextBoxes(blocks);
|
|
312
344
|
const noteBlockCache = /* @__PURE__ */ new Map();
|
|
313
345
|
const notePlan = options.footnotes && noteAssigned.footnotes.size > 0 ? {
|
|
314
346
|
numbers: noteAssigned.footnotes,
|
|
@@ -775,8 +807,98 @@ function frameShape(frame, paragraphs, widthPt, exact) {
|
|
|
775
807
|
};
|
|
776
808
|
}
|
|
777
809
|
/** §17.3.1.11 → §20.4.2.3: the frame's anchor, in the terms floats are placed in. */
|
|
810
|
+
/**
|
|
811
|
+
* `wps:linkedTxbx` — carry each chain's overflow from one box to the next.
|
|
812
|
+
* The words all live in the chain's FIRST box; a box shows as many of its lines
|
|
813
|
+
* as its height holds and hands the rest on, so LinkedTextBoxes.docx reads down
|
|
814
|
+
* one column and continues at the top of the other. A box that ends a chain
|
|
815
|
+
* keeps whatever is left, overflowing as it would have anyway.
|
|
816
|
+
*
|
|
817
|
+
* The lines are broken at the first box's width, so a chain of boxes of
|
|
818
|
+
* different widths sets its later columns to the wrong measure; re-breaking
|
|
819
|
+
* needs the source paragraphs split at the carry point, which the laid-out
|
|
820
|
+
* lines no longer know.
|
|
821
|
+
*/
|
|
822
|
+
function flowLinkedTextBoxes(blocks) {
|
|
823
|
+
const chains = /* @__PURE__ */ new Map();
|
|
824
|
+
blocks.forEach((b, i) => {
|
|
825
|
+
if (b.kind !== "shape" || !b.textChain) return;
|
|
826
|
+
const at = chains.get(b.textChain.id) ?? [];
|
|
827
|
+
at.push(i);
|
|
828
|
+
chains.set(b.textChain.id, at);
|
|
829
|
+
});
|
|
830
|
+
for (const indices of chains.values()) {
|
|
831
|
+
if (indices.length < 2) continue;
|
|
832
|
+
indices.sort((a, b) => {
|
|
833
|
+
return (blocks[a].textChain?.seq ?? 0) - (blocks[b].textChain?.seq ?? 0);
|
|
834
|
+
});
|
|
835
|
+
let carried = [];
|
|
836
|
+
indices.forEach((idx, n) => {
|
|
837
|
+
const box = blocks[idx];
|
|
838
|
+
const all = n === 0 ? boxLines(box) : carried;
|
|
839
|
+
const last = n === indices.length - 1;
|
|
840
|
+
const room = box.heightPt - box.insetTopPt - box.insetBottomPt;
|
|
841
|
+
const kept = [];
|
|
842
|
+
let used = 0;
|
|
843
|
+
for (const l of all) {
|
|
844
|
+
const h = computeLineHeight(l.line, l.line.resolved) + l.gapPt;
|
|
845
|
+
if (!last && kept.length > 0 && used + h > room) break;
|
|
846
|
+
kept.push(l);
|
|
847
|
+
used += h;
|
|
848
|
+
}
|
|
849
|
+
carried = all.slice(kept.length);
|
|
850
|
+
blocks[idx] = rebuildBoxLines(box, kept);
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
function boxLines(box) {
|
|
855
|
+
return box.textLines.map((line, i) => ({
|
|
856
|
+
line,
|
|
857
|
+
gapPt: box.textLineGaps?.get(i) ?? 0,
|
|
858
|
+
...box.textCharts?.get(i) ? { chart: box.textCharts.get(i) } : {},
|
|
859
|
+
...box.textShapes?.get(i) ? { shape: box.textShapes.get(i) } : {},
|
|
860
|
+
...box.textTables?.get(i) ? { table: box.textTables.get(i) } : {}
|
|
861
|
+
}));
|
|
862
|
+
}
|
|
863
|
+
function rebuildBoxLines(box, lines) {
|
|
864
|
+
const charts = /* @__PURE__ */ new Map();
|
|
865
|
+
const shapes = /* @__PURE__ */ new Map();
|
|
866
|
+
const tables = /* @__PURE__ */ new Map();
|
|
867
|
+
const gaps = /* @__PURE__ */ new Map();
|
|
868
|
+
let height = 0;
|
|
869
|
+
lines.forEach((l, i) => {
|
|
870
|
+
if (l.chart) charts.set(i, l.chart);
|
|
871
|
+
if (l.shape) shapes.set(i, l.shape);
|
|
872
|
+
if (l.table) tables.set(i, l.table);
|
|
873
|
+
if (l.gapPt > 0) gaps.set(i, l.gapPt);
|
|
874
|
+
height += computeLineHeight(l.line, l.line.resolved) + l.gapPt;
|
|
875
|
+
});
|
|
876
|
+
const { textCharts: _c, textShapes: _s, textTables: _t, textLineGaps: _g, ...rest } = box;
|
|
877
|
+
return {
|
|
878
|
+
...rest,
|
|
879
|
+
textLines: lines.map((l) => l.line),
|
|
880
|
+
...charts.size > 0 ? { textCharts: charts } : {},
|
|
881
|
+
...shapes.size > 0 ? { textShapes: shapes } : {},
|
|
882
|
+
...tables.size > 0 ? { textTables: tables } : {},
|
|
883
|
+
...gaps.size > 0 ? { textLineGaps: gaps } : {},
|
|
884
|
+
textHeightPt: height
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* §17.3.1.11 — whether the frame is placed DOWN THE PAGE by itself, rather than
|
|
889
|
+
* where the flow has reached. `w:vAnchor="text"` (the default) measures `w:y`
|
|
890
|
+
* from the paragraph's own position, so such frames stack as paragraphs do —
|
|
891
|
+
* and a float takes no flow space, so lifting them out puts every one of them
|
|
892
|
+
* on the same line: tdf105035_framePrB.docx writes its title and its author
|
|
893
|
+
* line as text-anchored frames and both landed on the cursor, one over the
|
|
894
|
+
* other. Only a frame anchored to the page or the margin, or aligned by
|
|
895
|
+
* keyword, truly stands somewhere of its own.
|
|
896
|
+
*/
|
|
897
|
+
function framePositioned(frame) {
|
|
898
|
+
return frame.yAlign !== void 0 || frame.vAnchor !== void 0 && frame.vAnchor !== "text";
|
|
899
|
+
}
|
|
778
900
|
function frameFloat(frame) {
|
|
779
|
-
const wrap = frame.wrap === "none" ? "none" : frame.wrap === "notBeside" ? "topAndBottom" : "square";
|
|
901
|
+
const wrap = frame.wrap === "none" ? "none" : frame.wrap === "notBeside" ? framePositioned(frame) ? "notBeside" : "topAndBottom" : "square";
|
|
780
902
|
const hRel = frame.hAnchor === "page" ? "page" : frame.hAnchor === "margin" ? "margin" : "column";
|
|
781
903
|
const vRel = frame.vAnchor === "page" ? "page" : frame.vAnchor === "margin" ? "margin" : "paragraph";
|
|
782
904
|
const align = frame.xAlign === "left" || frame.xAlign === "center" || frame.xAlign === "right" ? frame.xAlign : void 0;
|
|
@@ -825,7 +947,10 @@ function laidOutBlocksFor(elements, options, fontResources, contentWidth, imageR
|
|
|
825
947
|
function layoutBodyElement(el, options, fontResources, imageResources, contentWidth, maxHeight, box) {
|
|
826
948
|
if (el.kind === "paragraph") return layoutParagraphBlock(el.paragraph, options, fontResources, imageResources, contentWidth);
|
|
827
949
|
if (el.kind === "table") return layoutTableBlock(el.table, options, fontResources, imageResources, contentWidth);
|
|
828
|
-
if (el.kind === "image")
|
|
950
|
+
if (el.kind === "image") {
|
|
951
|
+
const meta = el.image.resource ? imageResources?.get(el.image.resource)?.metafile : void 0;
|
|
952
|
+
return meta ? layoutMetafileBlock(el.image, meta, options, fontResources, contentWidth, maxHeight, box) : layoutImageBlock(el.image, imageResources, contentWidth, maxHeight, box);
|
|
953
|
+
}
|
|
829
954
|
if (el.kind === "chart") return layoutChartBlock(el.chart, options, fontResources, contentWidth, maxHeight);
|
|
830
955
|
return layoutShapeBlock(el.shape, options, fontResources, imageResources, contentWidth, maxHeight, box);
|
|
831
956
|
}
|
|
@@ -873,6 +998,7 @@ function layoutImageBlock(image, imageResources, contentWidth, maxHeight, box) {
|
|
|
873
998
|
resolvedAlignment,
|
|
874
999
|
resourceName: res?.resourceName ?? "",
|
|
875
1000
|
...image.outline ? { outline: image.outline } : {},
|
|
1001
|
+
...image.wash ? { wash: image.wash } : {},
|
|
876
1002
|
...image.crop ? { crop: image.crop } : {},
|
|
877
1003
|
...image.rotation60k ? { rotationDeg: image.rotation60k / 6e4 } : {},
|
|
878
1004
|
...image.flipH ? { flipH: true } : {},
|
|
@@ -1055,6 +1181,7 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1055
1181
|
...fillImageResourceName && shape.fill.imageCrop ? { fillImageCrop: shape.fill.imageCrop } : {},
|
|
1056
1182
|
...fillColorHex ? { fillColorHex } : {},
|
|
1057
1183
|
...fillGradient ? { fillGradient } : {},
|
|
1184
|
+
...shape.fill.alpha !== void 0 && shape.fill.alpha < 1 ? { fillAlpha: shape.fill.alpha } : {},
|
|
1058
1185
|
...stroke ? { stroke } : {},
|
|
1059
1186
|
...shape.shadow ? { shadow: shape.shadow } : {},
|
|
1060
1187
|
rotation60k: t?.rotation60k ?? 0,
|
|
@@ -1069,6 +1196,7 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1069
1196
|
...textTables.size > 0 ? { textTables } : {},
|
|
1070
1197
|
...textLineGaps.size > 0 ? { textLineGaps } : {},
|
|
1071
1198
|
textHeightPt,
|
|
1199
|
+
...text?.chain ? { textChain: text.chain } : {},
|
|
1072
1200
|
insetLeftPt,
|
|
1073
1201
|
insetRightPt,
|
|
1074
1202
|
insetTopPt,
|
|
@@ -1079,6 +1207,144 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1079
1207
|
...shape.float ? { float: shape.float } : {}
|
|
1080
1208
|
};
|
|
1081
1209
|
}
|
|
1210
|
+
/**
|
|
1211
|
+
* MS-EMF / MS-WMF — a metafile picture as the primitives a chart is made of,
|
|
1212
|
+
* scaled from its own logical box into the box the drawing reserves.
|
|
1213
|
+
*
|
|
1214
|
+
* A metafile IS a little drawing program, and what it draws is paths and words:
|
|
1215
|
+
* the same two things a chart's layout carries, placed in the same local y-up
|
|
1216
|
+
* frame. So one is turned into the other rather than growing a block kind, a
|
|
1217
|
+
* pagination arm and an emitter of its own.
|
|
1218
|
+
*/
|
|
1219
|
+
function layoutMetafileBlock(image, pic, options, fontResources, contentWidth, maxHeight, box) {
|
|
1220
|
+
const placed = layoutImageBlock(image, void 0, contentWidth, maxHeight, box);
|
|
1221
|
+
const widthPt = placed.widthPt;
|
|
1222
|
+
const heightPt = placed.heightPt;
|
|
1223
|
+
const layout = rotateDrawing(metafileDrawing(pic, widthPt, heightPt, options, fontResources), (image.rotation60k ?? 0) / 6e4, widthPt / 2, heightPt / 2);
|
|
1224
|
+
const pp = image.paragraphProperties;
|
|
1225
|
+
return {
|
|
1226
|
+
kind: "chart",
|
|
1227
|
+
widthPt,
|
|
1228
|
+
heightPt,
|
|
1229
|
+
layout,
|
|
1230
|
+
resolvedAlignment: pp.alignment ?? "left",
|
|
1231
|
+
spacingBeforePt: pp.spacingBefore ?? 0,
|
|
1232
|
+
spacingAfterPt: pp.spacingAfter ?? 0,
|
|
1233
|
+
figureRole: "Image",
|
|
1234
|
+
...image.altText ? { altText: image.altText } : {},
|
|
1235
|
+
...image.float ? { float: image.float } : {}
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
/** The same primitives, turned `deg` CLOCKWISE about a point of the local frame. */
|
|
1239
|
+
function rotateDrawing(layout, deg, cx, cy) {
|
|
1240
|
+
if (!deg) return layout;
|
|
1241
|
+
const a = -deg * Math.PI / 180;
|
|
1242
|
+
const cos = Math.cos(a);
|
|
1243
|
+
const sin = Math.sin(a);
|
|
1244
|
+
const at = (x, y) => ({
|
|
1245
|
+
x: cx + (x - cx) * cos - (y - cy) * sin,
|
|
1246
|
+
y: cy + (x - cx) * sin + (y - cy) * cos
|
|
1247
|
+
});
|
|
1248
|
+
return {
|
|
1249
|
+
shapes: layout.shapes.map((sh) => ({
|
|
1250
|
+
...sh,
|
|
1251
|
+
paths: sh.paths.map((path) => ({
|
|
1252
|
+
...path,
|
|
1253
|
+
segments: path.segments.map((seg) => {
|
|
1254
|
+
if (seg.op === "close") return seg;
|
|
1255
|
+
if (seg.op === "cubic") {
|
|
1256
|
+
const c1 = at(seg.x1, seg.y1);
|
|
1257
|
+
const c2 = at(seg.x2, seg.y2);
|
|
1258
|
+
const e = at(seg.x, seg.y);
|
|
1259
|
+
return {
|
|
1260
|
+
op: "cubic",
|
|
1261
|
+
x1: c1.x,
|
|
1262
|
+
y1: c1.y,
|
|
1263
|
+
x2: c2.x,
|
|
1264
|
+
y2: c2.y,
|
|
1265
|
+
x: e.x,
|
|
1266
|
+
y: e.y
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1269
|
+
const p = at(seg.x, seg.y);
|
|
1270
|
+
return {
|
|
1271
|
+
op: seg.op,
|
|
1272
|
+
x: p.x,
|
|
1273
|
+
y: p.y
|
|
1274
|
+
};
|
|
1275
|
+
})
|
|
1276
|
+
}))
|
|
1277
|
+
})),
|
|
1278
|
+
texts: layout.texts.map((t) => {
|
|
1279
|
+
const p = at(t.x, t.y);
|
|
1280
|
+
return {
|
|
1281
|
+
...t,
|
|
1282
|
+
x: p.x,
|
|
1283
|
+
y: p.y,
|
|
1284
|
+
rotationDeg: (t.rotationDeg ?? 0) - deg
|
|
1285
|
+
};
|
|
1286
|
+
})
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
/**
|
|
1290
|
+
* A metafile's primitives, scaled from its own logical box into a `widthPt` ×
|
|
1291
|
+
* `heightPt` one and turned y-up about its bottom-left corner — the frame both
|
|
1292
|
+
* a chart block and an inline picture token are drawn in.
|
|
1293
|
+
*/
|
|
1294
|
+
function metafileDrawing(pic, widthPt, heightPt, options, fontResources) {
|
|
1295
|
+
const sx = widthPt / pic.width;
|
|
1296
|
+
const sy = heightPt / pic.height;
|
|
1297
|
+
const mapX = (x) => (x - pic.left) * sx;
|
|
1298
|
+
const mapY = (y) => heightPt - (y - pic.top) * sy;
|
|
1299
|
+
const shapes = [];
|
|
1300
|
+
const texts = [];
|
|
1301
|
+
for (const prim of pic.prims) {
|
|
1302
|
+
if (prim.kind === "path") {
|
|
1303
|
+
shapes.push({
|
|
1304
|
+
paths: prim.paths.map((path) => ({
|
|
1305
|
+
...path,
|
|
1306
|
+
segments: path.segments.map((seg) => seg.op === "close" ? seg : seg.op === "cubic" ? {
|
|
1307
|
+
op: "cubic",
|
|
1308
|
+
x1: mapX(seg.x1),
|
|
1309
|
+
y1: mapY(seg.y1),
|
|
1310
|
+
x2: mapX(seg.x2),
|
|
1311
|
+
y2: mapY(seg.y2),
|
|
1312
|
+
x: mapX(seg.x),
|
|
1313
|
+
y: mapY(seg.y)
|
|
1314
|
+
} : {
|
|
1315
|
+
op: seg.op,
|
|
1316
|
+
x: mapX(seg.x),
|
|
1317
|
+
y: mapY(seg.y)
|
|
1318
|
+
})
|
|
1319
|
+
})),
|
|
1320
|
+
...prim.fillColorHex !== void 0 ? { fillColorHex: prim.fillColorHex } : {},
|
|
1321
|
+
...prim.stroke ? { stroke: {
|
|
1322
|
+
...prim.stroke,
|
|
1323
|
+
widthPt: Math.max(.25, prim.stroke.widthPt * sx)
|
|
1324
|
+
} } : {}
|
|
1325
|
+
});
|
|
1326
|
+
continue;
|
|
1327
|
+
}
|
|
1328
|
+
if (prim.kind !== "text") continue;
|
|
1329
|
+
const { variant } = options.registry.resolveByStyle(prim.bold === true, prim.italic === true);
|
|
1330
|
+
const font = fontResources.get(variant);
|
|
1331
|
+
if (!font) continue;
|
|
1332
|
+
const sizePt = Math.max(1, prim.sizeLu * sy);
|
|
1333
|
+
const line = makeChartLabelLine(prim.text, font, sizePt, prim.colorHex);
|
|
1334
|
+
const shift = prim.alignH === "center" ? -line.contentWidthPt / 2 : prim.alignH === "right" ? -line.contentWidthPt : 0;
|
|
1335
|
+
const baselineY = mapY(prim.y) - (prim.alignBaseline ? 0 : sizePt * .8);
|
|
1336
|
+
texts.push({
|
|
1337
|
+
line,
|
|
1338
|
+
x: mapX(prim.x) + shift,
|
|
1339
|
+
y: baselineY,
|
|
1340
|
+
...prim.escapement ? { rotationDeg: prim.escapement / 10 } : {}
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
return {
|
|
1344
|
+
shapes,
|
|
1345
|
+
texts
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1082
1348
|
function layoutChartBlock(block, options, fontResources, contentWidth, maxHeight) {
|
|
1083
1349
|
let widthPt = block.width;
|
|
1084
1350
|
let heightPt = block.height;
|
|
@@ -1376,6 +1642,15 @@ function collectImageResources(body, headersFooters, options) {
|
|
|
1376
1642
|
for (const resourceId of seen) {
|
|
1377
1643
|
const bytes = options.resources.get(resourceId);
|
|
1378
1644
|
if (!bytes) continue;
|
|
1645
|
+
if (isEmf(bytes) || isWmf(bytes)) {
|
|
1646
|
+
try {
|
|
1647
|
+
out.set(resourceId, {
|
|
1648
|
+
resourceName: "",
|
|
1649
|
+
metafile: isEmf(bytes) ? readEmf(bytes) : readWmf(bytes)
|
|
1650
|
+
});
|
|
1651
|
+
} catch {}
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1379
1654
|
let prepared;
|
|
1380
1655
|
try {
|
|
1381
1656
|
prepared = prepareImage(bytes, { flattenAlpha });
|
|
@@ -1481,6 +1756,43 @@ function emitShapeText(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
|
1481
1756
|
textY -= sh.textLineGaps?.get(i) ?? 0;
|
|
1482
1757
|
});
|
|
1483
1758
|
}
|
|
1759
|
+
/** The page a table is being drawn onto, as a cell's floats need to see it. */
|
|
1760
|
+
function cellAnchorCtx(asm) {
|
|
1761
|
+
return {
|
|
1762
|
+
sink: (behind, zOrder) => PageAssembler.zSink(behind ? asm.floatsBehind : asm.floatsFront, zOrder),
|
|
1763
|
+
frame: asm.floatFrame(),
|
|
1764
|
+
exclude: (f, x, topYUp, widthPt, heightPt) => {
|
|
1765
|
+
asm.excludeFloat(f, x, topYUp, widthPt, heightPt);
|
|
1766
|
+
},
|
|
1767
|
+
pageHeight: asm.ctx.pageHeight
|
|
1768
|
+
};
|
|
1769
|
+
}
|
|
1770
|
+
function emitCellFloat(cf, ctx, frame) {
|
|
1771
|
+
const float = cf.block.float;
|
|
1772
|
+
if (!float) return;
|
|
1773
|
+
const x = floatXIn(frame, float, cf.block.widthPt);
|
|
1774
|
+
const topYUp = floatTopYUpIn(frame, float, cf.block.heightPt);
|
|
1775
|
+
const sink = ctx.sink(float.behind === true, float.zOrder);
|
|
1776
|
+
if (cf.block.kind === "shape") emitShapeItems(cf.block, x, topYUp - cf.block.heightPt, sink, ctx.pageHeight, void 0);
|
|
1777
|
+
else {
|
|
1778
|
+
const ins = cf.block.drawInset;
|
|
1779
|
+
sink.push({
|
|
1780
|
+
type: "image",
|
|
1781
|
+
x: pt(x + (ins?.dxPt ?? 0)),
|
|
1782
|
+
y: pt(ctx.pageHeight - (topYUp - (ins?.dyTopPt ?? 0))),
|
|
1783
|
+
width: pt(ins?.widthPt ?? cf.block.widthPt),
|
|
1784
|
+
height: pt(ins?.heightPt ?? cf.block.heightPt),
|
|
1785
|
+
imageResourceName: cf.block.resourceName,
|
|
1786
|
+
...cf.block.crop ? { crop: cf.block.crop } : {},
|
|
1787
|
+
...cf.block.wash ? { wash: cf.block.wash } : {},
|
|
1788
|
+
...cf.block.rotationDeg ? { rotationDeg: cf.block.rotationDeg } : {},
|
|
1789
|
+
...cf.block.flipH ? { flipH: true } : {},
|
|
1790
|
+
...cf.block.flipV ? { flipV: true } : {}
|
|
1791
|
+
});
|
|
1792
|
+
if (cf.block.outline) sink.push(...pictureOutlineItems(cf.block.outline, x + (ins?.dxPt ?? 0), ctx.pageHeight - (topYUp - (ins?.dyTopPt ?? 0)), ins?.widthPt ?? cf.block.widthPt, ins?.heightPt ?? cf.block.heightPt, void 0));
|
|
1793
|
+
}
|
|
1794
|
+
if (float.wrap !== "none") ctx.exclude(float, x, topYUp, cf.block.widthPt, cf.block.heightPt);
|
|
1795
|
+
}
|
|
1484
1796
|
function emitShapeItems(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
1485
1797
|
if (sh.fillImageResourceName) sink.push({
|
|
1486
1798
|
type: "image",
|
|
@@ -1511,6 +1823,7 @@ function emitShapeItems(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
|
1511
1823
|
paths: sh.paths,
|
|
1512
1824
|
...sh.fillColorHex ? { fillColorHex: sh.fillColorHex } : {},
|
|
1513
1825
|
...sh.fillGradient ? { fillGradient: sh.fillGradient } : {},
|
|
1826
|
+
...sh.fillAlpha !== void 0 ? { fillAlpha: sh.fillAlpha } : {},
|
|
1514
1827
|
...sh.stroke ? { stroke: sh.stroke } : {},
|
|
1515
1828
|
...sh.shadow ? { shadow: sh.shadow } : {},
|
|
1516
1829
|
transform: flipTransform(buildShapeTransform(x, bottomYUp, sh.widthPt, sh.heightPt, sh.rotation60k, sh.flipH, sh.flipV), pageHeight)
|
|
@@ -1620,6 +1933,7 @@ function drawBlocksSequentially(blocks, startX, startY, pageHeight, contentWidth
|
|
|
1620
1933
|
height: pt(block.heightPt),
|
|
1621
1934
|
imageResourceName: block.resourceName,
|
|
1622
1935
|
...block.crop ? { crop: block.crop } : {},
|
|
1936
|
+
...block.wash ? { wash: block.wash } : {},
|
|
1623
1937
|
...block.rotationDeg ? { rotationDeg: block.rotationDeg } : {},
|
|
1624
1938
|
...block.flipH ? { flipH: true } : {},
|
|
1625
1939
|
...block.flipV ? { flipV: true } : {}
|
|
@@ -1739,7 +2053,7 @@ function runFontKeyAndParsed(options, ascii, bold, italic) {
|
|
|
1739
2053
|
function lookupFont(resources, fontKey) {
|
|
1740
2054
|
return resources.get(fontKey) ?? resources.values().next().value;
|
|
1741
2055
|
}
|
|
1742
|
-
function collectFontResources(body, headersFooters, options) {
|
|
2056
|
+
function collectFontResources(body, headersFooters, options, imageResources) {
|
|
1743
2057
|
const used = /* @__PURE__ */ new Map();
|
|
1744
2058
|
const addRun = (run, para) => {
|
|
1745
2059
|
const resolved = resolveRunProperties(run.properties, para.properties, options.styles);
|
|
@@ -1774,30 +2088,48 @@ function collectFontResources(body, headersFooters, options) {
|
|
|
1774
2088
|
for (const ch of seg.text) bucket.gids.add(parsed.glyphForCodepoint(ch.codePointAt(0)));
|
|
1775
2089
|
}
|
|
1776
2090
|
};
|
|
1777
|
-
const
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
if (
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
continue;
|
|
1790
|
-
}
|
|
1791
|
-
if (run.footnoteRef !== void 0 || run.endnoteRef !== void 0 || run.noteNumber) {
|
|
1792
|
-
addRun({
|
|
1793
|
-
text: `${run.text}0123456789 `,
|
|
1794
|
-
properties: run.properties
|
|
1795
|
-
}, el.paragraph);
|
|
1796
|
-
continue;
|
|
2091
|
+
const addMetafile = (resource) => {
|
|
2092
|
+
const pic = resource ? imageResources.get(resource)?.metafile : void 0;
|
|
2093
|
+
for (const prim of pic?.prims ?? []) {
|
|
2094
|
+
if (prim.kind !== "text") continue;
|
|
2095
|
+
const reg = options.registry.resolveByStyle(prim.bold === true, prim.italic === true);
|
|
2096
|
+
let bucket = used.get(reg.variant);
|
|
2097
|
+
if (!bucket) {
|
|
2098
|
+
bucket = {
|
|
2099
|
+
parsed: reg.parsed,
|
|
2100
|
+
gids: /* @__PURE__ */ new Set()
|
|
2101
|
+
};
|
|
2102
|
+
used.set(reg.variant, bucket);
|
|
1797
2103
|
}
|
|
1798
|
-
|
|
2104
|
+
for (const ch of prim.text) bucket.gids.add(reg.parsed.glyphForCodepoint(ch.codePointAt(0)));
|
|
1799
2105
|
}
|
|
1800
|
-
|
|
2106
|
+
};
|
|
2107
|
+
const visit = (elements) => {
|
|
2108
|
+
for (const el of elements) if (el.kind === "paragraph") {
|
|
2109
|
+
for (const run of el.paragraph.runs) addMetafile(run.inlineImage?.resource);
|
|
2110
|
+
for (const run of displayCapsRuns(el.paragraph, options)) {
|
|
2111
|
+
if (run.math) {
|
|
2112
|
+
addMath(run.math);
|
|
2113
|
+
continue;
|
|
2114
|
+
}
|
|
2115
|
+
if (run.inlineImage && !run.text) continue;
|
|
2116
|
+
if (run.field !== void 0) {
|
|
2117
|
+
addRun({
|
|
2118
|
+
text: `${run.text}0123456789`,
|
|
2119
|
+
properties: run.properties
|
|
2120
|
+
}, el.paragraph);
|
|
2121
|
+
continue;
|
|
2122
|
+
}
|
|
2123
|
+
if (run.footnoteRef !== void 0 || run.endnoteRef !== void 0 || run.noteNumber) {
|
|
2124
|
+
addRun({
|
|
2125
|
+
text: `${run.text}0123456789 `,
|
|
2126
|
+
properties: run.properties
|
|
2127
|
+
}, el.paragraph);
|
|
2128
|
+
continue;
|
|
2129
|
+
}
|
|
2130
|
+
addRun(run, el.paragraph);
|
|
2131
|
+
}
|
|
2132
|
+
} else if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) {
|
|
1801
2133
|
if (cell.properties.hashOnOverflow === true) for (const inner of cell.content) {
|
|
1802
2134
|
if (inner.kind !== "paragraph") continue;
|
|
1803
2135
|
for (const run of inner.paragraph.runs) addRun({
|
|
@@ -1813,7 +2145,8 @@ function collectFontResources(body, headersFooters, options) {
|
|
|
1813
2145
|
for (const child of sh.children ?? []) shapeText(child.shape);
|
|
1814
2146
|
};
|
|
1815
2147
|
shapeText(el.shape);
|
|
1816
|
-
} else if (el.kind === "
|
|
2148
|
+
} else if (el.kind === "image") addMetafile(el.image.resource);
|
|
2149
|
+
else {
|
|
1817
2150
|
const chart = options.charts?.get(el.chart.chartRelId);
|
|
1818
2151
|
if (chart) {
|
|
1819
2152
|
const reg = options.registry.resolveByStyle(false, false);
|
|
@@ -2104,8 +2437,10 @@ function tokenizeParagraph(paragraph, options, fontResources, imageResources, co
|
|
|
2104
2437
|
imageWidthPt: widthPt,
|
|
2105
2438
|
imageHeightPt: heightPt,
|
|
2106
2439
|
imageResourceName: res?.resourceName ?? "",
|
|
2440
|
+
...res?.metafile ? { imageMetafile: metafileDrawing(res.metafile, drawBox?.widthPt ?? widthPt, drawBox?.heightPt ?? heightPt, options, fontResources) } : {},
|
|
2107
2441
|
...run.inlineImage.outline ? { imageOutline: run.inlineImage.outline } : {},
|
|
2108
2442
|
...run.inlineImage.shadow ? { imageShadow: run.inlineImage.shadow } : {},
|
|
2443
|
+
...run.inlineImage.wash ? { imageWash: run.inlineImage.wash } : {},
|
|
2109
2444
|
...run.inlineImage.crop ? { imageCrop: run.inlineImage.crop } : {},
|
|
2110
2445
|
...run.inlineImage.rotation60k ? { imageRotationDeg: run.inlineImage.rotation60k / 6e4 } : {},
|
|
2111
2446
|
...run.inlineImage.flipH ? { imageFlipH: true } : {},
|
|
@@ -2189,6 +2524,8 @@ function tokenizePlansLtr(plans) {
|
|
|
2189
2524
|
heightPt: plan.imageHeightPt,
|
|
2190
2525
|
...plan.imageOutline ? { outline: plan.imageOutline } : {},
|
|
2191
2526
|
...plan.imageShadow ? { shadow: plan.imageShadow } : {},
|
|
2527
|
+
...plan.imageWash ? { wash: plan.imageWash } : {},
|
|
2528
|
+
...plan.imageMetafile ? { metafile: plan.imageMetafile } : {},
|
|
2192
2529
|
...plan.imageCrop ? { crop: plan.imageCrop } : {},
|
|
2193
2530
|
...plan.imageRotationDeg ? { rotationDeg: plan.imageRotationDeg } : {},
|
|
2194
2531
|
...plan.imageFlipH ? { flipH: true } : {},
|
|
@@ -2260,6 +2597,8 @@ function tokenizePlansBidi(plans, realLevels) {
|
|
|
2260
2597
|
heightPt: plan.imageHeightPt,
|
|
2261
2598
|
...plan.imageOutline ? { outline: plan.imageOutline } : {},
|
|
2262
2599
|
...plan.imageShadow ? { shadow: plan.imageShadow } : {},
|
|
2600
|
+
...plan.imageWash ? { wash: plan.imageWash } : {},
|
|
2601
|
+
...plan.imageMetafile ? { metafile: plan.imageMetafile } : {},
|
|
2263
2602
|
...plan.imageCrop ? { crop: plan.imageCrop } : {},
|
|
2264
2603
|
...plan.imageRotationDeg ? { rotationDeg: plan.imageRotationDeg } : {},
|
|
2265
2604
|
...plan.imageFlipH ? { flipH: true } : {},
|
|
@@ -3158,7 +3497,8 @@ function layoutTableRow(row, rowIdx, rowCount, colCount, tableProps, columnWidth
|
|
|
3158
3497
|
cells: cells.map((c) => clipCellToHeight(c, heightPt)),
|
|
3159
3498
|
columnXOffsets,
|
|
3160
3499
|
rowIdx,
|
|
3161
|
-
rowCount
|
|
3500
|
+
rowCount,
|
|
3501
|
+
...row.properties.cantSplit ? { cantSplit: true } : {}
|
|
3162
3502
|
};
|
|
3163
3503
|
} else if (row.properties.height && row.properties.heightRule === "atLeast") heightPt = Math.max(heightPt, row.properties.height);
|
|
3164
3504
|
return {
|
|
@@ -3166,7 +3506,8 @@ function layoutTableRow(row, rowIdx, rowCount, colCount, tableProps, columnWidth
|
|
|
3166
3506
|
cells,
|
|
3167
3507
|
columnXOffsets,
|
|
3168
3508
|
rowIdx,
|
|
3169
|
-
rowCount
|
|
3509
|
+
rowCount,
|
|
3510
|
+
...row.properties.cantSplit ? { cantSplit: true } : {}
|
|
3170
3511
|
};
|
|
3171
3512
|
}
|
|
3172
3513
|
/**
|
|
@@ -3212,6 +3553,7 @@ function imageRun(image) {
|
|
|
3212
3553
|
inlineImage: {
|
|
3213
3554
|
...image.resource ? { resource: image.resource } : {},
|
|
3214
3555
|
...image.outline ? { outline: image.outline } : {},
|
|
3556
|
+
...image.wash ? { wash: image.wash } : {},
|
|
3215
3557
|
width: image.width,
|
|
3216
3558
|
height: image.height,
|
|
3217
3559
|
...image.crop ? { crop: image.crop } : {},
|
|
@@ -3235,6 +3577,7 @@ function layoutTableCell(cell, tableProps, widthPt, options, fontResources, imag
|
|
|
3235
3577
|
const lines = [];
|
|
3236
3578
|
const nestedTables = [];
|
|
3237
3579
|
const cellShapes = [];
|
|
3580
|
+
const cellFloats = [];
|
|
3238
3581
|
const lineGaps = /* @__PURE__ */ new Map();
|
|
3239
3582
|
let contentHeightPt = 0;
|
|
3240
3583
|
let clipped = false;
|
|
@@ -3288,7 +3631,14 @@ function layoutTableCell(cell, tableProps, widthPt, options, fontResources, imag
|
|
|
3288
3631
|
});
|
|
3289
3632
|
contentHeightPt += block.heightPt;
|
|
3290
3633
|
pendingGapPt = block.spacingAfterPt;
|
|
3291
|
-
}
|
|
3634
|
+
} else if (el.kind === "image" && isOutOfFlowFloat(el.image.float)) cellFloats.push({
|
|
3635
|
+
block: layoutImageBlock(el.image, imageResources, innerWidth),
|
|
3636
|
+
afterLine: lines.length
|
|
3637
|
+
});
|
|
3638
|
+
else if (el.kind === "shape" && isOutOfFlowFloat(el.shape.float)) cellFloats.push({
|
|
3639
|
+
block: layoutShapeBlock(el.shape, options, fontResources, imageResources, innerWidth),
|
|
3640
|
+
afterLine: lines.length
|
|
3641
|
+
});
|
|
3292
3642
|
contentHeightPt += pendingGapPt;
|
|
3293
3643
|
}
|
|
3294
3644
|
const colEnd = colStart + colSpan - 1;
|
|
@@ -3309,6 +3659,7 @@ function layoutTableCell(cell, tableProps, widthPt, options, fontResources, imag
|
|
|
3309
3659
|
...lineGaps.size > 0 ? { lineGaps } : {},
|
|
3310
3660
|
...nestedTables.length > 0 ? { nestedTables } : {},
|
|
3311
3661
|
...cellShapes.length > 0 ? { shapes: cellShapes } : {},
|
|
3662
|
+
...cellFloats.length > 0 ? { floats: cellFloats } : {},
|
|
3312
3663
|
contentHeightPt,
|
|
3313
3664
|
totalHeightPt,
|
|
3314
3665
|
...cell.properties.verticalAlign ? { verticalAlign: cell.properties.verticalAlign } : {},
|
|
@@ -3488,6 +3839,12 @@ var PageAssembler = class PageAssembler {
|
|
|
3488
3839
|
/** The current column's width (the section content width when single-column). */
|
|
3489
3840
|
colWidth = () => this.ctx.columns?.[this.colIdx]?.widthPt ?? this.ctx.contentWidth;
|
|
3490
3841
|
/**
|
|
3842
|
+
* The measure the section's blocks were BROKEN at — the first column's, since
|
|
3843
|
+
* that is all the block pass can know. A column of another width has to
|
|
3844
|
+
* re-break what lands in it.
|
|
3845
|
+
*/
|
|
3846
|
+
builtWidth = () => this.ctx.columns?.[0]?.widthPt ?? this.ctx.contentWidth;
|
|
3847
|
+
/**
|
|
3491
3848
|
* Whether the current column is already in use.
|
|
3492
3849
|
*
|
|
3493
3850
|
* This gates every overflow break, so that a block too tall for an empty page
|
|
@@ -3639,44 +3996,36 @@ var PageAssembler = class PageAssembler {
|
|
|
3639
3996
|
*/
|
|
3640
3997
|
excludeFloat = (f, x, topYUp, w, h) => {
|
|
3641
3998
|
const d = f.wrapDist;
|
|
3999
|
+
const wide = f.wrap === "notBeside";
|
|
3642
4000
|
this.exclusions.push({
|
|
3643
|
-
x0: x - (d?.leftPt ?? 0),
|
|
3644
|
-
x1: x + w + (d?.rightPt ?? 0),
|
|
4001
|
+
x0: wide ? this.colLeft() : x - (d?.leftPt ?? 0),
|
|
4002
|
+
x1: wide ? this.colLeft() + this.colWidth() : x + w + (d?.rightPt ?? 0),
|
|
3645
4003
|
topYUp: topYUp + (d?.topPt ?? 0),
|
|
3646
|
-
bottomYUp: topYUp - h - (d?.bottomPt ?? 0)
|
|
4004
|
+
bottomYUp: topYUp - h - (d?.bottomPt ?? 0),
|
|
4005
|
+
...f.wrapSide === "bothSides" ? { wrapBothSides: true } : {}
|
|
3647
4006
|
});
|
|
3648
4007
|
};
|
|
4008
|
+
/** The frame a float anchored in the body flow is resolved against. */
|
|
4009
|
+
floatFrame = () => ({
|
|
4010
|
+
pageLeft: 0,
|
|
4011
|
+
pageWidth: this.ctx.pageWidth,
|
|
4012
|
+
pageTopYUp: this.ctx.pageHeight,
|
|
4013
|
+
pageBottomYUp: 0,
|
|
4014
|
+
marginLeft: this.ctx.marginLeft,
|
|
4015
|
+
contentWidth: this.ctx.contentWidth,
|
|
4016
|
+
marginTopYUp: this.ctx.pageHeight - this.ctx.marginTop,
|
|
4017
|
+
marginBottomYUp: this.ctx.marginBottom,
|
|
4018
|
+
columnLeft: this.colLeft(),
|
|
4019
|
+
columnWidth: this.colWidth(),
|
|
4020
|
+
anchorY: this.cursorY
|
|
4021
|
+
});
|
|
3649
4022
|
/** The float's left edge on the page, resolved from its horizontal anchor. */
|
|
3650
|
-
floatX = (f, widthPt) =>
|
|
3651
|
-
const h = f.posH;
|
|
3652
|
-
if (!h) return this.colLeft();
|
|
3653
|
-
const textRight = this.ctx.marginLeft + this.ctx.contentWidth;
|
|
3654
|
-
const base = h.relativeFrom === "page" || h.relativeFrom === "leftMargin" ? 0 : h.relativeFrom === "column" ? this.colLeft() : h.relativeFrom === "rightMargin" ? textRight : this.ctx.marginLeft;
|
|
3655
|
-
const span = h.relativeFrom === "page" ? this.ctx.pageWidth : h.relativeFrom === "column" ? this.colWidth() : h.relativeFrom === "leftMargin" ? this.ctx.marginLeft : h.relativeFrom === "rightMargin" ? this.ctx.pageWidth - textRight : this.ctx.contentWidth;
|
|
3656
|
-
if (h.align === "center") return base + (span - widthPt) / 2;
|
|
3657
|
-
if (h.align === "right") return base + span - widthPt;
|
|
3658
|
-
return base + (h.offsetPt ?? 0);
|
|
3659
|
-
};
|
|
4023
|
+
floatX = (f, widthPt) => floatXIn(this.floatFrame(), f, widthPt);
|
|
3660
4024
|
/**
|
|
3661
4025
|
* The drawing's TOP in the y-up cursor frame. Paragraph/line-relative offsets
|
|
3662
4026
|
* hang off the anchoring paragraph's current position.
|
|
3663
4027
|
*/
|
|
3664
|
-
floatTopYUp = (f, heightPt = 0) =>
|
|
3665
|
-
const v = f.posV;
|
|
3666
|
-
if (!v) return this.cursorY;
|
|
3667
|
-
if (v.align !== void 0) {
|
|
3668
|
-
const page = v.relativeFrom === "page";
|
|
3669
|
-
const topYUp = page ? this.ctx.pageHeight : this.ctx.pageHeight - this.ctx.marginTop;
|
|
3670
|
-
const bottomYUp = page ? 0 : this.ctx.marginBottom;
|
|
3671
|
-
if (v.align === "top") return topYUp;
|
|
3672
|
-
if (v.align === "bottom") return bottomYUp + heightPt;
|
|
3673
|
-
return bottomYUp + (topYUp - bottomYUp + heightPt) / 2;
|
|
3674
|
-
}
|
|
3675
|
-
if (v.relativeFrom === "page" || v.relativeFrom === "topMargin") return this.ctx.pageHeight - (v.offsetPt ?? 0);
|
|
3676
|
-
if (v.relativeFrom === "bottomMargin") return this.ctx.marginBottom - (v.offsetPt ?? 0);
|
|
3677
|
-
if (v.relativeFrom === "margin") return this.ctx.pageHeight - this.ctx.marginTop - (v.offsetPt ?? 0);
|
|
3678
|
-
return this.cursorY - (v.offsetPt ?? 0);
|
|
3679
|
-
};
|
|
4028
|
+
floatTopYUp = (f, heightPt = 0) => floatTopYUpIn(this.floatFrame(), f, heightPt);
|
|
3680
4029
|
/**
|
|
3681
4030
|
* Tagged PDF: the stack of open list levels (for L/LI/LBody nesting). Cleared
|
|
3682
4031
|
* whenever a non-list-item block interrupts the run of list paragraphs.
|
|
@@ -3739,6 +4088,14 @@ var PageAssembler = class PageAssembler {
|
|
|
3739
4088
|
xOffset: 0,
|
|
3740
4089
|
blockedUntilYUp: e.bottomYUp
|
|
3741
4090
|
};
|
|
4091
|
+
if (leftRoom >= MIN_WRAP_WIDTH && rightRoom >= MIN_WRAP_WIDTH && e.wrapBothSides) return {
|
|
4092
|
+
width: leftRoom,
|
|
4093
|
+
xOffset: 0,
|
|
4094
|
+
pair: {
|
|
4095
|
+
width: rightRoom,
|
|
4096
|
+
xOffset: full - rightRoom
|
|
4097
|
+
}
|
|
4098
|
+
};
|
|
3742
4099
|
if (rightRoom >= leftRoom) return {
|
|
3743
4100
|
width: rightRoom,
|
|
3744
4101
|
xOffset: full - rightRoom
|
|
@@ -3770,6 +4127,7 @@ var PageAssembler = class PageAssembler {
|
|
|
3770
4127
|
continue;
|
|
3771
4128
|
}
|
|
3772
4129
|
widths.push(g.width);
|
|
4130
|
+
if (g.pair) widths.push(g.pair.width);
|
|
3773
4131
|
if (g.width < this.colWidth()) narrowed = true;
|
|
3774
4132
|
else if (narrowed) break;
|
|
3775
4133
|
y -= h0;
|
|
@@ -4083,9 +4441,11 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", n
|
|
|
4083
4441
|
if ((block.resolved.pageBreakBefore || block.pageBreakBefore) && asm.pageHasContent()) asm.flushPage();
|
|
4084
4442
|
asm.cursorY -= block.spacingBeforePt;
|
|
4085
4443
|
let pb = block;
|
|
4444
|
+
const colW = asm.colWidth();
|
|
4445
|
+
if (reflowParagraph && pb.source && Math.abs(colW - asm.builtWidth()) > .5) pb = reflowParagraph(pb.source, colW);
|
|
4086
4446
|
if (reflowParagraph && pb.source && asm.exclusions.length > 0) {
|
|
4087
|
-
const widths = asm.lineWidthsFor(
|
|
4088
|
-
if (widths) pb = reflowParagraph(pb.source,
|
|
4447
|
+
const widths = asm.lineWidthsFor(pb, asm.cursorY);
|
|
4448
|
+
if (widths) pb = reflowParagraph(pb.source, colW, widths);
|
|
4089
4449
|
}
|
|
4090
4450
|
const borderTopY = asm.cursorY;
|
|
4091
4451
|
const borderPage = asm.pages.length;
|
|
@@ -4103,6 +4463,7 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", n
|
|
|
4103
4463
|
if (lang && lang !== defaultLang) builder.node(structId).lang = lang;
|
|
4104
4464
|
}
|
|
4105
4465
|
let firstLineOfBlock = true;
|
|
4466
|
+
let pairPending;
|
|
4106
4467
|
for (const [lineIdx, line] of pb.lines.entries()) {
|
|
4107
4468
|
if (pb.columnBreakLines?.has(lineIdx) && asm.colHasContent()) asm.advanceColumn();
|
|
4108
4469
|
const h = computeLineHeight(line, pb.resolved);
|
|
@@ -4132,16 +4493,22 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", n
|
|
|
4132
4493
|
});
|
|
4133
4494
|
}
|
|
4134
4495
|
}
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
asm.
|
|
4496
|
+
const pairedNow = pairPending;
|
|
4497
|
+
pairPending = void 0;
|
|
4498
|
+
if (pairedNow === void 0) {
|
|
4499
|
+
for (let guard = 0; guard < 8 && asm.exclusions.length > 0; guard++) {
|
|
4500
|
+
const blocked = asm.lineGeometryAt(asm.cursorY, h).blockedUntilYUp;
|
|
4501
|
+
if (blocked === void 0 || blocked >= asm.cursorY) break;
|
|
4502
|
+
asm.cursorY = blocked;
|
|
4503
|
+
}
|
|
4504
|
+
asm.cursorY -= h;
|
|
4139
4505
|
}
|
|
4140
|
-
asm.cursorY -= h;
|
|
4141
4506
|
const indentLeft = pb.resolved.indentLeft + (line.firstLine ? pb.resolved.indentFirstLine : 0);
|
|
4142
4507
|
const offset = alignmentOffset(pb.resolved.alignment, line.contentWidthPt, line.availableWidthPt);
|
|
4143
4508
|
const baselineY = pt(asm.ctx.pageHeight - (asm.cursorY + lineBaselineOffset(line, pb.resolved)));
|
|
4144
|
-
const
|
|
4509
|
+
const geometry = asm.exclusions.length > 0 ? asm.lineGeometryAt(asm.cursorY + h, h) : void 0;
|
|
4510
|
+
const exclusionShift = pairedNow ?? geometry?.xOffset ?? 0;
|
|
4511
|
+
if (pairedNow === void 0 && geometry?.pair && Math.abs(line.availableWidthPt - geometry.width) < 1) pairPending = geometry.pair.xOffset;
|
|
4145
4512
|
const originX = asm.colLeft() + indentLeft + offset + exclusionShift;
|
|
4146
4513
|
if (markerLblId !== void 0 && line === firstLine) {
|
|
4147
4514
|
let k = 0;
|
|
@@ -4197,6 +4564,7 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", n
|
|
|
4197
4564
|
height: pt(ins?.heightPt ?? block.heightPt),
|
|
4198
4565
|
imageResourceName: block.resourceName,
|
|
4199
4566
|
...block.crop ? { crop: block.crop } : {},
|
|
4567
|
+
...block.wash ? { wash: block.wash } : {},
|
|
4200
4568
|
...block.rotationDeg ? { rotationDeg: block.rotationDeg } : {},
|
|
4201
4569
|
...block.flipH ? { flipH: true } : {},
|
|
4202
4570
|
...block.flipV ? { flipV: true } : {},
|
|
@@ -4236,7 +4604,7 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", n
|
|
|
4236
4604
|
asm.cursorY -= block.spacingAfterPt;
|
|
4237
4605
|
}
|
|
4238
4606
|
} else if (block.kind === "chart") {
|
|
4239
|
-
const figId = builder ? createFigure(builder, block.altText, "Chart") : void 0;
|
|
4607
|
+
const figId = builder ? createFigure(builder, block.altText, block.figureRole ?? "Chart") : void 0;
|
|
4240
4608
|
const emitChartAt = (x, bottomYUp, sink) => {
|
|
4241
4609
|
sink.push(...chartPageItems(block, x, bottomYUp, asm.ctx.pageHeight, figId));
|
|
4242
4610
|
};
|
|
@@ -4262,7 +4630,7 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", n
|
|
|
4262
4630
|
const sink = PageAssembler.zSink(block.float.behind ? asm.floatsBehind : asm.floatsFront, block.float.zOrder);
|
|
4263
4631
|
let rowY = fy;
|
|
4264
4632
|
for (const row of block.rows) {
|
|
4265
|
-
emitRowChunk(sink, row, fx, rowY, asm.ctx.pageHeight, colCount);
|
|
4633
|
+
emitRowChunk(sink, row, fx, rowY, asm.ctx.pageHeight, colCount, void 0, void 0, cellAnchorCtx(asm));
|
|
4266
4634
|
rowY -= row.heightPt;
|
|
4267
4635
|
}
|
|
4268
4636
|
if (block.float.wrap !== "none") asm.excludeFloat(block.float, fx, fy, block.totalWidthPt, block.heightPt);
|
|
@@ -4291,7 +4659,9 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", n
|
|
|
4291
4659
|
return b.create("P", cellNode).id;
|
|
4292
4660
|
});
|
|
4293
4661
|
}
|
|
4294
|
-
const
|
|
4662
|
+
const room = asm.cursorY - asm.bottomLimit();
|
|
4663
|
+
const page = asm.ctx.pageContentHeight;
|
|
4664
|
+
const chunks = !row.cantSplit && row.heightPt > room && asm.colHasContent() && room > 0 ? splitRowIntoChunks(row, room, page) : row.heightPt > page ? splitRowIntoChunks(row, page) : [row];
|
|
4295
4665
|
for (let ci = 0; ci < chunks.length; ci++) {
|
|
4296
4666
|
const chunk = chunks[ci];
|
|
4297
4667
|
const forcedBreak = ci === 0 && row.breakBefore && !isLeadingHeader && asm.current.length > 0;
|
|
@@ -4305,7 +4675,7 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", n
|
|
|
4305
4675
|
}
|
|
4306
4676
|
}
|
|
4307
4677
|
const mergedHeights = chunks.length === 1 && row.cells.some((c) => c.mergeRole === "start") ? row.cells.map((c) => c.mergeRole === "start" ? mergedBoxHeightPt(block.rows, ri, c.colStart, asm.cursorY - asm.bottomLimit()) : void 0) : void 0;
|
|
4308
|
-
emitRowChunk(asm.current, chunk, tableX, asm.cursorY, asm.ctx.pageHeight, colCount, cellStructIds, mergedHeights);
|
|
4678
|
+
emitRowChunk(asm.current, chunk, tableX, asm.cursorY, asm.ctx.pageHeight, colCount, cellStructIds, mergedHeights, cellAnchorCtx(asm));
|
|
4309
4679
|
asm.cursorY -= chunk.heightPt;
|
|
4310
4680
|
if (ci === chunks.length - 1 && ri < block.rows.length - 1) {
|
|
4311
4681
|
const next = block.rows[ri + 1];
|
|
@@ -4374,7 +4744,7 @@ function tableCellRowSpan(rows, startRowIdx, colStart) {
|
|
|
4374
4744
|
}
|
|
4375
4745
|
return span;
|
|
4376
4746
|
}
|
|
4377
|
-
function emitRowChunk(out, row, marginLeft, cursorY, pageHeight, colCount, cellStructIds, mergedHeights) {
|
|
4747
|
+
function emitRowChunk(out, row, marginLeft, cursorY, pageHeight, colCount, cellStructIds, mergedHeights, anchored) {
|
|
4378
4748
|
const rowTop = cursorY;
|
|
4379
4749
|
const rowBottom = cursorY - row.heightPt;
|
|
4380
4750
|
{
|
|
@@ -4553,7 +4923,7 @@ function emitRowChunk(out, row, marginLeft, cursorY, pageHeight, colCount, cellS
|
|
|
4553
4923
|
if (nt.afterLine !== n) continue;
|
|
4554
4924
|
for (const nrow of nt.block.rows) {
|
|
4555
4925
|
const nestedIds = structId !== void 0 ? nrow.cells.map(() => structId) : void 0;
|
|
4556
|
-
emitRowChunk(out, nrow, nestedX, textY, pageHeight, nt.block.colCount, nestedIds);
|
|
4926
|
+
emitRowChunk(out, nrow, nestedX, textY, pageHeight, nt.block.colCount, nestedIds, void 0, anchored);
|
|
4557
4927
|
textY -= nrow.heightPt;
|
|
4558
4928
|
}
|
|
4559
4929
|
}
|
|
@@ -4563,6 +4933,29 @@ function emitRowChunk(out, row, marginLeft, cursorY, pageHeight, colCount, cellS
|
|
|
4563
4933
|
textY -= cs.block.heightPt;
|
|
4564
4934
|
emitShapeItems(cs.block, nestedX + offset, textY, out, pageHeight, structId);
|
|
4565
4935
|
}
|
|
4936
|
+
for (const cf of cell.floats ?? []) {
|
|
4937
|
+
if (cf.afterLine !== n || !anchored) continue;
|
|
4938
|
+
const inner = cell.widthPt - cell.padLeftPt - cell.padRightPt;
|
|
4939
|
+
const cellTop = rowTop - cell.padTopPt;
|
|
4940
|
+
const cellBottom = rowTop - (mergedHeights?.[i] ?? row.heightPt) + cell.padBottomPt;
|
|
4941
|
+
const own = cf.block.float?.inCell !== false;
|
|
4942
|
+
emitCellFloat(cf, anchored, {
|
|
4943
|
+
...anchored.frame,
|
|
4944
|
+
...own ? {
|
|
4945
|
+
pageLeft: nestedX,
|
|
4946
|
+
pageWidth: inner,
|
|
4947
|
+
pageTopYUp: cellTop,
|
|
4948
|
+
pageBottomYUp: cellBottom,
|
|
4949
|
+
marginLeft: nestedX,
|
|
4950
|
+
contentWidth: inner,
|
|
4951
|
+
marginTopYUp: cellTop,
|
|
4952
|
+
marginBottomYUp: cellBottom
|
|
4953
|
+
} : {},
|
|
4954
|
+
columnLeft: nestedX,
|
|
4955
|
+
columnWidth: inner,
|
|
4956
|
+
anchorY: textY
|
|
4957
|
+
});
|
|
4958
|
+
}
|
|
4566
4959
|
};
|
|
4567
4960
|
for (const [lineIdx, line] of cell.lines.entries()) {
|
|
4568
4961
|
drawNestedBefore(lineIdx);
|
|
@@ -4588,10 +4981,13 @@ function emitRowChunk(out, row, marginLeft, cursorY, pageHeight, colCount, cellS
|
|
|
4588
4981
|
drawNestedBefore(cell.lines.length);
|
|
4589
4982
|
}
|
|
4590
4983
|
}
|
|
4591
|
-
function splitRowIntoChunks(row, capacity) {
|
|
4984
|
+
function splitRowIntoChunks(row, capacity, restCapacity = capacity) {
|
|
4592
4985
|
if (row.cells.some((c) => c.nestedTables && c.nestedTables.length > 0)) return [row];
|
|
4593
4986
|
const queues = row.cells.map((c) => ({
|
|
4594
|
-
remaining:
|
|
4987
|
+
remaining: c.lines.map((line, i) => ({
|
|
4988
|
+
line,
|
|
4989
|
+
gapPt: c.lineGaps?.get(i) ?? 0
|
|
4990
|
+
})),
|
|
4595
4991
|
template: c
|
|
4596
4992
|
}));
|
|
4597
4993
|
const anyHasLines = () => queues.some((q) => q.template.mergeRole === "middle" || q.template.mergeRole === "end" ? false : q.remaining.length > 0);
|
|
@@ -4609,23 +5005,31 @@ function splitRowIntoChunks(row, capacity) {
|
|
|
4609
5005
|
continue;
|
|
4610
5006
|
}
|
|
4611
5007
|
const padTop = isFirst ? tpl.padTopPt : 0;
|
|
4612
|
-
const capacityForLines = Math.max(0, capacity - padTop);
|
|
5008
|
+
const capacityForLines = Math.max(0, (isFirst ? capacity : restCapacity) - padTop);
|
|
4613
5009
|
const taken = [];
|
|
4614
5010
|
let takenHeight = 0;
|
|
4615
5011
|
while (q.remaining.length > 0) {
|
|
4616
5012
|
const next = q.remaining[0];
|
|
4617
|
-
const lh = computeLineHeight(next, next.resolved);
|
|
5013
|
+
const lh = computeLineHeight(next.line, next.line.resolved) + next.gapPt;
|
|
4618
5014
|
if (taken.length > 0 && takenHeight + lh > capacityForLines) break;
|
|
4619
5015
|
taken.push(next);
|
|
4620
5016
|
takenHeight += lh;
|
|
4621
5017
|
q.remaining.shift();
|
|
4622
5018
|
}
|
|
4623
5019
|
const cellHeight = padTop + takenHeight;
|
|
5020
|
+
const gaps = /* @__PURE__ */ new Map();
|
|
5021
|
+
taken.forEach((t, li) => {
|
|
5022
|
+
if (t.gapPt > 0) gaps.set(li, t.gapPt);
|
|
5023
|
+
});
|
|
5024
|
+
const { lineGaps: _g, shapes: _s, floats: _f, ...restOfCell } = tpl;
|
|
4624
5025
|
const chunkCell = {
|
|
4625
|
-
...
|
|
5026
|
+
...restOfCell,
|
|
5027
|
+
...isFirst && tpl.shapes ? { shapes: tpl.shapes } : {},
|
|
5028
|
+
...isFirst && tpl.floats ? { floats: tpl.floats } : {},
|
|
5029
|
+
...gaps.size > 0 ? { lineGaps: gaps } : {},
|
|
4626
5030
|
padTopPt: padTop,
|
|
4627
5031
|
padBottomPt: 0,
|
|
4628
|
-
lines: taken,
|
|
5032
|
+
lines: taken.map((t) => t.line),
|
|
4629
5033
|
contentHeightPt: takenHeight,
|
|
4630
5034
|
totalHeightPt: cellHeight
|
|
4631
5035
|
};
|
|
@@ -4664,7 +5068,8 @@ function splitRowIntoChunks(row, capacity) {
|
|
|
4664
5068
|
cells: chunkCells,
|
|
4665
5069
|
columnXOffsets: row.columnXOffsets,
|
|
4666
5070
|
rowIdx: row.rowIdx,
|
|
4667
|
-
rowCount: row.rowCount
|
|
5071
|
+
rowCount: row.rowCount,
|
|
5072
|
+
...row.isHeader ? { isHeader: true } : {}
|
|
4668
5073
|
});
|
|
4669
5074
|
isFirst = false;
|
|
4670
5075
|
}
|