reamkit 1.30.0 → 1.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -24
- package/dist/esm/core/converter/project.js +3 -1
- package/dist/esm/core/crypto/offcrypto.js +1 -1
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +63 -0
- package/dist/esm/core/font/index.d.ts +2 -0
- package/dist/esm/core/font/ttf-build.d.ts +113 -0
- package/dist/esm/core/font/ttf-build.js +1224 -0
- package/dist/esm/core/font/ttf-subset.d.ts +19 -0
- package/dist/esm/core/font/ttf-subset.js +14 -1
- package/dist/esm/core/fonts/provider.d.ts +17 -0
- package/dist/esm/core/fonts/provider.js +27 -2
- package/dist/esm/core/fonts/remote-fonts.js +8 -1
- package/dist/esm/core/ir/flow.d.ts +71 -1
- package/dist/esm/core/numbering/index.d.ts +1 -1
- package/dist/esm/core/numbering/state.d.ts +11 -1
- package/dist/esm/core/numbering/state.js +10 -1
- package/dist/esm/core/style-cascade/resolver.js +35 -4
- package/dist/esm/core/style-cascade/types.d.ts +19 -1
- package/dist/esm/core/style-cascade/types.js +3 -0
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/layout/page-doc.d.ts +10 -3
- package/dist/esm/layout/styled-layout.d.ts +48 -7
- package/dist/esm/layout/styled-layout.js +881 -119
- package/dist/esm/layout/turned-section.d.ts +38 -0
- package/dist/esm/layout/turned-section.js +193 -0
- package/dist/esm/pdf/styled-page-emitter.js +78 -2
- package/dist/esm/pdf-reader/cff-outline.d.ts +27 -0
- package/dist/esm/pdf-reader/cff-outline.js +169 -21
- package/dist/esm/pdf-reader/content.d.ts +53 -0
- package/dist/esm/pdf-reader/content.js +9 -1
- package/dist/esm/pdf-reader/display.d.ts +36 -0
- package/dist/esm/pdf-reader/display.js +66 -1
- package/dist/esm/pdf-reader/document.js +5 -1
- package/dist/esm/pdf-reader/embedded-fonts.d.ts +2 -1
- package/dist/esm/pdf-reader/embedded-fonts.js +32 -2
- package/dist/esm/pdf-reader/encodings.d.ts +8 -0
- package/dist/esm/pdf-reader/encodings.js +25 -3
- package/dist/esm/pdf-reader/face-outlines.d.ts +78 -0
- package/dist/esm/pdf-reader/face-outlines.js +362 -0
- package/dist/esm/pdf-reader/figures.d.ts +52 -0
- package/dist/esm/pdf-reader/figures.js +433 -0
- package/dist/esm/pdf-reader/flow-build.d.ts +131 -5
- package/dist/esm/pdf-reader/flow-build.js +345 -26
- package/dist/esm/pdf-reader/font.js +321 -36
- package/dist/esm/pdf-reader/glyf-outline.d.ts +33 -0
- package/dist/esm/pdf-reader/glyf-outline.js +135 -1
- package/dist/esm/pdf-reader/glyph-names.js +154 -1
- package/dist/esm/pdf-reader/layout.d.ts +93 -0
- package/dist/esm/pdf-reader/layout.js +1703 -214
- package/dist/esm/pdf-reader/page-numbers.d.ts +53 -0
- package/dist/esm/pdf-reader/page-numbers.js +167 -0
- package/dist/esm/pdf-reader/tagged.js +182 -23
- package/dist/esm/pdf-reader/text.d.ts +6 -3
- package/dist/esm/pdf-reader/text.js +98 -9
- package/dist/esm/pdf-reader/type1-outline.d.ts +11 -0
- package/dist/esm/pdf-reader/type1-outline.js +63 -8
- package/dist/esm/pdf-reader/vector.js +71 -1
- package/dist/esm/word/doc/doc-reader.js +6 -2
- package/dist/esm/word/doc/doc-text.d.ts +6 -0
- package/dist/esm/word/doc/doc-text.js +19 -1
- package/dist/esm/word/document-parser.d.ts +2 -2
- package/dist/esm/word/document-parser.js +11 -1
- package/dist/esm/word/docx-reader.js +5 -3
- package/dist/esm/word/docx-writer.js +207 -21
- package/dist/esm/word/drawing-parser.d.ts +5 -3
- package/dist/esm/word/drawing-parser.js +49 -8
- package/dist/esm/word/font-embed.d.ts +30 -0
- package/dist/esm/word/font-embed.js +173 -0
- package/dist/esm/word/font-table.d.ts +10 -0
- package/dist/esm/word/font-table.js +13 -1
- package/dist/esm/word/index.js +1 -1
- package/dist/esm/word/numbering-parser.d.ts +3 -1
- package/dist/esm/word/numbering-parser.js +2 -1
- package/dist/esm/word/paragraph-properties.d.ts +7 -6
- package/dist/esm/word/paragraph-properties.js +14 -2
- package/dist/esm/word/run-properties.js +26 -0
- package/package.json +8 -3
|
@@ -22,3 +22,22 @@ export declare function subsetTtf(parsed: ParsedTtf, usedGids: Iterable<number>)
|
|
|
22
22
|
* @returns The closed set of glyph ids.
|
|
23
23
|
*/
|
|
24
24
|
export declare function glyphClosure(parsed: ParsedTtf, usedGids: Iterable<number>): Set<number>;
|
|
25
|
+
/**
|
|
26
|
+
* The sfnt table directory's binary-search fields for `numTables` tables.
|
|
27
|
+
*
|
|
28
|
+
* @param numTables How many tables the font holds.
|
|
29
|
+
* @returns `searchRange`, `entrySelector` and `rangeShift`, as the header states them.
|
|
30
|
+
*/
|
|
31
|
+
export declare function directoryGeometry(numTables: number): {
|
|
32
|
+
searchRange: number;
|
|
33
|
+
entrySelector: number;
|
|
34
|
+
rangeShift: number;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* An sfnt table checksum: the sum of its big-endian 32-bit words, the last one
|
|
38
|
+
* padded with zeros.
|
|
39
|
+
*
|
|
40
|
+
* @param data The table's bytes (or the whole font's).
|
|
41
|
+
* @returns The checksum, as an unsigned 32-bit value.
|
|
42
|
+
*/
|
|
43
|
+
export declare function paddedChecksum(data: Uint8Array): number;
|
|
@@ -193,6 +193,12 @@ function assembleSubsetTtf(parsed, newGlyf, newLoca) {
|
|
|
193
193
|
outView.setUint32(head.offset + HEAD_CHECKSUM_ADJUSTMENT_OFFSET, adjustment, false);
|
|
194
194
|
return out;
|
|
195
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* The sfnt table directory's binary-search fields for `numTables` tables.
|
|
198
|
+
*
|
|
199
|
+
* @param numTables How many tables the font holds.
|
|
200
|
+
* @returns `searchRange`, `entrySelector` and `rangeShift`, as the header states them.
|
|
201
|
+
*/
|
|
196
202
|
function directoryGeometry(numTables) {
|
|
197
203
|
let entrySelector = 0;
|
|
198
204
|
let pow2 = 1;
|
|
@@ -208,6 +214,13 @@ function directoryGeometry(numTables) {
|
|
|
208
214
|
rangeShift
|
|
209
215
|
};
|
|
210
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* An sfnt table checksum: the sum of its big-endian 32-bit words, the last one
|
|
219
|
+
* padded with zeros.
|
|
220
|
+
*
|
|
221
|
+
* @param data The table's bytes (or the whole font's).
|
|
222
|
+
* @returns The checksum, as an unsigned 32-bit value.
|
|
223
|
+
*/
|
|
211
224
|
function paddedChecksum(data) {
|
|
212
225
|
let sum = 0;
|
|
213
226
|
const len = data.length;
|
|
@@ -244,4 +257,4 @@ function concatBytes(parts) {
|
|
|
244
257
|
return out;
|
|
245
258
|
}
|
|
246
259
|
//#endregion
|
|
247
|
-
export { glyphClosure, subsetTtf };
|
|
260
|
+
export { directoryGeometry, glyphClosure, paddedChecksum, subsetTtf };
|
|
@@ -45,6 +45,23 @@ export declare function embeddedDocFontProvider(embedded: ReadonlyMap<string, Fo
|
|
|
45
45
|
* Open CDN substitutes (Arimo / Tinos / Cousine / Carlito / Caladea — the
|
|
46
46
|
* LibreOffice metric-compatible mapping).
|
|
47
47
|
* Always answers; the chain reports it as a substitution.
|
|
48
|
+
*
|
|
49
|
+
* A family's set is shared by every request for it, those made while the
|
|
50
|
+
* download is in flight included, and a whole set is downloaded once per
|
|
51
|
+
* provider. A set whose regular face cannot be downloaded rejects `resolve`
|
|
52
|
+
* with {@link fetchFontSet}'s error rather than answering {@link NO_FONT}: this
|
|
53
|
+
* is the chain's last resort, and a chain that answers none sends the
|
|
54
|
+
* conversion to the auto-download path, which records no substitution. The
|
|
55
|
+
* failed set is not kept, so the next request asks the network again.
|
|
56
|
+
*
|
|
57
|
+
* Nor is a set kept that came without a bold or italic face. The requests that
|
|
58
|
+
* waited on it fall back to the faces it has, and the next request assembles
|
|
59
|
+
* the set anew: a face the network lost is asked for again, and one the CDN
|
|
60
|
+
* answered with an HTTP error is not, since the download cache beneath
|
|
61
|
+
* {@link fetchFontSet} remembers it as missing.
|
|
62
|
+
*
|
|
63
|
+
* @param options An injectable `fetch` (defaults to the global one).
|
|
64
|
+
* @returns The `'remote'` provider.
|
|
48
65
|
*/
|
|
49
66
|
export declare function remoteFontProvider(options?: {
|
|
50
67
|
readonly fetch?: FetchLike;
|
|
@@ -66,6 +66,23 @@ function embeddedDocFontProvider(embedded) {
|
|
|
66
66
|
* Open CDN substitutes (Arimo / Tinos / Cousine / Carlito / Caladea — the
|
|
67
67
|
* LibreOffice metric-compatible mapping).
|
|
68
68
|
* Always answers; the chain reports it as a substitution.
|
|
69
|
+
*
|
|
70
|
+
* A family's set is shared by every request for it, those made while the
|
|
71
|
+
* download is in flight included, and a whole set is downloaded once per
|
|
72
|
+
* provider. A set whose regular face cannot be downloaded rejects `resolve`
|
|
73
|
+
* with {@link fetchFontSet}'s error rather than answering {@link NO_FONT}: this
|
|
74
|
+
* is the chain's last resort, and a chain that answers none sends the
|
|
75
|
+
* conversion to the auto-download path, which records no substitution. The
|
|
76
|
+
* failed set is not kept, so the next request asks the network again.
|
|
77
|
+
*
|
|
78
|
+
* Nor is a set kept that came without a bold or italic face. The requests that
|
|
79
|
+
* waited on it fall back to the faces it has, and the next request assembles
|
|
80
|
+
* the set anew: a face the network lost is asked for again, and one the CDN
|
|
81
|
+
* answered with an HTTP error is not, since the download cache beneath
|
|
82
|
+
* {@link fetchFontSet} remembers it as missing.
|
|
83
|
+
*
|
|
84
|
+
* @param options An injectable `fetch` (defaults to the global one).
|
|
85
|
+
* @returns The `'remote'` provider.
|
|
69
86
|
*/
|
|
70
87
|
function remoteFontProvider(options = {}) {
|
|
71
88
|
const cache = /* @__PURE__ */ new Map();
|
|
@@ -81,10 +98,18 @@ function remoteFontProvider(options = {}) {
|
|
|
81
98
|
});
|
|
82
99
|
cache.set(family, set);
|
|
83
100
|
}
|
|
84
|
-
|
|
101
|
+
let fonts;
|
|
102
|
+
try {
|
|
103
|
+
fonts = await set;
|
|
104
|
+
} catch (error) {
|
|
105
|
+
if (cache.get(family) === set) cache.delete(family);
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
if ((fonts.bold === void 0 || fonts.italic === void 0 || fonts.boldItalic === void 0) && cache.get(family) === set) cache.delete(family);
|
|
109
|
+
const picked = pickVariant((x) => fonts[x] !== void 0, req.bold, req.italic) ?? "regular";
|
|
85
110
|
return {
|
|
86
111
|
kind: "bytes",
|
|
87
|
-
bytes: fonts[
|
|
112
|
+
bytes: fonts[picked] ?? fonts.regular,
|
|
88
113
|
faceName: family,
|
|
89
114
|
providerId: "remote"
|
|
90
115
|
};
|
|
@@ -330,7 +330,14 @@ async function fetchTtf(url, fetchImpl, required) {
|
|
|
330
330
|
})();
|
|
331
331
|
cache.set(url, pending);
|
|
332
332
|
}
|
|
333
|
-
|
|
333
|
+
let result;
|
|
334
|
+
try {
|
|
335
|
+
result = await pending;
|
|
336
|
+
} catch (cause) {
|
|
337
|
+
if (cache.get(url) === pending) cache.delete(url);
|
|
338
|
+
if (!required) return void 0;
|
|
339
|
+
throw new Error(`Failed to download font from ${url}`, { cause });
|
|
340
|
+
}
|
|
334
341
|
if (!result && required) {
|
|
335
342
|
cache.delete(url);
|
|
336
343
|
throw new Error(`Failed to download font from ${url}`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BodyElement, Chart, Comment, DocumentInfo, Numbering, Section, SectionProperties, ShapeFill, StyleSheet } from '../document-model/index.js';
|
|
2
|
-
import { FontRegistry } from '../font/index.js';
|
|
2
|
+
import { FontRegistry, GlyphSeg } from '../font/index.js';
|
|
3
3
|
import { ResourceStore } from './resources.js';
|
|
4
4
|
/**
|
|
5
5
|
* A face's family as a word processor names it (ECMA-376 §17.8.3.9 `w:font`).
|
|
@@ -10,6 +10,55 @@ export interface FaceFamily {
|
|
|
10
10
|
/** §17.8.3.10 `w:family` — the kind of face, for a reader that has to substitute. */
|
|
11
11
|
readonly generic: 'roman' | 'swiss' | 'modern';
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* The outlines a face drew a document's characters with — what a writer needs
|
|
15
|
+
* to EMBED the face, so a reader that lacks it sets the text in the face the
|
|
16
|
+
* source was set in instead of a substitute (ECMA-376 §17.8.1).
|
|
17
|
+
*/
|
|
18
|
+
export interface FaceOutlines {
|
|
19
|
+
/** Each character (one code point) the document shows in the face → its glyph. */
|
|
20
|
+
readonly glyphs: ReadonlyMap<string, FaceGlyph>;
|
|
21
|
+
/**
|
|
22
|
+
* The pairs the source KERNED the face by: two characters → the adjustment
|
|
23
|
+
* to the first one's advance, in thousandths of an em (negative tightens).
|
|
24
|
+
*/
|
|
25
|
+
readonly kerning?: ReadonlyMap<string, number>;
|
|
26
|
+
/**
|
|
27
|
+
* The ligatures the source drew in the face: the letters one glyph stands
|
|
28
|
+
* for ("fi", "ffl") → that glyph.
|
|
29
|
+
*/
|
|
30
|
+
readonly ligatures?: ReadonlyMap<string, FaceGlyph>;
|
|
31
|
+
/**
|
|
32
|
+
* OS/2 `fsType` — the embedding the face's licence allows, as its program
|
|
33
|
+
* states it; absent where the program states nothing.
|
|
34
|
+
*/
|
|
35
|
+
readonly fsType?: number;
|
|
36
|
+
/** The style the face IS, which is the slot a family embeds it in. */
|
|
37
|
+
readonly bold: boolean;
|
|
38
|
+
readonly italic: boolean;
|
|
39
|
+
/** The program's own name for the face, without a subset tag. */
|
|
40
|
+
readonly postScriptName: string;
|
|
41
|
+
/**
|
|
42
|
+
* The line to set the face in, above and below the baseline, in thousandths
|
|
43
|
+
* of an em — `descent` negative. A reader that reconstructs a page gives the
|
|
44
|
+
* line it measured the page against, so a paragraph set in the face's single
|
|
45
|
+
* spacing lands where the page put it.
|
|
46
|
+
*/
|
|
47
|
+
readonly ascent: number;
|
|
48
|
+
readonly descent: number;
|
|
49
|
+
readonly capHeight?: number;
|
|
50
|
+
readonly xHeight?: number;
|
|
51
|
+
/** Degrees counterclockwise from the vertical; a face slanted right is negative. */
|
|
52
|
+
readonly italicAngle: number;
|
|
53
|
+
readonly fixedPitch: boolean;
|
|
54
|
+
}
|
|
55
|
+
/** One glyph of a {@link FaceOutlines}: what it draws and how far it advances. */
|
|
56
|
+
export interface FaceGlyph {
|
|
57
|
+
/** Its contours in a one-unit em, y up, filled by the nonzero rule; empty when blank. */
|
|
58
|
+
readonly outline: ReadonlyArray<GlyphSeg>;
|
|
59
|
+
/** How far the pen moves after it, in thousandths of an em. */
|
|
60
|
+
readonly advance: number;
|
|
61
|
+
}
|
|
13
62
|
/**
|
|
14
63
|
* The semantic IR tree (ir-design §5): everything a reader extracts from the
|
|
15
64
|
* document bytes, format-neutrally — the flow `body` plus its document-scoped
|
|
@@ -59,6 +108,11 @@ export interface FlowDoc {
|
|
|
59
108
|
* to another program names the family, which is the name that program knows.
|
|
60
109
|
*/
|
|
61
110
|
readonly faceFamilies?: ReadonlyMap<string, FaceFamily>;
|
|
111
|
+
/**
|
|
112
|
+
* The outlines of the faces a run names, keyed as {@link faceFamilies} is —
|
|
113
|
+
* for a writer that embeds them (see {@link FaceOutlines}).
|
|
114
|
+
*/
|
|
115
|
+
readonly faceOutlines?: ReadonlyMap<string, FaceOutlines>;
|
|
62
116
|
/** Document metadata from docProps/core.xml. */
|
|
63
117
|
readonly info?: DocumentInfo;
|
|
64
118
|
/** Document natural language hint (BCP-47), e.g. for tagged-PDF /Lang. */
|
|
@@ -85,4 +139,20 @@ export interface FlowDoc {
|
|
|
85
139
|
* @w:gutter` reserves belongs to the TOP margin rather than the left.
|
|
86
140
|
*/
|
|
87
141
|
readonly gutterAtTop?: boolean;
|
|
142
|
+
/**
|
|
143
|
+
* [MS-DOCX] `w:compatSetting` `compatibilityMode` — the version of Word
|
|
144
|
+
* whose layout the document asks for: 15 is Word 2013's, which every Word
|
|
145
|
+
* since sets a new document by. Word opens a document that states none in
|
|
146
|
+
* Compatibility Mode, and forms there none of the OpenType ligatures its
|
|
147
|
+
* faces carry.
|
|
148
|
+
*/
|
|
149
|
+
readonly compatibilityMode?: number;
|
|
150
|
+
/**
|
|
151
|
+
* The application whose rules the document is set by: `'word'` for one Word
|
|
152
|
+
* sets — lines as tall as the faces on them make them (§17.3.1.33), table
|
|
153
|
+
* rows as tall as their borders make them (§17.4.38); see the layout's
|
|
154
|
+
* `TypesetBy`. Absent, the layout's flat 1.2× lines and borders that take no
|
|
155
|
+
* room.
|
|
156
|
+
*/
|
|
157
|
+
readonly typesetBy?: 'word';
|
|
88
158
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { NumberingState, formatLevelMarker } from './state.js';
|
|
1
|
+
export { NumberingState, formatCounter, formatLevelMarker } from './state.js';
|
|
2
2
|
export { applyNumbering, applyNumberingToHeadersFooters } from './apply.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AbstractNumbering, Numbering, NumberingInstance, NumberingLevel, NumberingReference } from '../document-model/index.js';
|
|
1
|
+
import { AbstractNumbering, Numbering, NumberingFormat, NumberingInstance, NumberingLevel, NumberingReference } from '../document-model/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* §17.9.27 — the levels an INSTANCE actually numbers by: its abstract
|
|
4
4
|
* definition's, with any `w:lvlOverride/w:lvl` shadowing them. Cached per
|
|
@@ -31,3 +31,13 @@ export declare class NumberingState {
|
|
|
31
31
|
resolveMarker(numbering: Numbering, ref: NumberingReference): string | null;
|
|
32
32
|
}
|
|
33
33
|
export declare function formatLevelMarker(abstractNum: AbstractNumbering, currentLevel: NumberingLevel, counters: ReadonlyArray<number>): string;
|
|
34
|
+
/**
|
|
35
|
+
* A counter in the numerals a §17.18.59 format names: `lowerRoman` 4 is "iv".
|
|
36
|
+
* A format with no numeral for the number — a letter or a roman zero — gives
|
|
37
|
+
* the empty string.
|
|
38
|
+
*
|
|
39
|
+
* @param format The number format.
|
|
40
|
+
* @param n The counter's value.
|
|
41
|
+
* @returns The counter as that format writes it.
|
|
42
|
+
*/
|
|
43
|
+
export declare function formatCounter(format: NumberingFormat, n: number): string;
|
|
@@ -77,6 +77,15 @@ function formatLevelMarker(abstractNum, currentLevel, counters) {
|
|
|
77
77
|
return formatCounter(currentLevel.isLegal === true && lvlIdx !== currentLevel.ilvl ? "decimal" : level?.format ?? "decimal", counter);
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* A counter in the numerals a §17.18.59 format names: `lowerRoman` 4 is "iv".
|
|
82
|
+
* A format with no numeral for the number — a letter or a roman zero — gives
|
|
83
|
+
* the empty string.
|
|
84
|
+
*
|
|
85
|
+
* @param format The number format.
|
|
86
|
+
* @param n The counter's value.
|
|
87
|
+
* @returns The counter as that format writes it.
|
|
88
|
+
*/
|
|
80
89
|
function formatCounter(format, n) {
|
|
81
90
|
if (n < 0) return "";
|
|
82
91
|
switch (format) {
|
|
@@ -336,4 +345,4 @@ function normalizeBullet(lvlText) {
|
|
|
336
345
|
return lvlText;
|
|
337
346
|
}
|
|
338
347
|
//#endregion
|
|
339
|
-
export { NumberingState, effectiveAbstract, formatLevelMarker };
|
|
348
|
+
export { NumberingState, effectiveAbstract, formatCounter, formatLevelMarker };
|
|
@@ -137,7 +137,10 @@ function mergeRun(base, override) {
|
|
|
137
137
|
...lang !== void 0 ? { lang } : {},
|
|
138
138
|
...(override.shadingColorHex ?? base.shadingColorHex) !== void 0 ? { shadingColorHex: override.shadingColorHex ?? base.shadingColorHex } : {},
|
|
139
139
|
...(override.textOutline ?? base.textOutline) !== void 0 ? { textOutline: override.textOutline ?? base.textOutline } : {},
|
|
140
|
-
...(override.letterSpacingPt ?? base.letterSpacingPt) !== void 0 ? { letterSpacingPt: override.letterSpacingPt ?? base.letterSpacingPt } : {}
|
|
140
|
+
...(override.letterSpacingPt ?? base.letterSpacingPt) !== void 0 ? { letterSpacingPt: override.letterSpacingPt ?? base.letterSpacingPt } : {},
|
|
141
|
+
...(override.widthScale ?? base.widthScale) !== void 0 ? { widthScale: override.widthScale ?? base.widthScale } : {},
|
|
142
|
+
...(override.kerningMinPt ?? base.kerningMinPt) !== void 0 ? { kerningMinPt: override.kerningMinPt ?? base.kerningMinPt } : {},
|
|
143
|
+
...(override.ligatures ?? base.ligatures) !== void 0 ? { ligatures: override.ligatures ?? base.ligatures } : {}
|
|
141
144
|
};
|
|
142
145
|
}
|
|
143
146
|
function mergePar(base, override) {
|
|
@@ -152,6 +155,7 @@ function mergePar(base, override) {
|
|
|
152
155
|
const sectionBreak = override.sectionBreak ?? base.sectionBreak;
|
|
153
156
|
const textDirection = override.textDirection ?? base.textDirection;
|
|
154
157
|
const snapToGrid = override.snapToGrid ?? base.snapToGrid;
|
|
158
|
+
const beforeAuto = override.spacingBeforeAuto ?? (override.spacingBefore === void 0 ? base.spacingBeforeAuto : void 0);
|
|
155
159
|
return {
|
|
156
160
|
alignment: override.alignment ?? base.alignment,
|
|
157
161
|
spacingBefore: override.spacingBeforeAuto ?? override.spacingBefore ?? base.spacingBefore,
|
|
@@ -162,6 +166,9 @@ function mergePar(base, override) {
|
|
|
162
166
|
indentRight: override.indentRight ?? base.indentRight,
|
|
163
167
|
indentFirstLine: override.indentFirstLine ?? base.indentFirstLine,
|
|
164
168
|
pageBreakBefore: override.pageBreakBefore ?? base.pageBreakBefore,
|
|
169
|
+
keepNext: override.keepNext ?? base.keepNext,
|
|
170
|
+
keepLines: override.keepLines ?? base.keepLines,
|
|
171
|
+
widowControl: override.widowControl ?? base.widowControl,
|
|
165
172
|
contextualSpacing: override.contextualSpacing ?? base.contextualSpacing,
|
|
166
173
|
tabs: override.tabs ?? base.tabs,
|
|
167
174
|
bidi: override.bidi ?? base.bidi,
|
|
@@ -174,7 +181,8 @@ function mergePar(base, override) {
|
|
|
174
181
|
...frame !== void 0 ? { frame } : {},
|
|
175
182
|
...sectionBreak !== void 0 ? { sectionBreak } : {},
|
|
176
183
|
...textDirection !== void 0 ? { textDirection } : {},
|
|
177
|
-
...snapToGrid !== void 0 ? { snapToGrid } : {}
|
|
184
|
+
...snapToGrid !== void 0 ? { snapToGrid } : {},
|
|
185
|
+
...beforeAuto !== void 0 ? { spacingBeforeAuto: beforeAuto } : {}
|
|
178
186
|
};
|
|
179
187
|
}
|
|
180
188
|
function mergeRunPartial(base, override) {
|
|
@@ -222,6 +230,7 @@ function primeParagraphFixpoint(para) {
|
|
|
222
230
|
}
|
|
223
231
|
if (!bySheet.has(para)) bySheet.set(para, para);
|
|
224
232
|
}
|
|
233
|
+
var markCascadeCache = /* @__PURE__ */ new WeakMap();
|
|
225
234
|
/**
|
|
226
235
|
* Resolve the style cascade across an entire body so the tree carries final
|
|
227
236
|
* effective run/paragraph properties (FlowDoc transform, ir-design stage 6).
|
|
@@ -229,9 +238,25 @@ function primeParagraphFixpoint(para) {
|
|
|
229
238
|
* resolving again over {@link EMPTY_STYLE_SHEET} is the identity.
|
|
230
239
|
*/
|
|
231
240
|
function resolveBodyStyles(body, sheet) {
|
|
241
|
+
let bySheet = markCascadeCache.get(sheet);
|
|
242
|
+
if (!bySheet) {
|
|
243
|
+
bySheet = /* @__PURE__ */ new WeakMap();
|
|
244
|
+
markCascadeCache.set(sheet, bySheet);
|
|
245
|
+
}
|
|
246
|
+
const marks = bySheet;
|
|
247
|
+
const withResolvedMark = (pp) => {
|
|
248
|
+
const hit = marks.get(pp);
|
|
249
|
+
if (hit) return hit;
|
|
250
|
+
const resolved = {
|
|
251
|
+
...resolveParagraphProperties(pp, sheet),
|
|
252
|
+
runProperties: resolveRunProperties(pp.runProperties ?? {}, pp, sheet)
|
|
253
|
+
};
|
|
254
|
+
marks.set(pp, resolved);
|
|
255
|
+
return resolved;
|
|
256
|
+
};
|
|
232
257
|
const visitParagraph = (p) => {
|
|
233
258
|
for (const r of p.runs) r.properties = resolveRunProperties(r.properties, p.properties, sheet);
|
|
234
|
-
p.properties =
|
|
259
|
+
p.properties = withResolvedMark(p.properties);
|
|
235
260
|
primeParagraphFixpoint(p.properties);
|
|
236
261
|
for (const r of p.runs) primeResolvedFixpoint(r.properties, p.properties);
|
|
237
262
|
};
|
|
@@ -244,7 +269,13 @@ function resolveBodyStyles(body, sheet) {
|
|
|
244
269
|
for (const member of sh.children ?? []) shapeText(member.shape);
|
|
245
270
|
};
|
|
246
271
|
shapeText(el.shape);
|
|
247
|
-
|
|
272
|
+
standsOn(el.shape);
|
|
273
|
+
} else if (el.kind === "image") standsOn(el.image);
|
|
274
|
+
else standsOn(el.chart);
|
|
275
|
+
};
|
|
276
|
+
const standsOn = (block) => {
|
|
277
|
+
if (block.float !== void 0) return;
|
|
278
|
+
block.paragraphProperties = withResolvedMark(block.paragraphProperties);
|
|
248
279
|
};
|
|
249
280
|
for (const el of body) visit(el);
|
|
250
281
|
return body;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Alignment, CellBorders, CellShading, FontFamilyMap, FrameProperties, NumberingReference, RunProperties, TabStop, TextOutline, UnderlineStyle, VerticalAlign } from '../document-model/index.js';
|
|
1
|
+
import { Alignment, CellBorders, CellShading, FontFamilyMap, FrameProperties, Ligatures, NumberingReference, RunProperties, TabStop, TextOutline, UnderlineStyle, VerticalAlign } from '../document-model/index.js';
|
|
2
2
|
import { Pt } from '../ir/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* A run's fully-resolved properties: every field required because the cascade
|
|
@@ -30,6 +30,12 @@ export interface ResolvedRunProperties {
|
|
|
30
30
|
readonly shadingColorHex?: string;
|
|
31
31
|
/** §17.3.2.35 — extra space between the run's characters, in points. */
|
|
32
32
|
readonly letterSpacingPt?: Pt;
|
|
33
|
+
/** §17.3.2.43 — the share of its own width each character is set at. */
|
|
34
|
+
readonly widthScale?: number;
|
|
35
|
+
/** §17.3.2.19 — the run is kerned at this size and above (0: not at all). */
|
|
36
|
+
readonly kerningMinPt?: Pt;
|
|
37
|
+
/** [MS-DOCX] `w14:ligatures` — the face's ligatures the run is set with. */
|
|
38
|
+
readonly ligatures?: Ligatures;
|
|
33
39
|
/** §21.1.2.3.9 — a line drawn round the glyphs themselves. */
|
|
34
40
|
readonly textOutline?: TextOutline;
|
|
35
41
|
}
|
|
@@ -40,6 +46,12 @@ export interface ResolvedRunProperties {
|
|
|
40
46
|
export interface ResolvedParagraphProperties {
|
|
41
47
|
readonly alignment: Alignment;
|
|
42
48
|
readonly spacingBefore: Pt;
|
|
49
|
+
/**
|
|
50
|
+
* §17.3.1.3 `w:beforeAutospacing` — present, and equal to
|
|
51
|
+
* {@link spacingBefore}, where the space before is the automatic (HTML) one:
|
|
52
|
+
* Word does not give it to the document's first paragraph.
|
|
53
|
+
*/
|
|
54
|
+
readonly spacingBeforeAuto?: Pt;
|
|
43
55
|
readonly spacingAfter: Pt;
|
|
44
56
|
readonly spacingLine: Pt;
|
|
45
57
|
readonly spacingLineRule: 'auto' | 'exact' | 'atLeast';
|
|
@@ -47,6 +59,12 @@ export interface ResolvedParagraphProperties {
|
|
|
47
59
|
readonly indentRight: Pt;
|
|
48
60
|
readonly indentFirstLine: Pt;
|
|
49
61
|
readonly pageBreakBefore: boolean;
|
|
62
|
+
/** §17.3.1.14 — on the same page as the start of the next paragraph. */
|
|
63
|
+
readonly keepNext: boolean;
|
|
64
|
+
/** §17.3.1.15 — every line on one page. */
|
|
65
|
+
readonly keepLines: boolean;
|
|
66
|
+
/** §17.3.1.44 — no first or last line left alone on a page. */
|
|
67
|
+
readonly widowControl: boolean;
|
|
50
68
|
/** §17.3.1.9 — drop the space between this paragraph and a same-styled neighbour. */
|
|
51
69
|
readonly contextualSpacing: boolean;
|
|
52
70
|
/** §17.3.1.37 — the paragraph's tab stops, in ascending position order. */
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -29,12 +29,12 @@ export { signPdf } from './pdf/index.js';
|
|
|
29
29
|
export type { SignaturePlaceholder, SignerCredentials, SignatureOptions } from './pdf/index.js';
|
|
30
30
|
export type { PdfEncryptOptions, PdfPermissions } from './pdf/index.js';
|
|
31
31
|
export { FontRegistry, parseTtf, subsetTtf } from './core/font/index.js';
|
|
32
|
-
export type { FontBytesByVariant, FontVariant, ParsedTtf } from './core/font/index.js';
|
|
32
|
+
export type { FontBytesByVariant, FontVariant, GlyphSeg, ParsedTtf } from './core/font/index.js';
|
|
33
33
|
export { getHyphenator, createLanguageHyphenator, createHyphenator, splitPatternBundle, } from './core/hyphenation/index.js';
|
|
34
34
|
export type { Hyphenator, HyphenatorOptions, SupportedLanguage } from './core/hyphenation/index.js';
|
|
35
35
|
export type { Pt, ResourceId, Feature, KnownFeature, Loss, LossReport, LossSeverity, NativeBag, } from './core/ir/index.js';
|
|
36
36
|
export { FEATURES, ResourceStore, ConversionLossError, formatLoss, pt, twipsToPt, halfPtToPt, eighthPtToPt, emuToPt, pxToPt, inchToPt, mmToPt, } from './core/ir/index.js';
|
|
37
|
-
export type { FaceFamily, FlowDoc } from './core/ir/flow.js';
|
|
37
|
+
export type { FaceFamily, FaceGlyph, FaceOutlines, FlowDoc } from './core/ir/flow.js';
|
|
38
38
|
export type { DocumentReader, DocumentWriter, ReadOptions, ReadResult, WriteOptions, WriteResult, } from './core/ir/adapters.js';
|
|
39
39
|
export { docxReader, readDocx } from './word/docx-reader.js';
|
|
40
40
|
export { xlsxReader, readXlsx } from './excel/xlsx-reader.js';
|
|
@@ -198,12 +198,19 @@ export interface Line {
|
|
|
198
198
|
readonly mathAscentPt?: number;
|
|
199
199
|
readonly mathDescentPt?: number;
|
|
200
200
|
/**
|
|
201
|
-
*
|
|
202
|
-
* the line
|
|
203
|
-
* `
|
|
201
|
+
* §17.3.1.33 — the line's single height and descent (Pt) from the faces on
|
|
202
|
+
* it, pictures included, where the line model reads faces (a Word document,
|
|
203
|
+
* or a renderer-compat `layoutProfile`). Absent under the flat 1.2×/0.2
|
|
204
|
+
* model.
|
|
204
205
|
*/
|
|
205
206
|
readonly metricHeightPt?: number;
|
|
206
207
|
readonly metricDescentPt?: number;
|
|
208
|
+
/**
|
|
209
|
+
* The line of its TEXT alone (the paragraph mark's, on a line with none):
|
|
210
|
+
* what a spacing of more lines adds per line, where a picture on the line
|
|
211
|
+
* adds nothing.
|
|
212
|
+
*/
|
|
213
|
+
readonly metricTextHeightPt?: number;
|
|
207
214
|
}
|
|
208
215
|
/** An image bound into a {@link LaidOutDocument}: its resource name plus the decoded/validated bytes. */
|
|
209
216
|
/**
|
|
@@ -7,6 +7,7 @@ import { LaidOutDocument, PageItem } from './page-doc.js';
|
|
|
7
7
|
import { AttachedFile } from '../pdf/embedded-file.js';
|
|
8
8
|
import { SignaturePlaceholder } from '../pdf/signature.js';
|
|
9
9
|
import { PdfEncryptOptions } from '../pdf/encryption.js';
|
|
10
|
+
import { Sheet } from './turned-section.js';
|
|
10
11
|
import { StructTreeBuilder } from '../pdf/struct-tree.js';
|
|
11
12
|
/**
|
|
12
13
|
* PDF/A conformance string: part 1 (ISO 19005-1, PDF 1.4) / 2 (ISO 19005-2) / 3
|
|
@@ -24,15 +25,27 @@ export interface PdfAProfile {
|
|
|
24
25
|
readonly version: '1.4' | '1.7';
|
|
25
26
|
}
|
|
26
27
|
/**
|
|
27
|
-
* E-PARITY: renderer-compatibility profile
|
|
28
|
-
*
|
|
29
|
-
* `'
|
|
30
|
-
*
|
|
28
|
+
* E-PARITY: renderer-compatibility profile — how lines are measured, broken
|
|
29
|
+
* and stacked.
|
|
30
|
+
* `'ream'` (default) — kerned measuring, Knuth-Plass breaking, and the line
|
|
31
|
+
* height the document asks for (see {@link TypesetBy}).
|
|
32
|
+
* `'word'` — kern-free measuring, first-fit breaking, and lines as Word sets
|
|
33
|
+
* them whatever the document.
|
|
34
|
+
* `'libreoffice'` — first-fit breaking, lines from the face in hand: hhea, or
|
|
35
|
+
* the OS/2 typo line when USE_TYPO_METRICS is set.
|
|
31
36
|
*
|
|
32
|
-
* Opt-in: a profile emulates that renderer
|
|
33
|
-
* parity. It never changes default (`'ream'`) output.
|
|
37
|
+
* Opt-in: a profile emulates that renderer for closer visual parity.
|
|
34
38
|
*/
|
|
35
39
|
export type LayoutProfile = 'ream' | 'word' | 'libreoffice';
|
|
40
|
+
/**
|
|
41
|
+
* The application whose rules a document is set by: `'word'` stands its
|
|
42
|
+
* lines as tall as the faces on them make them (§17.3.1.33, see
|
|
43
|
+
* `fontLeadingPt`) rather than Ream's flat 1.2× of the size, and gives every
|
|
44
|
+
* horizontal table border the room it is wide (§17.4.38, see
|
|
45
|
+
* `withBorderBands`) rather than none. A Word document's reader asks for it
|
|
46
|
+
* (see `FlowDoc.typesetBy`).
|
|
47
|
+
*/
|
|
48
|
+
export type TypesetBy = 'word';
|
|
36
49
|
/**
|
|
37
50
|
* The full option set the layout engine and PDF emitter consume: the resolved
|
|
38
51
|
* font registry, the style/numbering tables, the section model and page
|
|
@@ -46,6 +59,8 @@ export interface StyledRenderOptions {
|
|
|
46
59
|
readonly registry: FontRegistry;
|
|
47
60
|
/** Renderer-compatibility profile for the line-height model (default `'ream'`). */
|
|
48
61
|
readonly layoutProfile?: LayoutProfile;
|
|
62
|
+
/** The application whose rules the document is set by (see {@link TypesetBy}). */
|
|
63
|
+
readonly typesetBy?: TypesetBy;
|
|
49
64
|
/**
|
|
50
65
|
* Per-run font resolution: when supplied, each text run picks the registry of
|
|
51
66
|
* its declared family (sans→arimo / serif→tinos / mono→cousine via the run's
|
|
@@ -173,6 +188,12 @@ export interface StyledRenderOptions {
|
|
|
173
188
|
* TOP margin, not the left.
|
|
174
189
|
*/
|
|
175
190
|
readonly gutterAtTop?: boolean;
|
|
191
|
+
/**
|
|
192
|
+
* [MS-DOCX] `compatibilityMode` — the version of Word whose layout the
|
|
193
|
+
* document asks for; a Word document that states none is an older Word's
|
|
194
|
+
* (see {@link legacyTableOutdent}).
|
|
195
|
+
*/
|
|
196
|
+
readonly compatibilityMode?: number;
|
|
176
197
|
/**
|
|
177
198
|
* §7.6 PDF encryption (AES-256, R6). Only honoured on the ASYNC conversion
|
|
178
199
|
* path (WebCrypto); mutually exclusive with `pdfA` (ISO 19005 forbids
|
|
@@ -302,6 +323,12 @@ export interface SectionRenderCtx {
|
|
|
302
323
|
}>;
|
|
303
324
|
readonly headerSet: HeaderFooterSet;
|
|
304
325
|
readonly footerSet: HeaderFooterSet;
|
|
326
|
+
/**
|
|
327
|
+
* §17.10 — where the body starts and ends on a page that shows each band:
|
|
328
|
+
* below the header band and above the footer band that page carries, each
|
|
329
|
+
* as tall as it is. Absent ⇒ every page takes `marginTop`/`marginBottom`.
|
|
330
|
+
*/
|
|
331
|
+
readonly bandMargins?: Readonly<Record<HfBand, BodyMargins>>;
|
|
305
332
|
readonly titlePg: boolean;
|
|
306
333
|
readonly evenAndOddHeaders: boolean;
|
|
307
334
|
/**
|
|
@@ -316,10 +343,24 @@ export interface SectionRenderCtx {
|
|
|
316
343
|
* paragraph in it. Absent on a bare context built outside a layout run.
|
|
317
344
|
*/
|
|
318
345
|
readonly options?: StyledRenderOptions;
|
|
346
|
+
/**
|
|
347
|
+
* §17.6.20 — the sheet a section whose lines run DOWN it prints on. Such a
|
|
348
|
+
* section's body is laid out in the frame its text reads in, which the
|
|
349
|
+
* geometry above describes — the sheet turned back a quarter — and turned
|
|
350
|
+
* onto this sheet page by page, while its header and footer are laid out
|
|
351
|
+
* on the sheet itself (see ./turned-section). Absent ⇒ the frame is the sheet.
|
|
352
|
+
*/
|
|
353
|
+
readonly sheet?: Sheet;
|
|
354
|
+
}
|
|
355
|
+
type HfBand = 'default' | 'first' | 'even';
|
|
356
|
+
/** The distances from the paper's top and bottom edges to the body's. */
|
|
357
|
+
interface BodyMargins {
|
|
358
|
+
readonly top: number;
|
|
359
|
+
readonly bottom: number;
|
|
319
360
|
}
|
|
320
361
|
interface HfBandEntry {
|
|
321
362
|
readonly commands: Array<PageItem>;
|
|
322
|
-
readonly renderDynamic?: (
|
|
363
|
+
readonly renderDynamic?: (pageText: string, totalPages: number) => Array<PageItem>;
|
|
323
364
|
/** Laid-out height of the band, so the body can be kept clear of it. */
|
|
324
365
|
readonly heightPt?: number;
|
|
325
366
|
}
|