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
package/README.md CHANGED
@@ -211,7 +211,7 @@ const buffer = await Workbook.toBuffer(wb);
211
211
 
212
212
  ```html
213
213
  <!-- Script tag (no bundler) — one IIFE per module, each under the shared `Documonster` global -->
214
- <script src="https://unpkg.com/documonster@0.12.0/dist/iife/documonster.excel.iife.min.js"></script>
214
+ <script src="https://unpkg.com/documonster@0.13.0/dist/iife/documonster.excel.iife.min.js"></script>
215
215
  <script>
216
216
  const { Workbook, Cell } = Documonster.Excel;
217
217
  const wb = Workbook.create();
package/README_zh.md CHANGED
@@ -198,7 +198,7 @@ const buffer = await Workbook.toBuffer(wb);
198
198
 
199
199
  ```html
200
200
  <!-- Script 标签(无需打包工具)— 每个模块一个 IIFE,共享同一个 `Documonster` 全局 -->
201
- <script src="https://unpkg.com/documonster@0.12.0/dist/iife/documonster.excel.iife.min.js"></script>
201
+ <script src="https://unpkg.com/documonster@0.13.0/dist/iife/documonster.excel.iife.min.js"></script>
202
202
  <script>
203
203
  const { Workbook, Cell } = Documonster.Excel;
204
204
  const wb = Workbook.create();
@@ -24,7 +24,7 @@ import { collectEmbeddedGlyphUses, embedTtfFont } from "./font-embedder.js";
24
24
  import { buildFontPlan } from "./font-plan.js";
25
25
  import { measureText as measureType1Text, getFontAscent as getType1Ascent, getFontDescent as getType1Descent, getLineHeight as getType1LineHeight } from "./metrics.js";
26
26
  import { TextFeatureReport } from "./text-features.js";
27
- import { isType3Drawable } from "./type3-repertoire.js";
27
+ import { isType3Drawable, isType3Letterform } from "./type3-repertoire.js";
28
28
  import { addCjkLanguageEvidence, concludeCjkLanguage, createCjkLanguageEvidence, isGlyphlessControl } from "../../../utils/cjk.js";
29
29
  import { describeCodePointBlocks } from "../../../utils/unicode-blocks.js";
30
30
  // =============================================================================
@@ -426,8 +426,23 @@ export class FontManager {
426
426
  `Call embedFont(bytes) with a font that covers these blocks.`);
427
427
  }
428
428
  if (substituted.length > 0) {
429
- warn(`${substituted.length} character(s) are outside the embedded font and will be drawn ` +
430
- `with built-in Type3 glyphs: ${describeCodePointBlocks(new Set(substituted))}. ` +
429
+ // "Outside the embedded font" is only true when there is one. On the path this
430
+ // message matters most — a browser, which cannot read the host's fonts — there is
431
+ // no embedded face at all, and telling the reader a character fell outside a font
432
+ // they never supplied sends them looking for the wrong thing.
433
+ const where = this.hasEmbeddedFont()
434
+ ? "are outside the embedded font"
435
+ : "are not covered by any font available here";
436
+ // Letters are worth naming apart from symbols. A built-in arrow is as good as any
437
+ // font's, so it is a note; a built-in `Δ` is legible but visibly not the typeface
438
+ // the document asked for, which is a different thing to decide about.
439
+ const letters = substituted.filter(cp => isType3Letterform(cp));
440
+ warn(`${substituted.length} character(s) ${where} and will be drawn with built-in ` +
441
+ `Type3 glyphs: ${describeCodePointBlocks(new Set(substituted))}. ` +
442
+ (letters.length > 0
443
+ ? `${letters.length} of them are letters, drawn with a plain built-in letterform ` +
444
+ `rather than the requested typeface. `
445
+ : "") +
431
446
  `Pass a font covering them through embedFont(bytes) to keep the whole document in ` +
432
447
  `one typeface.`);
433
448
  }
@@ -22,6 +22,18 @@ import { lookupGlyph, NOTDEF_GLYPH } from "./type3-glyphs.js";
22
22
  * With a 1000-unit em square, FontMatrix = [0.001 0 0 0.001 0 0].
23
23
  */
24
24
  const UNITS_PER_EM = 1000;
25
+ /**
26
+ * The glyph bounding box every Type3 glyph declares, as `[llx, lly, urx, ury]`.
27
+ *
28
+ * The `d1` operator's box is a clip region as far as a viewer is concerned, so it has
29
+ * to contain the ink. It used to read `0 0 1000 1000`, which was true for as long as
30
+ * the repertoire was symbols: nothing reached below the baseline. Greek and Cyrillic
31
+ * brought descenders — `β γ μ φ χ ψ`, `Д Ц Щ у ф` — and accents that sit above the cap
32
+ * height, so a box starting at zero would have clipped the tail off a letter in any
33
+ * viewer that honours it. The bounds below sit clear of both, and
34
+ * `type3-letterforms.test.ts` asserts every glyph fits inside them.
35
+ */
36
+ export const GLYPH_BBOX = [0, -350, 1300, 1250];
25
37
  /** Maximum glyphs per Type3 font (single-byte encoding limit). */
26
38
  const MAX_GLYPHS_PER_FONT = 256;
27
39
  // First usable encoding slot (0x00 = .notdef, start user glyphs at 0x01).
@@ -105,8 +117,11 @@ function writeSingleType3Font(writer, codePoints, resourceName) {
105
117
  const toUnicodeObjNum = writeToUnicodeCMap(writer, codePoints);
106
118
  // Build the Type3 font dictionary
107
119
  const fontObjNum = writer.allocObject();
108
- const fontBBox = `[0 0 ${UNITS_PER_EM} ${UNITS_PER_EM}]`;
109
- const fontMatrix = "[0.001 0 0 0.001 0 0]";
120
+ const fontBBox = `[${GLYPH_BBOX.join(" ")}]`;
121
+ // Derived, not written out: the matrix and the em are the same fact, and the glyph
122
+ // coordinates every table in this directory uses depend on them agreeing.
123
+ const unit = 1 / UNITS_PER_EM;
124
+ const fontMatrix = `[${unit} 0 0 ${unit} 0 0]`;
110
125
  const fontDict = new PdfDict()
111
126
  .set("Type", "/Font")
112
127
  .set("Subtype", "/Type3")
@@ -129,7 +144,8 @@ function writeGlyphStream(writer, glyph) {
129
144
  const stream = new PdfContentStream();
130
145
  // d1 operator: wx wy llx lly urx ury — sets glyph width and bounding box
131
146
  // This tells the PDF viewer the advance width and clip region
132
- stream.raw(`${glyph.width} 0 0 0 ${UNITS_PER_EM} ${UNITS_PER_EM} d1`);
147
+ const [llx, lly, urx, ury] = GLYPH_BBOX;
148
+ stream.raw(`${glyph.width} 0 ${llx} ${lly} ${urx} ${ury} d1`);
133
149
  // Draw the glyph using the pen adapter
134
150
  const pen = createPen(stream);
135
151
  glyph.draw(pen);
@@ -0,0 +1,480 @@
1
+ /**
2
+ * Cyrillic letterforms for the Type3 fallback — U+0400…U+045F.
3
+ *
4
+ * The whole of the modern range: Russian, Bulgarian, Serbian, Macedonian, Ukrainian
5
+ * and Belarusian all read out of these 96 code points. The Cyrillic Supplement and
6
+ * the historic letters above U+045F are absent for the same reason polytonic Greek is
7
+ * — a document that needs them needs a real font, and `requiresEmbeddedFace` still
8
+ * asks for one.
9
+ *
10
+ * Three kinds of reuse do most of the work, and the second is the one that makes this
11
+ * table small:
12
+ *
13
+ * - **Eleven capitals are Latin letters.** `А В Е К М Н О Р С Т Х` are the same
14
+ * outlines, taken from the shared stroke font.
15
+ * - **Cyrillic lowercase is largely its own uppercase at x-height.** `в к м н п т`
16
+ * and a dozen more are small capitals, not distinct shapes as in Latin, so
17
+ * {@link asSmall} derives them from the capitals above. Only `б г д е з и й у ф`
18
+ * and the soft signs need their own drawing or a Latin twin.
19
+ * - **Three capitals are Greek.** `Г` `П` `Ф` are `Γ` `Π` `Φ`, and are built the
20
+ * same way here rather than imported, because the Greek table's exports are
21
+ * glyphs and what this needs is the shape.
22
+ *
23
+ * @module
24
+ */
25
+ import { acute, ascii, asSmall, breve, diaeresis, grave, merge, shape, toGlyphDef, withMarkOver, withMarkOverSmall } from "./type3-letterforms.js";
26
+ // =============================================================================
27
+ // Capitals
28
+ // =============================================================================
29
+ /** Б — `Ь` with a top arm. */
30
+ const BE = shape(0.5, [
31
+ [0.1, 0.15],
32
+ [0.42, 0.15]
33
+ ], [
34
+ [0.1, 0.15],
35
+ [0.1, 0.75],
36
+ [0.3, 0.75],
37
+ [0.4, 0.67],
38
+ [0.4, 0.52],
39
+ [0.3, 0.45],
40
+ [0.1, 0.45]
41
+ ]);
42
+ /** Г — a stem and a top arm. */
43
+ const GHE = shape(0.44, [
44
+ [0.1, 0.75],
45
+ [0.1, 0.15],
46
+ [0.4, 0.15]
47
+ ]);
48
+ /** Д — a bowl on two feet. */
49
+ const DE = shape(0.56, [
50
+ [0.06, 0.85],
51
+ [0.06, 0.75],
52
+ [0.14, 0.75],
53
+ [0.2, 0.15],
54
+ [0.42, 0.15],
55
+ [0.42, 0.75],
56
+ [0.5, 0.75],
57
+ [0.5, 0.85]
58
+ ], [
59
+ [0.14, 0.75],
60
+ [0.42, 0.75]
61
+ ]);
62
+ /** Ж — a stem with four arms. */
63
+ const ZHE = shape(0.66, [
64
+ [0.33, 0.15],
65
+ [0.33, 0.75]
66
+ ], [
67
+ [0.06, 0.15],
68
+ [0.31, 0.45]
69
+ ], [
70
+ [0.06, 0.75],
71
+ [0.31, 0.45]
72
+ ], [
73
+ [0.6, 0.15],
74
+ [0.35, 0.45]
75
+ ], [
76
+ [0.6, 0.75],
77
+ [0.35, 0.45]
78
+ ]);
79
+ /** З — two arcs, like a `3`. */
80
+ const ZE = shape(0.46, [
81
+ [0.1, 0.22],
82
+ [0.22, 0.15],
83
+ [0.36, 0.2],
84
+ [0.38, 0.33],
85
+ [0.26, 0.44],
86
+ [0.38, 0.55],
87
+ [0.38, 0.68],
88
+ [0.24, 0.75],
89
+ [0.1, 0.68]
90
+ ]);
91
+ /** И — two stems joined by a rising diagonal. */
92
+ const I_CYR = shape(0.52, [
93
+ [0.1, 0.75],
94
+ [0.1, 0.15]
95
+ ], [
96
+ [0.42, 0.75],
97
+ [0.42, 0.15]
98
+ ], [
99
+ [0.1, 0.75],
100
+ [0.42, 0.15]
101
+ ]);
102
+ /** Л — a bowl-less `П` with a slanted left leg. */
103
+ const EL = shape(0.54, [
104
+ [0.06, 0.75],
105
+ [0.16, 0.4],
106
+ [0.2, 0.15],
107
+ [0.44, 0.15],
108
+ [0.44, 0.75]
109
+ ]);
110
+ /** П — two stems under a bridge. */
111
+ const PE = shape(0.54, [
112
+ [0.1, 0.75],
113
+ [0.1, 0.15],
114
+ [0.44, 0.15],
115
+ [0.44, 0.75]
116
+ ]);
117
+ /** У — a `Y` whose tail descends and hooks left. */
118
+ const U_CYR = shape(0.48, [
119
+ [0.06, 0.15],
120
+ [0.26, 0.5]
121
+ ], [
122
+ [0.44, 0.15],
123
+ [0.16, 0.86],
124
+ [0.06, 0.9]
125
+ ]);
126
+ /** Ф — a full-height stem through a bowl. */
127
+ const EF = merge(shape(0.58, [
128
+ [0.29, 0.15],
129
+ [0.29, 0.75]
130
+ ]), shape(0.58, [
131
+ [0.29, 0.26],
132
+ [0.16, 0.29],
133
+ [0.09, 0.37],
134
+ [0.09, 0.53],
135
+ [0.16, 0.61],
136
+ [0.29, 0.64],
137
+ [0.42, 0.61],
138
+ [0.49, 0.53],
139
+ [0.49, 0.37],
140
+ [0.42, 0.29],
141
+ [0.29, 0.26]
142
+ ]));
143
+ /** Ц — `И` reversed, with a descending tail. */
144
+ const TSE = shape(0.54, [
145
+ [0.1, 0.15],
146
+ [0.1, 0.75],
147
+ [0.42, 0.75],
148
+ [0.42, 0.15]
149
+ ], [
150
+ [0.42, 0.75],
151
+ [0.42, 0.88],
152
+ [0.48, 0.88]
153
+ ]);
154
+ /** Ч — a stem with a cup on its left. */
155
+ const CHE = shape(0.5, [
156
+ [0.1, 0.15],
157
+ [0.1, 0.38],
158
+ [0.18, 0.46],
159
+ [0.4, 0.46],
160
+ [0.4, 0.15],
161
+ [0.4, 0.75]
162
+ ]);
163
+ /** Ш — three stems on a bar. */
164
+ const SHA = shape(0.66, [
165
+ [0.08, 0.15],
166
+ [0.08, 0.75],
167
+ [0.32, 0.75],
168
+ [0.32, 0.15],
169
+ [0.32, 0.75],
170
+ [0.56, 0.75],
171
+ [0.56, 0.15]
172
+ ]);
173
+ /** Щ — `Ш` with a descending tail. */
174
+ const SHCHA = merge(SHA, shape(0.7, [
175
+ [0.56, 0.75],
176
+ [0.56, 0.88],
177
+ [0.62, 0.88]
178
+ ]));
179
+ /** Ъ — a hard sign: a shoulder and a bowl. */
180
+ const HARD = shape(0.54, [
181
+ [0.06, 0.15],
182
+ [0.2, 0.15]
183
+ ], [
184
+ [0.2, 0.15],
185
+ [0.2, 0.75],
186
+ [0.38, 0.75],
187
+ [0.47, 0.67],
188
+ [0.47, 0.53],
189
+ [0.38, 0.46],
190
+ [0.2, 0.46]
191
+ ]);
192
+ /** Ь — a soft sign. */
193
+ const SOFT = shape(0.46, [
194
+ [0.1, 0.15],
195
+ [0.1, 0.75],
196
+ [0.28, 0.75],
197
+ [0.38, 0.67],
198
+ [0.38, 0.53],
199
+ [0.28, 0.46],
200
+ [0.1, 0.46]
201
+ ]);
202
+ /** Ы — a soft sign with a stem to its right. */
203
+ const YERU = merge(SOFT, shape(0.62, [
204
+ [0.53, 0.15],
205
+ [0.53, 0.75]
206
+ ]));
207
+ /** Э — a reversed `С` with a waist bar. */
208
+ const E_CYR = merge(shape(0.48, [
209
+ [0.1, 0.22],
210
+ [0.24, 0.15],
211
+ [0.38, 0.24],
212
+ [0.42, 0.45],
213
+ [0.38, 0.66],
214
+ [0.24, 0.75],
215
+ [0.1, 0.68]
216
+ ]), shape(0.48, [
217
+ [0.24, 0.45],
218
+ [0.42, 0.45]
219
+ ]));
220
+ /** Ю — a stem tied to a bowl. */
221
+ const YU = merge(shape(0.66, [
222
+ [0.08, 0.15],
223
+ [0.08, 0.75]
224
+ ]), shape(0.66, [
225
+ [0.08, 0.45],
226
+ [0.24, 0.45]
227
+ ]), shape(0.66, [
228
+ [0.38, 0.15],
229
+ [0.26, 0.22],
230
+ [0.24, 0.36],
231
+ [0.24, 0.54],
232
+ [0.26, 0.68],
233
+ [0.38, 0.75],
234
+ [0.52, 0.68],
235
+ [0.56, 0.54],
236
+ [0.56, 0.36],
237
+ [0.52, 0.22],
238
+ [0.38, 0.15]
239
+ ]));
240
+ /** Я — a mirrored `R`. */
241
+ const YA = shape(0.5, [
242
+ [0.42, 0.15],
243
+ [0.42, 0.75]
244
+ ], [
245
+ [0.42, 0.15],
246
+ [0.2, 0.15],
247
+ [0.1, 0.23],
248
+ [0.1, 0.37],
249
+ [0.2, 0.45],
250
+ [0.42, 0.45]
251
+ ], [
252
+ [0.24, 0.45],
253
+ [0.1, 0.75]
254
+ ]);
255
+ // =============================================================================
256
+ // Letters outside the Russian alphabet
257
+ // =============================================================================
258
+ /** Ђ — a barred stem with a bowl on the right. */
259
+ const DJE = merge(shape(0.54, [
260
+ [0.06, 0.28],
261
+ [0.34, 0.28]
262
+ ], [
263
+ [0.2, 0.15],
264
+ [0.2, 0.75]
265
+ ]), shape(0.54, [
266
+ [0.2, 0.45],
267
+ [0.38, 0.45],
268
+ [0.47, 0.53],
269
+ [0.47, 0.67],
270
+ [0.38, 0.75],
271
+ [0.2, 0.75]
272
+ ]));
273
+ /** Є — a reversed `Э` without the descender: an `E` rounded to the right. */
274
+ const UKR_IE = merge(shape(0.48, [
275
+ [0.4, 0.22],
276
+ [0.26, 0.15],
277
+ [0.12, 0.24],
278
+ [0.08, 0.45],
279
+ [0.12, 0.66],
280
+ [0.26, 0.75],
281
+ [0.4, 0.68]
282
+ ]), shape(0.48, [
283
+ [0.08, 0.45],
284
+ [0.3, 0.45]
285
+ ]));
286
+ /** Љ — `Л` tied to a soft sign. */
287
+ const LJE = merge(shape(0.72, [
288
+ [0.04, 0.75],
289
+ [0.12, 0.4],
290
+ [0.16, 0.15],
291
+ [0.34, 0.15],
292
+ [0.34, 0.75]
293
+ ]), shape(0.72, [
294
+ [0.34, 0.45],
295
+ [0.52, 0.45],
296
+ [0.62, 0.53],
297
+ [0.62, 0.67],
298
+ [0.52, 0.75],
299
+ [0.34, 0.75]
300
+ ]));
301
+ /** Њ — `Н` tied to a soft sign. */
302
+ const NJE = merge(shape(0.72, [
303
+ [0.08, 0.15],
304
+ [0.08, 0.75]
305
+ ], [
306
+ [0.34, 0.15],
307
+ [0.34, 0.75]
308
+ ], [
309
+ [0.08, 0.45],
310
+ [0.34, 0.45]
311
+ ]), shape(0.72, [
312
+ [0.34, 0.45],
313
+ [0.52, 0.45],
314
+ [0.62, 0.53],
315
+ [0.62, 0.67],
316
+ [0.52, 0.75],
317
+ [0.34, 0.75]
318
+ ]));
319
+ /** Ћ — a barred stem with a bowl, the Serbian tshe. */
320
+ const TSHE = merge(shape(0.54, [
321
+ [0.06, 0.28],
322
+ [0.34, 0.28]
323
+ ], [
324
+ [0.2, 0.15],
325
+ [0.2, 0.75]
326
+ ]), shape(0.54, [
327
+ [0.2, 0.45],
328
+ [0.38, 0.45],
329
+ [0.47, 0.53],
330
+ [0.47, 0.75]
331
+ ]));
332
+ /** Џ — `Ц` with the tail centred. */
333
+ const DZHE = shape(0.54, [
334
+ [0.1, 0.15],
335
+ [0.1, 0.75],
336
+ [0.42, 0.75],
337
+ [0.42, 0.15]
338
+ ], [
339
+ [0.26, 0.75],
340
+ [0.26, 0.88]
341
+ ]);
342
+ /** Й — `И` under a breve. */
343
+ const SHORT_I = merge(I_CYR, shape(I_CYR.w, ...breve(0.12, 0.04, 0.28)));
344
+ /** Ў — `У` under a breve. */
345
+ const U_BREVE = merge(U_CYR, shape(U_CYR.w, ...breve(0.1, 0.04, 0.28)));
346
+ /** ў — the lowercase of the above, over the Latin `y` that stands in for `у`. */
347
+ const U_BREVE_SMALL = merge(ascii("y"), shape(ascii("y").w, ...breve(0.08, 0.27, 0.26)));
348
+ // =============================================================================
349
+ // Table
350
+ // =============================================================================
351
+ /**
352
+ * Put a mark over a letter whose advance is much narrower than its mark.
353
+ *
354
+ * `Ї` and `ї` are the cases: centring a two-dot diaeresis on a stem 0.25 em wide by
355
+ * the usual rule puts the right dot outside the advance.
356
+ */
357
+ function overNarrow(base, mark) {
358
+ return merge(base, shape(base.w, ...mark(base.w * 0.5 - 0.07, 0.02)));
359
+ }
360
+ const SHAPES = {
361
+ // U+0400–U+040F — the letters outside Russian, and the accented capitals.
362
+ 0x400: withMarkOver(ascii("E"), grave),
363
+ 0x401: withMarkOver(ascii("E"), diaeresis),
364
+ 0x402: DJE,
365
+ 0x403: withMarkOver(GHE, acute),
366
+ 0x404: UKR_IE,
367
+ 0x405: ascii("S"),
368
+ 0x406: ascii("I"),
369
+ 0x407: overNarrow(ascii("I"), diaeresis),
370
+ 0x408: ascii("J"),
371
+ 0x409: LJE,
372
+ 0x40a: NJE,
373
+ 0x40b: TSHE,
374
+ 0x40c: withMarkOver(ascii("K"), acute),
375
+ 0x40d: withMarkOver(I_CYR, grave),
376
+ 0x40e: U_BREVE,
377
+ 0x40f: DZHE,
378
+ // U+0410–U+042F — the Russian capitals.
379
+ 0x410: ascii("A"),
380
+ 0x411: BE,
381
+ 0x412: ascii("B"),
382
+ 0x413: GHE,
383
+ 0x414: DE,
384
+ 0x415: ascii("E"),
385
+ 0x416: ZHE,
386
+ 0x417: ZE,
387
+ 0x418: I_CYR,
388
+ 0x419: SHORT_I,
389
+ 0x41a: ascii("K"),
390
+ 0x41b: EL,
391
+ 0x41c: ascii("M"),
392
+ 0x41d: ascii("H"),
393
+ 0x41e: ascii("O"),
394
+ 0x41f: PE,
395
+ 0x420: ascii("P"),
396
+ 0x421: ascii("C"),
397
+ 0x422: ascii("T"),
398
+ 0x423: U_CYR,
399
+ 0x424: EF,
400
+ 0x425: ascii("X"),
401
+ 0x426: TSE,
402
+ 0x427: CHE,
403
+ 0x428: SHA,
404
+ 0x429: SHCHA,
405
+ 0x42a: HARD,
406
+ 0x42b: YERU,
407
+ 0x42c: SOFT,
408
+ 0x42d: E_CYR,
409
+ 0x42e: YU,
410
+ 0x42f: YA,
411
+ // U+0430–U+044F — the Russian lowercase. Small capitals except where noted.
412
+ 0x430: ascii("a"),
413
+ 0x431: shape(0.46, [
414
+ [0.36, 0.28],
415
+ [0.24, 0.24],
416
+ [0.14, 0.3],
417
+ [0.1, 0.42]
418
+ ], [
419
+ [0.1, 0.42],
420
+ [0.1, 0.66],
421
+ [0.2, 0.75],
422
+ [0.32, 0.75],
423
+ [0.4, 0.66],
424
+ [0.4, 0.52],
425
+ [0.32, 0.45],
426
+ [0.14, 0.45],
427
+ [0.1, 0.5]
428
+ ]),
429
+ 0x432: asSmall(ascii("B")),
430
+ 0x433: asSmall(GHE),
431
+ 0x434: asSmall(DE),
432
+ 0x435: ascii("e"),
433
+ 0x436: asSmall(ZHE),
434
+ 0x437: asSmall(ZE),
435
+ 0x438: asSmall(I_CYR),
436
+ 0x439: asSmall(SHORT_I),
437
+ 0x43a: asSmall(ascii("K")),
438
+ 0x43b: asSmall(EL),
439
+ 0x43c: asSmall(ascii("M")),
440
+ 0x43d: asSmall(ascii("H")),
441
+ 0x43e: ascii("o"),
442
+ 0x43f: asSmall(PE),
443
+ 0x440: ascii("p"),
444
+ 0x441: ascii("c"),
445
+ 0x442: asSmall(ascii("T")),
446
+ 0x443: ascii("y"),
447
+ 0x444: asSmall(EF),
448
+ 0x445: ascii("x"),
449
+ 0x446: asSmall(TSE),
450
+ 0x447: asSmall(CHE),
451
+ 0x448: asSmall(SHA),
452
+ 0x449: asSmall(SHCHA),
453
+ 0x44a: asSmall(HARD),
454
+ 0x44b: asSmall(YERU),
455
+ 0x44c: asSmall(SOFT),
456
+ 0x44d: asSmall(E_CYR),
457
+ 0x44e: asSmall(YU),
458
+ 0x44f: asSmall(YA),
459
+ // U+0450–U+045F — the lowercase of U+0400–U+040F.
460
+ 0x450: withMarkOverSmall(ascii("e"), grave),
461
+ 0x451: withMarkOverSmall(ascii("e"), diaeresis),
462
+ 0x452: asSmall(DJE),
463
+ 0x453: withMarkOverSmall(asSmall(GHE), acute),
464
+ 0x454: asSmall(UKR_IE),
465
+ 0x455: ascii("s"),
466
+ 0x456: ascii("i"),
467
+ 0x457: overNarrow(ascii("i"), diaeresis),
468
+ 0x458: ascii("j"),
469
+ 0x459: asSmall(LJE),
470
+ 0x45a: asSmall(NJE),
471
+ 0x45b: asSmall(TSHE),
472
+ 0x45c: withMarkOverSmall(asSmall(ascii("K")), acute),
473
+ 0x45d: withMarkOverSmall(asSmall(I_CYR), grave),
474
+ 0x45e: U_BREVE_SMALL,
475
+ 0x45f: asSmall(DZHE)
476
+ };
477
+ /** Cyrillic, as Type3 glyphs. */
478
+ export const CYRILLIC = Object.fromEntries(Object.entries(SHAPES).map(([cp, form]) => [Number(cp), toGlyphDef(form)]));
479
+ /** The code points this table defines, for the repertoire to state without importing it. */
480
+ export const CYRILLIC_CODE_POINTS = Object.keys(SHAPES).map(Number);