documonster 0.12.0 → 0.13.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 (34) hide show
  1. package/README.md +1 -1
  2. package/README_zh.md +1 -1
  3. package/dist/esm/modules/pdf/font/font-manager.js +18 -3
  4. package/dist/esm/modules/pdf/font/type3-font.js +19 -3
  5. package/dist/esm/modules/pdf/font/type3-glyphs-cyrillic.js +480 -0
  6. package/dist/esm/modules/pdf/font/type3-glyphs-greek-poly.js +306 -0
  7. package/dist/esm/modules/pdf/font/type3-glyphs-greek.js +438 -0
  8. package/dist/esm/modules/pdf/font/type3-glyphs-latin-b.js +457 -0
  9. package/dist/esm/modules/pdf/font/type3-glyphs-latin-ext.js +351 -0
  10. package/dist/esm/modules/pdf/font/type3-glyphs-vietnamese.js +166 -0
  11. package/dist/esm/modules/pdf/font/type3-glyphs.js +14 -0
  12. package/dist/esm/modules/pdf/font/type3-letterforms.js +619 -0
  13. package/dist/esm/modules/pdf/font/type3-repertoire.js +113 -23
  14. package/dist/iife/documonster.archive.iife.min.js +1 -1
  15. package/dist/iife/documonster.csv.iife.min.js +1 -1
  16. package/dist/iife/documonster.draw.iife.min.js +1 -1
  17. package/dist/iife/documonster.excel.iife.min.js +1 -1
  18. package/dist/iife/documonster.formula.iife.min.js +1 -1
  19. package/dist/iife/documonster.markdown.iife.min.js +1 -1
  20. package/dist/iife/documonster.mermaid.iife.min.js +1 -1
  21. package/dist/iife/documonster.pdf.iife.min.js +33 -33
  22. package/dist/iife/documonster.stream.iife.min.js +1 -1
  23. package/dist/iife/documonster.word.iife.min.js +1 -1
  24. package/dist/iife/documonster.xml.iife.min.js +1 -1
  25. package/dist/types/modules/pdf/font/type3-font.d.ts +12 -0
  26. package/dist/types/modules/pdf/font/type3-glyphs-cyrillic.d.ts +29 -0
  27. package/dist/types/modules/pdf/font/type3-glyphs-greek-poly.d.ts +43 -0
  28. package/dist/types/modules/pdf/font/type3-glyphs-greek.d.ts +36 -0
  29. package/dist/types/modules/pdf/font/type3-glyphs-latin-b.d.ts +33 -0
  30. package/dist/types/modules/pdf/font/type3-glyphs-latin-ext.d.ts +55 -0
  31. package/dist/types/modules/pdf/font/type3-glyphs-vietnamese.d.ts +35 -0
  32. package/dist/types/modules/pdf/font/type3-letterforms.d.ts +296 -0
  33. package/dist/types/modules/pdf/font/type3-repertoire.d.ts +44 -18
  34. package/package.json +1 -1
@@ -0,0 +1,306 @@
1
+ /**
2
+ * Type3 letterforms for polytonic Greek — U+1F00…U+1FFE.
3
+ *
4
+ * Excluded from the first pass on the same mistaken reason as Vietnamese: that this
5
+ * renderer "cannot position one mark over another". It cannot do so at *draw* time, for a
6
+ * decomposed sequence. Every code point in this block is precomposed, and a precomposed
7
+ * glyph is one outline this directory authors in full — including one carrying a breathing,
8
+ * an accent and an iota subscript at once.
9
+ *
10
+ * ## Generated from the block's own structure, not written out
11
+ *
12
+ * Unicode lays this block out as a product, and hand-writing 233 rows would obscure that
13
+ * while inviting a transcription error in every one. So the table below is built from the
14
+ * grid Unicode used:
15
+ *
16
+ * U+1F00…U+1F7D vowel × breathing × accent, in rows of eight
17
+ * U+1F80…U+1FB4 the same, with an iota subscript
18
+ * U+1FB6…U+1FFE the long/short marks, the standalone breathings and accents
19
+ *
20
+ * A row of eight is `smooth, rough` × `none, grave, acute, circumflex`, which is exactly
21
+ * how {@link row} reads. Where Unicode leaves a cell empty — `ε` and `ο` have no
22
+ * circumflex, `ῂ` has no unaccented form — the generator skips it, and
23
+ * `type3-repertoire.ts` states the same gaps as ranges. The two are checked against each
24
+ * other code point for code point, so a mistake in either fails a test rather than
25
+ * shipping a hole.
26
+ *
27
+ * ## What the marks are
28
+ *
29
+ * Three of the four are already drawn: `acute`, `grave` and the `circumflex` here is the
30
+ * Greek one, a tilde-like `perispomeni`. The breathings are new — a smooth breathing is an
31
+ * apostrophe-shaped comma, a rough breathing its mirror — and the iota subscript is a
32
+ * short stroke below. A vowel can carry a breathing *and* an accent, which is the stack
33
+ * the block needs and the reason it is reachable at all.
34
+ *
35
+ * Absent: nothing. The block is complete, which is why it can be stated as three ranges.
36
+ *
37
+ * @module
38
+ */
39
+ import { GREEK_SHAPES } from "./type3-glyphs-greek.js";
40
+ import { BASE, CAP_TOP, X_TOP, acute, grave, macron, merge, shape, toGlyphDef } from "./type3-letterforms.js";
41
+ // =============================================================================
42
+ // The marks this block adds
43
+ // =============================================================================
44
+ /** Psili — smooth breathing, a raised comma opening right. Standing on `y`. */
45
+ function smooth(x, y) {
46
+ return [
47
+ [
48
+ [x + 0.02, y - 0.09],
49
+ [x + 0.07, y - 0.1],
50
+ [x + 0.09, y - 0.06],
51
+ [x + 0.05, y - 0.02],
52
+ [x + 0.02, y]
53
+ ]
54
+ ];
55
+ }
56
+ /** Dasia — rough breathing, the mirror of the smooth one. Standing on `y`. */
57
+ function rough(x, y) {
58
+ return [
59
+ [
60
+ [x + 0.08, y - 0.09],
61
+ [x + 0.03, y - 0.1],
62
+ [x + 0.01, y - 0.06],
63
+ [x + 0.05, y - 0.02],
64
+ [x + 0.08, y]
65
+ ]
66
+ ];
67
+ }
68
+ /** Perispomeni — the Greek circumflex, drawn as a tilde. Standing on `y`. */
69
+ function perispomeni(x, y) {
70
+ return [
71
+ [
72
+ [x, y - 0.02],
73
+ [x + 0.04, y - 0.07],
74
+ [x + 0.1, y - 0.02],
75
+ [x + 0.14, y - 0.07]
76
+ ]
77
+ ];
78
+ }
79
+ /** Ypogegrammeni — the iota subscript, a short stroke under the letter. */
80
+ function iotaBelow(x, y) {
81
+ return [
82
+ [
83
+ [x + 0.06, y],
84
+ [x + 0.06, y + 0.11]
85
+ ]
86
+ ];
87
+ }
88
+ /** Vrachy — the short mark, a breve standing on `y`. */
89
+ function vrachy(x, y) {
90
+ return [
91
+ [
92
+ [x, y - 0.07],
93
+ [x + 0.04, y - 0.02],
94
+ [x + 0.08, y],
95
+ [x + 0.12, y - 0.02],
96
+ [x + 0.16, y - 0.07]
97
+ ]
98
+ ];
99
+ }
100
+ /** Heights of the marks that can carry another above them. */
101
+ const HEIGHT = new Map([
102
+ [smooth, 0.1],
103
+ [rough, 0.1],
104
+ [acute, 0.1],
105
+ [grave, 0.1],
106
+ [perispomeni, 0.07]
107
+ ]);
108
+ // =============================================================================
109
+ // Composition
110
+ // =============================================================================
111
+ /** How far a mark stands above the letter, and a second mark above the first. */
112
+ const CLEARANCE = 0.1;
113
+ const STACK = 0.09;
114
+ /** Whether a Greek letter is a capital, which decides the band its marks sit in. */
115
+ function isCapital(codePoint) {
116
+ return codePoint >= 0x0386 && codePoint <= 0x03ab;
117
+ }
118
+ /**
119
+ * Put a breathing, an accent, or both, over a Greek letter — and an iota under it.
120
+ *
121
+ * The breathing always sits closer to the letter; the accent stacks above it. Where there
122
+ * is no breathing the accent takes the lower position, which is what makes `ά` and `ἄ`
123
+ * differ by a mark rather than by a height.
124
+ */
125
+ function compose(codePoint, breathing, accent, iota) {
126
+ const base = GREEK_SHAPES[codePoint];
127
+ if (base === undefined) {
128
+ throw new Error(`polytonic Greek: no base shape for U+${codePoint.toString(16)}`);
129
+ }
130
+ const top = isCapital(codePoint) ? CAP_TOP : X_TOP;
131
+ const x = base.w * 0.5 - 0.03;
132
+ const parts = [base];
133
+ const lower = breathing ?? accent;
134
+ if (lower !== null) {
135
+ parts.push(shape(base.w, ...lower(x, top - CLEARANCE)));
136
+ }
137
+ if (breathing !== null && accent !== null) {
138
+ const stackAt = top - CLEARANCE - HEIGHT.get(breathing) - STACK;
139
+ parts.push(shape(base.w, ...accent(x, stackAt)));
140
+ }
141
+ if (iota) {
142
+ parts.push(shape(base.w, ...iotaBelow(x, BASE + 0.02)));
143
+ }
144
+ return merge(...parts);
145
+ }
146
+ /**
147
+ * One case-pair of a vowel's breathing/accent grid.
148
+ *
149
+ * `cells` is how many the case takes — eight where the vowel has a circumflex, six where
150
+ * it does not — and the uppercase half always begins eight code points after the
151
+ * lowercase, *not* after the last assigned cell. Unicode leaves the two-cell hole in place
152
+ * for `ε` and `ο`, and generating the uppercase from `start + cells` instead of
153
+ * `start + 8` put every capital of those two rows two code points early.
154
+ */
155
+ function pair(start, lower, upper, cells, iota = false) {
156
+ const accents = [null, grave, acute, perispomeni];
157
+ const out = {};
158
+ for (let index = 0; index < cells; index++) {
159
+ const breathing = index % 2 === 0 ? smooth : rough;
160
+ const accent = accents[Math.floor(index / 2)];
161
+ out[start + index] = compose(lower, breathing, accent, iota);
162
+ out[start + 8 + index] = compose(upper, breathing, accent, iota);
163
+ }
164
+ return out;
165
+ }
166
+ // =============================================================================
167
+ // Table
168
+ // =============================================================================
169
+ const ALPHA = 0x03b1;
170
+ const ALPHA_UPPER = 0x0391;
171
+ const EPSILON = 0x03b5;
172
+ const EPSILON_UPPER = 0x0395;
173
+ const ETA = 0x03b7;
174
+ const ETA_UPPER = 0x0397;
175
+ const IOTA = 0x03b9;
176
+ const IOTA_UPPER = 0x0399;
177
+ const OMICRON = 0x03bf;
178
+ const OMICRON_UPPER = 0x039f;
179
+ const UPSILON = 0x03c5;
180
+ const UPSILON_UPPER = 0x03a5;
181
+ const OMEGA = 0x03c9;
182
+ const OMEGA_UPPER = 0x03a9;
183
+ const RHO = 0x03c1;
184
+ const RHO_UPPER = 0x03a1;
185
+ const SHAPES = {
186
+ // U+1F00–U+1F6F: vowel × breathing × accent. `ε` and `ο` take no circumflex, so their
187
+ // grids are six wide and Unicode leaves the remaining two cells of each case unassigned.
188
+ ...pair(0x1f00, ALPHA, ALPHA_UPPER, 8),
189
+ ...pair(0x1f10, EPSILON, EPSILON_UPPER, 6),
190
+ ...pair(0x1f20, ETA, ETA_UPPER, 8),
191
+ ...pair(0x1f30, IOTA, IOTA_UPPER, 8),
192
+ ...pair(0x1f40, OMICRON, OMICRON_UPPER, 6),
193
+ ...pair(0x1f60, OMEGA, OMEGA_UPPER, 8),
194
+ // U+1F50–U+1F5F: upsilon. Only the rough-breathing capitals exist.
195
+ 0x1f50: compose(UPSILON, smooth, null, false),
196
+ 0x1f51: compose(UPSILON, rough, null, false),
197
+ 0x1f52: compose(UPSILON, smooth, grave, false),
198
+ 0x1f53: compose(UPSILON, rough, grave, false),
199
+ 0x1f54: compose(UPSILON, smooth, acute, false),
200
+ 0x1f55: compose(UPSILON, rough, acute, false),
201
+ 0x1f56: compose(UPSILON, smooth, perispomeni, false),
202
+ 0x1f57: compose(UPSILON, rough, perispomeni, false),
203
+ 0x1f59: compose(UPSILON_UPPER, rough, null, false),
204
+ 0x1f5b: compose(UPSILON_UPPER, rough, grave, false),
205
+ 0x1f5d: compose(UPSILON_UPPER, rough, acute, false),
206
+ 0x1f5f: compose(UPSILON_UPPER, rough, perispomeni, false),
207
+ // U+1F70–U+1F7D: the plain accented vowels, without a breathing.
208
+ 0x1f70: compose(ALPHA, null, grave, false),
209
+ 0x1f71: compose(ALPHA, null, acute, false),
210
+ 0x1f72: compose(EPSILON, null, grave, false),
211
+ 0x1f73: compose(EPSILON, null, acute, false),
212
+ 0x1f74: compose(ETA, null, grave, false),
213
+ 0x1f75: compose(ETA, null, acute, false),
214
+ 0x1f76: compose(IOTA, null, grave, false),
215
+ 0x1f77: compose(IOTA, null, acute, false),
216
+ 0x1f78: compose(OMICRON, null, grave, false),
217
+ 0x1f79: compose(OMICRON, null, acute, false),
218
+ 0x1f7a: compose(UPSILON, null, grave, false),
219
+ 0x1f7b: compose(UPSILON, null, acute, false),
220
+ 0x1f7c: compose(OMEGA, null, grave, false),
221
+ 0x1f7d: compose(OMEGA, null, acute, false),
222
+ // U+1F80–U+1FAF: the same again, over an iota subscript.
223
+ ...pair(0x1f80, ALPHA, ALPHA_UPPER, 8, true),
224
+ ...pair(0x1f90, ETA, ETA_UPPER, 8, true),
225
+ ...pair(0x1fa0, OMEGA, OMEGA_UPPER, 8, true),
226
+ // U+1FB0–U+1FBE: alpha's length marks, and the standalone iota.
227
+ 0x1fb0: compose(ALPHA, null, null, false),
228
+ 0x1fb1: compose(ALPHA, null, macron, false),
229
+ 0x1fb2: compose(ALPHA, null, grave, true),
230
+ 0x1fb3: compose(ALPHA, null, null, true),
231
+ 0x1fb4: compose(ALPHA, null, acute, true),
232
+ 0x1fb6: compose(ALPHA, null, perispomeni, false),
233
+ 0x1fb7: compose(ALPHA, null, perispomeni, true),
234
+ 0x1fb8: compose(ALPHA_UPPER, null, null, false),
235
+ 0x1fb9: compose(ALPHA_UPPER, null, macron, false),
236
+ 0x1fba: compose(ALPHA_UPPER, null, grave, false),
237
+ 0x1fbb: compose(ALPHA_UPPER, null, acute, false),
238
+ 0x1fbc: compose(ALPHA_UPPER, null, null, true),
239
+ 0x1fbd: shape(0.32, ...smooth(0.08, 0.28)),
240
+ 0x1fbe: shape(0.24, ...iotaBelow(0.06, 0.5)),
241
+ // U+1FBF–U+1FCF: the standalone breathings and accents, and eta's iota forms.
242
+ 0x1fbf: shape(0.32, ...smooth(0.08, 0.28)),
243
+ 0x1fc0: shape(0.34, ...perispomeni(0.08, 0.3)),
244
+ 0x1fc1: merge(shape(0.34, ...perispomeni(0.08, 0.18)), shape(0.34, ...smooth(0.1, 0.3))),
245
+ 0x1fc2: compose(ETA, null, grave, true),
246
+ 0x1fc3: compose(ETA, null, null, true),
247
+ 0x1fc4: compose(ETA, null, acute, true),
248
+ 0x1fc6: compose(ETA, null, perispomeni, false),
249
+ 0x1fc7: compose(ETA, null, perispomeni, true),
250
+ 0x1fc8: compose(EPSILON_UPPER, null, grave, false),
251
+ 0x1fc9: compose(EPSILON_UPPER, null, acute, false),
252
+ 0x1fca: compose(ETA_UPPER, null, grave, false),
253
+ 0x1fcb: compose(ETA_UPPER, null, acute, false),
254
+ 0x1fcc: compose(ETA_UPPER, null, null, true),
255
+ 0x1fcd: merge(shape(0.34, ...smooth(0.08, 0.3)), shape(0.34, ...grave(0.1, 0.16))),
256
+ 0x1fce: merge(shape(0.34, ...smooth(0.08, 0.3)), shape(0.34, ...acute(0.1, 0.16))),
257
+ 0x1fcf: merge(shape(0.34, ...smooth(0.08, 0.3)), shape(0.34, ...perispomeni(0.08, 0.16))),
258
+ // U+1FD0–U+1FDF: iota's length marks.
259
+ 0x1fd0: compose(IOTA, null, vrachy, false),
260
+ 0x1fd1: compose(IOTA, null, macron, false),
261
+ 0x1fd2: compose(IOTA, null, grave, false),
262
+ 0x1fd3: compose(IOTA, null, acute, false),
263
+ 0x1fd6: compose(IOTA, null, perispomeni, false),
264
+ 0x1fd7: compose(IOTA, null, perispomeni, true),
265
+ 0x1fd8: compose(IOTA_UPPER, null, vrachy, false),
266
+ 0x1fd9: compose(IOTA_UPPER, null, macron, false),
267
+ 0x1fda: compose(IOTA_UPPER, null, grave, false),
268
+ 0x1fdb: compose(IOTA_UPPER, null, acute, false),
269
+ 0x1fdd: merge(shape(0.34, ...rough(0.08, 0.3)), shape(0.34, ...grave(0.1, 0.16))),
270
+ 0x1fde: merge(shape(0.34, ...rough(0.08, 0.3)), shape(0.34, ...acute(0.1, 0.16))),
271
+ 0x1fdf: merge(shape(0.34, ...rough(0.08, 0.3)), shape(0.34, ...perispomeni(0.08, 0.16))),
272
+ // U+1FE0–U+1FEF: upsilon's length marks, and rho's breathings.
273
+ 0x1fe0: compose(UPSILON, null, vrachy, false),
274
+ 0x1fe1: compose(UPSILON, null, macron, false),
275
+ 0x1fe2: compose(UPSILON, null, grave, false),
276
+ 0x1fe3: compose(UPSILON, null, acute, false),
277
+ 0x1fe4: compose(RHO, smooth, null, false),
278
+ 0x1fe5: compose(RHO, rough, null, false),
279
+ 0x1fe6: compose(UPSILON, null, perispomeni, false),
280
+ 0x1fe7: compose(UPSILON, null, perispomeni, true),
281
+ 0x1fe8: compose(UPSILON_UPPER, null, vrachy, false),
282
+ 0x1fe9: compose(UPSILON_UPPER, null, macron, false),
283
+ 0x1fea: compose(UPSILON_UPPER, null, grave, false),
284
+ 0x1feb: compose(UPSILON_UPPER, null, acute, false),
285
+ 0x1fec: compose(RHO_UPPER, rough, null, false),
286
+ 0x1fed: merge(shape(0.34, ...macron(0.06, 0.24)), shape(0.34, ...grave(0.1, 0.16))),
287
+ 0x1fee: merge(shape(0.34, ...macron(0.06, 0.24)), shape(0.34, ...acute(0.1, 0.16))),
288
+ 0x1fef: shape(0.3, ...grave(0.1, 0.26)),
289
+ // U+1FF2–U+1FFE: omega's iota forms, and the last standalone marks.
290
+ 0x1ff2: compose(OMEGA, null, grave, true),
291
+ 0x1ff3: compose(OMEGA, null, null, true),
292
+ 0x1ff4: compose(OMEGA, null, acute, true),
293
+ 0x1ff6: compose(OMEGA, null, perispomeni, false),
294
+ 0x1ff7: compose(OMEGA, null, perispomeni, true),
295
+ 0x1ff8: compose(OMICRON_UPPER, null, grave, false),
296
+ 0x1ff9: compose(OMICRON_UPPER, null, acute, false),
297
+ 0x1ffa: compose(OMEGA_UPPER, null, grave, false),
298
+ 0x1ffb: compose(OMEGA_UPPER, null, acute, false),
299
+ 0x1ffc: compose(OMEGA_UPPER, null, null, true),
300
+ 0x1ffd: shape(0.3, ...acute(0.1, 0.26)),
301
+ 0x1ffe: shape(0.32, ...rough(0.08, 0.28))
302
+ };
303
+ /** Polytonic Greek, as Type3 glyphs. */
304
+ export const GREEK_POLYTONIC = Object.fromEntries(Object.entries(SHAPES).map(([cp, form]) => [Number(cp), toGlyphDef(form)]));
305
+ /** The code points this table defines, for the repertoire to state without importing it. */
306
+ export const GREEK_POLYTONIC_CODE_POINTS = Object.keys(SHAPES).map(Number);