reamkit 1.16.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.
Files changed (76) hide show
  1. package/dist/esm/core/bidi/segments.js +1 -2
  2. package/dist/esm/core/converter/project.js +5 -1
  3. package/dist/esm/core/document-model/index.d.ts +1 -1
  4. package/dist/esm/core/document-model/types.d.ts +526 -8
  5. package/dist/esm/core/drawingml/chart-geometry.d.ts +8 -12
  6. package/dist/esm/core/drawingml/chart-geometry.js +58 -9
  7. package/dist/esm/core/drawingml/chart-parser.js +44 -5
  8. package/dist/esm/core/drawingml/colors.d.ts +1 -1
  9. package/dist/esm/core/drawingml/colors.js +27 -1
  10. package/dist/esm/core/drawingml/preset-geometry.js +233 -0
  11. package/dist/esm/core/drawingml/shape-render.d.ts +12 -0
  12. package/dist/esm/core/drawingml/shape-render.js +116 -3
  13. package/dist/esm/core/drawingml/theme-parser.d.ts +10 -0
  14. package/dist/esm/core/drawingml/theme-parser.js +19 -1
  15. package/dist/esm/core/font/measure.d.ts +5 -0
  16. package/dist/esm/core/font/measure.js +21 -1
  17. package/dist/esm/core/images.d.ts +2 -2
  18. package/dist/esm/core/images.js +219 -0
  19. package/dist/esm/core/ir/flow.d.ts +23 -1
  20. package/dist/esm/core/lzw.d.ts +17 -0
  21. package/dist/esm/core/lzw.js +83 -0
  22. package/dist/esm/core/metafile/emf.d.ts +16 -0
  23. package/dist/esm/core/metafile/emf.js +635 -0
  24. package/dist/esm/core/metafile/picture.d.ts +106 -0
  25. package/dist/esm/core/metafile/picture.js +55 -0
  26. package/dist/esm/core/metafile/wmf.d.ts +9 -0
  27. package/dist/esm/core/metafile/wmf.js +371 -0
  28. package/dist/esm/core/numbering/apply.d.ts +5 -3
  29. package/dist/esm/core/numbering/apply.js +42 -11
  30. package/dist/esm/core/numbering/index.js +2 -0
  31. package/dist/esm/core/numbering/state.d.ts +13 -1
  32. package/dist/esm/core/numbering/state.js +256 -15
  33. package/dist/esm/core/po-helpers.js +16 -1
  34. package/dist/esm/core/style-cascade/resolver.js +66 -11
  35. package/dist/esm/core/style-cascade/table.js +35 -11
  36. package/dist/esm/core/style-cascade/types.d.ts +42 -1
  37. package/dist/esm/core/style-cascade/types.js +4 -0
  38. package/dist/esm/core/tiff.d.ts +20 -0
  39. package/dist/esm/core/tiff.js +339 -0
  40. package/dist/esm/core/vector.d.ts +22 -0
  41. package/dist/esm/excel/print-model.js +4 -2
  42. package/dist/esm/excel/sheet-to-flow.js +10 -8
  43. package/dist/esm/excel/worksheet-parser.js +1 -1
  44. package/dist/esm/html/html-writer.js +20 -5
  45. package/dist/esm/layout/page-doc.d.ts +107 -4
  46. package/dist/esm/layout/styled-layout.d.ts +44 -2
  47. package/dist/esm/layout/styled-layout.js +2330 -283
  48. package/dist/esm/pdf/shading.js +76 -6
  49. package/dist/esm/pdf/styled-page-emitter.js +294 -45
  50. package/dist/esm/pdf/vector-graphics.d.ts +29 -2
  51. package/dist/esm/pdf/vector-graphics.js +96 -12
  52. package/dist/esm/pdf-reader/image-decode.js +7 -75
  53. package/dist/esm/pptx/pptx-reader.js +1 -0
  54. package/dist/esm/pptx/slide-parser.d.ts +21 -4
  55. package/dist/esm/pptx/slide-parser.js +86 -23
  56. package/dist/esm/svg/svg-writer.js +2 -2
  57. package/dist/esm/word/document-parser.d.ts +96 -7
  58. package/dist/esm/word/document-parser.js +540 -116
  59. package/dist/esm/word/docx-reader.js +135 -43
  60. package/dist/esm/word/docx-writer.js +6 -1
  61. package/dist/esm/word/drawing-parser.d.ts +58 -5
  62. package/dist/esm/word/drawing-parser.js +1632 -63
  63. package/dist/esm/word/index.d.ts +4 -4
  64. package/dist/esm/word/numbering-parser.d.ts +2 -1
  65. package/dist/esm/word/numbering-parser.js +107 -21
  66. package/dist/esm/word/paragraph-properties.d.ts +11 -1
  67. package/dist/esm/word/paragraph-properties.js +219 -10
  68. package/dist/esm/word/run-properties.js +45 -1
  69. package/dist/esm/word/settings-parser.d.ts +24 -0
  70. package/dist/esm/word/settings-parser.js +31 -5
  71. package/dist/esm/word/shading.d.ts +11 -0
  72. package/dist/esm/word/shading.js +64 -0
  73. package/dist/esm/word/styles-parser.js +8 -2
  74. package/dist/esm/word/table-parser.d.ts +9 -1
  75. package/dist/esm/word/table-parser.js +182 -30
  76. package/package.json +1 -1
@@ -0,0 +1,106 @@
1
+ import { StrokeStyle, VectorPath } from '../vector.js';
2
+ /** A path drawn by the metafile: filled, stroked, or both. */
3
+ export interface PicturePath {
4
+ readonly kind: 'path';
5
+ readonly paths: ReadonlyArray<VectorPath>;
6
+ /** 6-hex, no leading `#`. Absent when the path is not filled. */
7
+ readonly fillColorHex?: string;
8
+ readonly stroke?: StrokeStyle;
9
+ }
10
+ /** A run of text the metafile puts at a point, in its own logical units. */
11
+ export interface PictureText {
12
+ readonly kind: 'text';
13
+ readonly text: string;
14
+ /** The reference point, in logical units (y DOWN, as the metafile has it). */
15
+ readonly x: number;
16
+ readonly y: number;
17
+ /** Which corner of the text the point names (MS-WMF §2.1.2.4 TextAlignment). */
18
+ readonly alignH: 'left' | 'center' | 'right';
19
+ /** Whether `y` is the text's TOP (the default) or its baseline. */
20
+ readonly alignBaseline: boolean;
21
+ /** Em size in logical units — the height the font was created with. */
22
+ readonly sizeLu: number;
23
+ readonly colorHex: string;
24
+ readonly fontFamily?: string;
25
+ readonly bold?: boolean;
26
+ readonly italic?: boolean;
27
+ /** Tenths of a degree, counter-clockwise — the font's own escapement. */
28
+ readonly escapement?: number;
29
+ }
30
+ /** A bitmap the metafile blits into a rectangle of its own logical frame. */
31
+ export interface PictureImage {
32
+ readonly kind: 'image';
33
+ /** The destination rectangle in logical units (y down). */
34
+ readonly x: number;
35
+ readonly y: number;
36
+ readonly width: number;
37
+ readonly height: number;
38
+ /** The bitmap as a standalone file (PNG), ready for the resource store. */
39
+ readonly png: Uint8Array;
40
+ }
41
+ export type PicturePrim = PicturePath | PictureText | PictureImage;
42
+ /**
43
+ * One metafile, read: its primitives and the logical box they are drawn in.
44
+ * Coordinates are the metafile's own, with y running DOWN; the caller maps the
45
+ * box onto the picture's frame.
46
+ */
47
+ export interface MetaPicture {
48
+ readonly left: number;
49
+ readonly top: number;
50
+ readonly width: number;
51
+ readonly height: number;
52
+ readonly prims: ReadonlyArray<PicturePrim>;
53
+ /** Records the reader knew of but did not draw, for a loss note. */
54
+ readonly skipped: ReadonlyArray<string>;
55
+ }
56
+ /** A pen, a brush and a font, as the device context holds them. */
57
+ export interface MetaPen {
58
+ readonly kind: 'pen';
59
+ readonly colorHex: string;
60
+ readonly widthLu: number;
61
+ readonly style: 'solid' | 'dash' | 'dot' | 'dashdot' | 'dashdotdot' | 'none';
62
+ }
63
+ export interface MetaBrush {
64
+ readonly kind: 'brush';
65
+ readonly colorHex: string;
66
+ /** `null` for BS_HOLLOW/BS_NULL — a brush that paints nothing. */
67
+ readonly hollow: boolean;
68
+ }
69
+ export interface MetaFont {
70
+ readonly kind: 'font';
71
+ readonly heightLu: number;
72
+ readonly family?: string;
73
+ readonly bold?: boolean;
74
+ readonly italic?: boolean;
75
+ readonly escapement?: number;
76
+ }
77
+ export type MetaObject = MetaPen | MetaBrush | MetaFont;
78
+ /** The device context: everything a record draws THROUGH. */
79
+ export interface DeviceContext {
80
+ pen: MetaPen;
81
+ brush: MetaBrush;
82
+ font?: MetaFont;
83
+ textColorHex: string;
84
+ bkColorHex: string;
85
+ /** MS-WMF §2.1.1.9 — TRANSPARENT leaves the background of text unpainted. */
86
+ bkOpaque: boolean;
87
+ alignH: 'left' | 'center' | 'right';
88
+ alignBaseline: boolean;
89
+ fillRule: 'nonzero' | 'evenodd';
90
+ x: number;
91
+ y: number;
92
+ /** The world→page transform, as `[a, b, c, d, e, f]`. */
93
+ transform: readonly [number, number, number, number, number, number];
94
+ }
95
+ export declare const DEFAULT_PEN: MetaPen;
96
+ export declare const DEFAULT_BRUSH: MetaBrush;
97
+ /** A device context in its documented initial state (MS-WMF §3.1.5). */
98
+ export declare function newDeviceContext(): DeviceContext;
99
+ export declare function cloneDc(dc: DeviceContext): DeviceContext;
100
+ /** A COLORREF (`0x00bbggrr`) as the 6-hex this codebase's colours use. */
101
+ export declare function colorRef(v: number): string;
102
+ /** Apply the world transform to a point. */
103
+ export declare function applyTransform(t: DeviceContext['transform'], x: number, y: number): {
104
+ x: number;
105
+ y: number;
106
+ };
@@ -0,0 +1,55 @@
1
+ //#region src/core/metafile/picture.ts
2
+ var DEFAULT_PEN = {
3
+ kind: "pen",
4
+ colorHex: "000000",
5
+ widthLu: 1,
6
+ style: "solid"
7
+ };
8
+ var DEFAULT_BRUSH = {
9
+ kind: "brush",
10
+ colorHex: "FFFFFF",
11
+ hollow: false
12
+ };
13
+ /** A device context in its documented initial state (MS-WMF §3.1.5). */
14
+ function newDeviceContext() {
15
+ return {
16
+ pen: DEFAULT_PEN,
17
+ brush: DEFAULT_BRUSH,
18
+ textColorHex: "000000",
19
+ bkColorHex: "FFFFFF",
20
+ bkOpaque: true,
21
+ alignH: "left",
22
+ alignBaseline: false,
23
+ fillRule: "evenodd",
24
+ x: 0,
25
+ y: 0,
26
+ transform: [
27
+ 1,
28
+ 0,
29
+ 0,
30
+ 1,
31
+ 0,
32
+ 0
33
+ ]
34
+ };
35
+ }
36
+ function cloneDc(dc) {
37
+ return { ...dc };
38
+ }
39
+ /** A COLORREF (`0x00bbggrr`) as the 6-hex this codebase's colours use. */
40
+ function colorRef(v) {
41
+ return [
42
+ v & 255,
43
+ v >>> 8 & 255,
44
+ v >>> 16 & 255
45
+ ].map((c) => c.toString(16).padStart(2, "0")).join("").toUpperCase();
46
+ }
47
+ /** Apply the world transform to a point. */
48
+ function applyTransform(t, x, y) {
49
+ return {
50
+ x: t[0] * x + t[2] * y + t[4],
51
+ y: t[1] * x + t[3] * y + t[5]
52
+ };
53
+ }
54
+ //#endregion
55
+ export { applyTransform, cloneDc, colorRef, newDeviceContext };
@@ -0,0 +1,9 @@
1
+ import { MetaPicture } from './picture.js';
2
+ /** Whether the bytes open with a WMF header — placeable or bare (§2.3.2.2). */
3
+ export declare function isWmf(bytes: Uint8Array): boolean;
4
+ /**
5
+ * Read a WMF into its primitives.
6
+ *
7
+ * @throws Error when the bytes are not a WMF.
8
+ */
9
+ export declare function readWmf(bytes: Uint8Array): MetaPicture;
@@ -0,0 +1,371 @@
1
+ import { PathBuilder } from "../vector.js";
2
+ import { cloneDc, colorRef, newDeviceContext } from "./picture.js";
3
+ import { ellipseSegments } from "./emf.js";
4
+ //#region src/core/metafile/wmf.ts
5
+ var PLACEABLE_KEY = 2596720087;
6
+ /** Whether the bytes open with a WMF header — placeable or bare (§2.3.2.2). */
7
+ function isWmf(bytes) {
8
+ if (bytes.length < 18) return false;
9
+ const v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
10
+ if (v.getUint32(0, true) === PLACEABLE_KEY) return true;
11
+ const type = v.getUint16(0, true);
12
+ const headerWords = v.getUint16(2, true);
13
+ return (type === 1 || type === 2) && headerWords === 9;
14
+ }
15
+ var RECORD_NAMES = new Map([
16
+ [2368, "bitmap"],
17
+ [2881, "bitmap"],
18
+ [3907, "bitmap"],
19
+ [2338, "pie"],
20
+ [2096, "chord"],
21
+ [2071, "arc"],
22
+ [1049, "flood fill"],
23
+ [1352, "flood fill"],
24
+ [247, "palette"],
25
+ [1574, "escape"],
26
+ [765, "region"],
27
+ [552, "region fill"],
28
+ [1065, "region frame"],
29
+ [298, "region invert"],
30
+ [299, "region paint"]
31
+ ]);
32
+ /**
33
+ * Read a WMF into its primitives.
34
+ *
35
+ * @throws Error when the bytes are not a WMF.
36
+ */
37
+ function readWmf(bytes) {
38
+ if (!isWmf(bytes)) throw new Error("WMF: not a Windows metafile");
39
+ const v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
40
+ const placeable = v.getUint32(0, true) === PLACEABLE_KEY;
41
+ const frame = placeable ? {
42
+ left: v.getInt16(6, true),
43
+ top: v.getInt16(8, true),
44
+ right: v.getInt16(10, true),
45
+ bottom: v.getInt16(12, true)
46
+ } : void 0;
47
+ const prims = [];
48
+ const skipped = /* @__PURE__ */ new Set();
49
+ const objects = [];
50
+ const put = (obj) => {
51
+ const free = objects.indexOf(void 0);
52
+ if (free >= 0) objects[free] = obj;
53
+ else objects.push(obj);
54
+ };
55
+ const stack = [];
56
+ let dc = newDeviceContext();
57
+ let win = {
58
+ x: 0,
59
+ y: 0,
60
+ cx: 0,
61
+ cy: 0
62
+ };
63
+ const strokeOf = () => {
64
+ if (dc.pen.style === "none") return void 0;
65
+ const w = Math.max(1, dc.pen.widthLu);
66
+ return {
67
+ colorHex: dc.pen.colorHex,
68
+ widthPt: w,
69
+ ...dc.pen.style === "solid" ? {} : { dash: dc.pen.style === "dot" ? [w, 2 * w] : [4 * w, 3 * w] }
70
+ };
71
+ };
72
+ const paint = (segments, fill, stroke) => {
73
+ if (segments.length === 0) return;
74
+ const path = {
75
+ segments,
76
+ fillRule: dc.fillRule
77
+ };
78
+ const st = stroke ? strokeOf() : void 0;
79
+ const fillHex = fill && !dc.brush.hollow ? dc.brush.colorHex : void 0;
80
+ if (fillHex === void 0 && !st) return;
81
+ prims.push({
82
+ kind: "path",
83
+ paths: [path],
84
+ ...fillHex !== void 0 ? { fillColorHex: fillHex } : {},
85
+ ...st ? { stroke: st } : {}
86
+ });
87
+ };
88
+ const rectSegments = (l, t, r, b) => new PathBuilder().moveTo(l, t).lineTo(r, t).lineTo(r, b).lineTo(l, b).close().build().segments;
89
+ let off = placeable ? 22 : 0;
90
+ off += 18;
91
+ let guard = 0;
92
+ while (off + 6 <= bytes.length && guard++ < 5e5) {
93
+ const size = v.getUint32(off, true);
94
+ const fn = v.getUint16(off + 4, true);
95
+ if (size < 3 || off + size * 2 > bytes.length) break;
96
+ const p = (i) => v.getInt16(off + 6 + i * 2, true);
97
+ const pu = (i) => v.getUint16(off + 6 + i * 2, true);
98
+ const p32 = (i) => v.getUint32(off + 6 + i * 2, true);
99
+ switch (fn) {
100
+ case 0:
101
+ off = bytes.length;
102
+ continue;
103
+ case 523:
104
+ win = {
105
+ ...win,
106
+ x: p(1),
107
+ y: p(0)
108
+ };
109
+ break;
110
+ case 524:
111
+ win = {
112
+ ...win,
113
+ cx: p(1),
114
+ cy: p(0)
115
+ };
116
+ break;
117
+ case 30:
118
+ stack.push(cloneDc(dc));
119
+ break;
120
+ case 295:
121
+ {
122
+ const back = Math.max(1, -p(0));
123
+ for (let i = 0; i < back && stack.length > 0; i++) dc = stack.pop();
124
+ }
125
+ break;
126
+ case 301:
127
+ {
128
+ const obj = objects[pu(0)];
129
+ if (obj?.kind === "pen") dc.pen = obj;
130
+ else if (obj?.kind === "brush") dc.brush = obj;
131
+ else if (obj?.kind === "font") dc.font = obj;
132
+ }
133
+ break;
134
+ case 496:
135
+ objects[pu(0)] = void 0;
136
+ break;
137
+ case 762:
138
+ put({
139
+ kind: "pen",
140
+ style: penStyle(pu(0)),
141
+ widthLu: p(1),
142
+ colorHex: colorRef(p32(3))
143
+ });
144
+ break;
145
+ case 764:
146
+ put({
147
+ kind: "brush",
148
+ colorHex: colorRef(p32(1)),
149
+ hollow: pu(0) === 1
150
+ });
151
+ break;
152
+ case 763:
153
+ put(readLogFont(v, bytes, off + 6));
154
+ break;
155
+ case 258:
156
+ dc.bkOpaque = pu(0) === 2;
157
+ break;
158
+ case 262:
159
+ dc.fillRule = pu(0) === 2 ? "nonzero" : "evenodd";
160
+ break;
161
+ case 302:
162
+ {
163
+ const f = pu(0);
164
+ dc.alignH = (f & 6) === 6 ? "center" : (f & 2) === 2 ? "right" : "left";
165
+ dc.alignBaseline = (f & 24) === 24;
166
+ }
167
+ break;
168
+ case 521:
169
+ dc.textColorHex = colorRef(p32(0));
170
+ break;
171
+ case 513:
172
+ dc.bkColorHex = colorRef(p32(0));
173
+ break;
174
+ case 532:
175
+ dc.x = p(1);
176
+ dc.y = p(0);
177
+ break;
178
+ case 531:
179
+ {
180
+ const x = p(1);
181
+ const y = p(0);
182
+ paint([{
183
+ op: "move",
184
+ x: dc.x,
185
+ y: dc.y
186
+ }, {
187
+ op: "line",
188
+ x,
189
+ y
190
+ }], false, true);
191
+ dc.x = x;
192
+ dc.y = y;
193
+ }
194
+ break;
195
+ case 1051:
196
+ paint(rectSegments(p(3), p(2), p(1), p(0)), true, true);
197
+ break;
198
+ case 1048:
199
+ paint(ellipseSegments((x, y) => ({
200
+ x,
201
+ y
202
+ }), p(3), p(2), p(1), p(0)), true, true);
203
+ break;
204
+ case 1564:
205
+ paint(rectSegments(p(5), p(4), p(3), p(2)), true, true);
206
+ break;
207
+ case 1565:
208
+ {
209
+ const rop = p32(0);
210
+ const h = p(2);
211
+ const w = p(3);
212
+ const y = p(4);
213
+ const x = p(5);
214
+ const hex = rop === 66 ? "000000" : rop === 16711778 ? "FFFFFF" : void 0;
215
+ const brush = dc.brush;
216
+ if (hex !== void 0) dc.brush = {
217
+ kind: "brush",
218
+ colorHex: hex,
219
+ hollow: false
220
+ };
221
+ paint(rectSegments(x, y, x + w, y + h), true, false);
222
+ dc.brush = brush;
223
+ }
224
+ break;
225
+ case 804:
226
+ case 805:
227
+ {
228
+ const count = pu(0);
229
+ const pts = readPoints(v, off + 8, count);
230
+ const closed = fn === 804;
231
+ paint(polySegments(pts, closed), closed, true);
232
+ }
233
+ break;
234
+ case 1336:
235
+ {
236
+ const polys = pu(0);
237
+ const counts = [];
238
+ for (let i = 0; i < polys; i++) counts.push(v.getUint16(off + 8 + i * 2, true));
239
+ let at = off + 8 + polys * 2;
240
+ const segs = [];
241
+ for (const c of counts) {
242
+ segs.push(...polySegments(readPoints(v, at, c), true));
243
+ at += c * 4;
244
+ }
245
+ paint(segs, true, true);
246
+ }
247
+ break;
248
+ case 1313:
249
+ {
250
+ const count = pu(0);
251
+ const text = readString(bytes, off + 8, count, false);
252
+ const words = count + 1 >> 1;
253
+ pushText(prims, dc, text, p(1 + words + 1), p(1 + words));
254
+ }
255
+ break;
256
+ case 2610:
257
+ {
258
+ const y = p(0);
259
+ const x = p(1);
260
+ const count = pu(2);
261
+ const hasRect = (pu(3) & 6) !== 0;
262
+ const text = readString(bytes, off + 6 + (4 + (hasRect ? 4 : 0)) * 2, count, false);
263
+ pushText(prims, dc, text, x, y);
264
+ }
265
+ break;
266
+ default:
267
+ {
268
+ const name = RECORD_NAMES.get(fn);
269
+ if (name) skipped.add(name);
270
+ }
271
+ break;
272
+ }
273
+ off += size * 2;
274
+ }
275
+ const box = frame ?? {
276
+ left: win.x,
277
+ top: win.y,
278
+ right: win.x + (win.cx || 1e3),
279
+ bottom: win.y + (win.cy || 1e3)
280
+ };
281
+ return {
282
+ left: box.left,
283
+ top: box.top,
284
+ width: Math.max(1, Math.abs(box.right - box.left)),
285
+ height: Math.max(1, Math.abs(box.bottom - box.top)),
286
+ prims,
287
+ skipped: [...skipped]
288
+ };
289
+ }
290
+ function pushText(prims, dc, text, x, y) {
291
+ if (text.trim() === "") return;
292
+ prims.push({
293
+ kind: "text",
294
+ text,
295
+ x,
296
+ y,
297
+ alignH: dc.alignH,
298
+ alignBaseline: dc.alignBaseline,
299
+ sizeLu: Math.abs(dc.font?.heightLu ?? 12),
300
+ colorHex: dc.textColorHex,
301
+ ...dc.font?.family ? { fontFamily: dc.font.family } : {},
302
+ ...dc.font?.bold ? { bold: true } : {},
303
+ ...dc.font?.italic ? { italic: true } : {},
304
+ ...dc.font?.escapement ? { escapement: dc.font.escapement } : {}
305
+ });
306
+ }
307
+ function penStyle(style) {
308
+ switch (style & 15) {
309
+ case 1: return "dash";
310
+ case 2: return "dot";
311
+ case 3: return "dashdot";
312
+ case 4: return "dashdotdot";
313
+ case 5: return "none";
314
+ default: return "solid";
315
+ }
316
+ }
317
+ function readLogFont(v, bytes, at) {
318
+ const height = v.getInt16(at, true);
319
+ const escapement = v.getInt16(at + 4, true);
320
+ const weight = v.getInt16(at + 8, true);
321
+ const italic = bytes[at + 10] !== 0;
322
+ const face = readString(bytes, at + 18, 32, false).replace(/\0.*$/u, "");
323
+ return {
324
+ kind: "font",
325
+ heightLu: height,
326
+ ...face ? { family: face } : {},
327
+ ...weight >= 600 ? { bold: true } : {},
328
+ ...italic ? { italic: true } : {},
329
+ ...escapement ? { escapement } : {}
330
+ };
331
+ }
332
+ function readString(bytes, at, count, wide) {
333
+ let out = "";
334
+ for (let i = 0; i < count; i++) {
335
+ const o = at + (wide ? i * 2 : i);
336
+ if (o >= bytes.length) break;
337
+ const code = wide ? bytes[o] | (bytes[o + 1] ?? 0) << 8 : bytes[o];
338
+ if (code === 0) break;
339
+ out += String.fromCharCode(code);
340
+ }
341
+ return out;
342
+ }
343
+ function readPoints(v, at, count) {
344
+ const out = [];
345
+ for (let i = 0; i < count; i++) {
346
+ const o = at + i * 4;
347
+ if (o + 4 > v.byteLength) break;
348
+ out.push({
349
+ x: v.getInt16(o, true),
350
+ y: v.getInt16(o + 2, true)
351
+ });
352
+ }
353
+ return out;
354
+ }
355
+ function polySegments(pts, closed) {
356
+ if (pts.length === 0) return [];
357
+ const segs = [{
358
+ op: "move",
359
+ x: pts[0].x,
360
+ y: pts[0].y
361
+ }];
362
+ for (let i = 1; i < pts.length; i++) segs.push({
363
+ op: "line",
364
+ x: pts[i].x,
365
+ y: pts[i].y
366
+ });
367
+ if (closed) segs.push({ op: "close" });
368
+ return segs;
369
+ }
370
+ //#endregion
371
+ export { isWmf, readWmf };
@@ -1,4 +1,4 @@
1
- import { BodyElement, Numbering } from '../document-model/index.js';
1
+ import { BodyElement, Numbering, StyleSheet } from '../document-model/index.js';
2
2
  /**
3
3
  * Apply list numbering to a body as a FlowDoc transform (§17.9): walk the
4
4
  * elements (recursing into table cells), advancing list counters and prepending
@@ -8,9 +8,11 @@ import { BodyElement, Numbering } from '../document-model/index.js';
8
8
  *
9
9
  * @param body The body elements to transform.
10
10
  * @param numbering The parsed numbering definitions, or `undefined`.
11
+ * @param styles The style sheet, for a paragraph whose numbering comes from
12
+ * its STYLE (§17.9.24) rather than its own `w:numPr`.
11
13
  * @returns A new body with markers materialized.
12
14
  */
13
- export declare function applyNumbering(body: ReadonlyArray<BodyElement>, numbering: Numbering | undefined): Array<BodyElement>;
15
+ export declare function applyNumbering(body: ReadonlyArray<BodyElement>, numbering: Numbering | undefined, styles?: StyleSheet): Array<BodyElement>;
14
16
  /**
15
17
  * Apply {@link applyNumbering} to each header/footer band independently (each
16
18
  * gets its own counter state), keyed as in the input map.
@@ -19,4 +21,4 @@ export declare function applyNumbering(body: ReadonlyArray<BodyElement>, numberi
19
21
  * @param numbering The parsed numbering definitions, or `undefined`.
20
22
  * @returns A new map with numbering applied (empty when `hf` is empty/absent).
21
23
  */
22
- export declare function applyNumberingToHeadersFooters(hf: ReadonlyMap<string, ReadonlyArray<BodyElement>> | undefined, numbering: Numbering | undefined): ReadonlyMap<string, ReadonlyArray<BodyElement>>;
24
+ export declare function applyNumberingToHeadersFooters(hf: ReadonlyMap<string, ReadonlyArray<BodyElement>> | undefined, numbering: Numbering | undefined, styles?: StyleSheet): ReadonlyMap<string, ReadonlyArray<BodyElement>>;
@@ -1,5 +1,13 @@
1
- import { NumberingState } from "./state.js";
1
+ import { pt } from "../ir/units.js";
2
+ import { NumberingState, effectiveAbstract } from "./state.js";
3
+ import { resolveParagraphProperties } from "../style-cascade/resolver.js";
4
+ import "../style-cascade/index.js";
2
5
  //#region src/core/numbering/apply.ts
6
+ /** The height a picture bullet takes when neither the level nor the paragraph
7
+ * mark states a font size — Word's own default text size. */
8
+ var DEFAULT_BULLET_HEIGHT_PT = 11;
9
+ /** SOFT HYPHEN, which a `w:lvlText` may spell a dash bullet with (§17.9.11). */
10
+ var SOFT_HYPHEN = "­";
3
11
  /**
4
12
  * Apply list numbering to a body as a FlowDoc transform (§17.9): walk the
5
13
  * elements (recursing into table cells), advancing list counters and prepending
@@ -9,28 +17,51 @@ import { NumberingState } from "./state.js";
9
17
  *
10
18
  * @param body The body elements to transform.
11
19
  * @param numbering The parsed numbering definitions, or `undefined`.
20
+ * @param styles The style sheet, for a paragraph whose numbering comes from
21
+ * its STYLE (§17.9.24) rather than its own `w:numPr`.
12
22
  * @returns A new body with markers materialized.
13
23
  */
14
- function applyNumbering(body, numbering) {
24
+ function applyNumbering(body, numbering, styles) {
15
25
  if (!numbering || numbering.abstractNums.size === 0) return body.map((b) => b);
16
26
  const state = new NumberingState();
27
+ const numberingOf = (p) => p.properties.numbering ?? (styles ? resolveParagraphProperties(p.properties, styles).numbering : void 0);
17
28
  const transformParagraph = (p) => {
18
- const ref = p.properties.numbering;
29
+ if (p.properties.sectionBreak === true && p.runs.every((r) => r.text === "")) return p;
30
+ const ref = numberingOf(p);
19
31
  if (!ref) return p;
20
32
  const marker = state.resolveMarker(numbering, ref);
21
33
  if (marker === null) return p;
22
34
  const instance = numbering.numInstances.get(ref.numId);
23
- const level = (instance ? numbering.abstractNums.get(instance.abstractNumId) : void 0)?.levels.get(ref.ilvl);
24
- const markerRun = {
25
- text: `${marker}\t`,
26
- properties: level?.runProperties ?? {},
35
+ const level = (instance ? effectiveAbstract(numbering, instance) : void 0)?.levels.get(ref.ilvl);
36
+ const pic = level?.picBullet;
37
+ const bulletCapPt = level?.runProperties.fontSizePt ?? p.properties.runProperties?.fontSizePt ?? DEFAULT_BULLET_HEIGHT_PT;
38
+ const bulletScale = pic ? Math.min(1, bulletCapPt / Math.max(1, pic.heightPt)) : 1;
39
+ const markerRuns = pic ? [{
40
+ text: "",
41
+ properties: {},
42
+ listMarker: true,
43
+ inlineImage: {
44
+ resource: pic.resource,
45
+ width: pt(pic.widthPt * bulletScale),
46
+ height: pt(pic.heightPt * bulletScale)
47
+ }
48
+ }, {
49
+ text: " ",
50
+ properties: {},
27
51
  listMarker: true
28
- };
52
+ }] : [{
53
+ text: `${marker.replaceAll(SOFT_HYPHEN, "-")}\t`,
54
+ properties: {
55
+ ...p.properties.runProperties,
56
+ ...level?.runProperties
57
+ },
58
+ listMarker: true
59
+ }];
29
60
  const newProps = mergeIndentFromLevel(p.properties, level?.paragraphProperties);
30
61
  return {
31
62
  ...p,
32
63
  properties: newProps,
33
- runs: [markerRun, ...p.runs]
64
+ runs: [...markerRuns, ...p.runs]
34
65
  };
35
66
  };
36
67
  const visit = (el) => {
@@ -73,11 +104,11 @@ function mergeIndentFromLevel(paragraphProps, levelProps) {
73
104
  * @param numbering The parsed numbering definitions, or `undefined`.
74
105
  * @returns A new map with numbering applied (empty when `hf` is empty/absent).
75
106
  */
76
- function applyNumberingToHeadersFooters(hf, numbering) {
107
+ function applyNumberingToHeadersFooters(hf, numbering, styles) {
77
108
  if (!hf || hf.size === 0) return /* @__PURE__ */ new Map();
78
109
  if (!numbering || numbering.abstractNums.size === 0) return hf;
79
110
  const out = /* @__PURE__ */ new Map();
80
- for (const [key, value] of hf) out.set(key, applyNumbering(value, numbering));
111
+ for (const [key, value] of hf) out.set(key, applyNumbering(value, numbering, styles));
81
112
  return out;
82
113
  }
83
114
  //#endregion
@@ -0,0 +1,2 @@
1
+ import "./state.js";
2
+ import "./apply.js";
@@ -1,4 +1,15 @@
1
- import { AbstractNumbering, Numbering, NumberingLevel, NumberingReference } from '../document-model/index.js';
1
+ import { AbstractNumbering, Numbering, NumberingInstance, NumberingLevel, NumberingReference } from '../document-model/index.js';
2
+ /**
3
+ * §17.9.27 — the levels an INSTANCE actually numbers by: its abstract
4
+ * definition's, with any `w:lvlOverride/w:lvl` shadowing them. Cached per
5
+ * instance, since every list paragraph asks for it.
6
+ *
7
+ * @param numbering The parsed numbering definitions.
8
+ * @param instance The `w:num` the paragraph refers to.
9
+ * @returns The effective abstract numbering, or `undefined` when the instance
10
+ * names one that is not there.
11
+ */
12
+ export declare function effectiveAbstract(numbering: Numbering, instance: NumberingInstance): AbstractNumbering | undefined;
2
13
  /**
3
14
  * Mutable list-counter state for one numbering scope (e.g. a body or a single
4
15
  * header/footer band). Tracks a counter per list per level and advances them as
@@ -6,6 +17,7 @@ import { AbstractNumbering, Numbering, NumberingLevel, NumberingReference } from
6
17
  */
7
18
  export declare class NumberingState {
8
19
  private readonly counters;
20
+ private readonly restarted;
9
21
  /**
10
22
  * Advance the counter for `ref` (resetting deeper levels) and format its
11
23
  * marker text. The first hit at a level seeds it from the level's `start`;