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.
- package/README.md +1 -1
- package/README_zh.md +1 -1
- package/dist/esm/modules/pdf/font/font-manager.js +18 -3
- package/dist/esm/modules/pdf/font/type3-font.js +19 -3
- package/dist/esm/modules/pdf/font/type3-glyphs-cyrillic.js +480 -0
- package/dist/esm/modules/pdf/font/type3-glyphs-greek-poly.js +306 -0
- package/dist/esm/modules/pdf/font/type3-glyphs-greek.js +438 -0
- package/dist/esm/modules/pdf/font/type3-glyphs-latin-b.js +457 -0
- package/dist/esm/modules/pdf/font/type3-glyphs-latin-ext.js +351 -0
- package/dist/esm/modules/pdf/font/type3-glyphs-vietnamese.js +166 -0
- package/dist/esm/modules/pdf/font/type3-glyphs.js +14 -0
- package/dist/esm/modules/pdf/font/type3-letterforms.js +619 -0
- package/dist/esm/modules/pdf/font/type3-repertoire.js +113 -23
- package/dist/iife/documonster.archive.iife.min.js +1 -1
- package/dist/iife/documonster.csv.iife.min.js +1 -1
- package/dist/iife/documonster.draw.iife.min.js +1 -1
- package/dist/iife/documonster.excel.iife.min.js +1 -1
- package/dist/iife/documonster.formula.iife.min.js +1 -1
- package/dist/iife/documonster.markdown.iife.min.js +1 -1
- package/dist/iife/documonster.mermaid.iife.min.js +1 -1
- package/dist/iife/documonster.pdf.iife.min.js +33 -33
- package/dist/iife/documonster.stream.iife.min.js +1 -1
- package/dist/iife/documonster.word.iife.min.js +1 -1
- package/dist/iife/documonster.xml.iife.min.js +1 -1
- package/dist/types/modules/pdf/font/type3-font.d.ts +12 -0
- package/dist/types/modules/pdf/font/type3-glyphs-cyrillic.d.ts +29 -0
- package/dist/types/modules/pdf/font/type3-glyphs-greek-poly.d.ts +43 -0
- package/dist/types/modules/pdf/font/type3-glyphs-greek.d.ts +36 -0
- package/dist/types/modules/pdf/font/type3-glyphs-latin-b.d.ts +33 -0
- package/dist/types/modules/pdf/font/type3-glyphs-latin-ext.d.ts +55 -0
- package/dist/types/modules/pdf/font/type3-glyphs-vietnamese.d.ts +35 -0
- package/dist/types/modules/pdf/font/type3-letterforms.d.ts +296 -0
- package/dist/types/modules/pdf/font/type3-repertoire.d.ts +44 -18
- 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.
|
|
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.
|
|
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
|
-
|
|
430
|
-
|
|
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 = `[
|
|
109
|
-
|
|
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
|
-
|
|
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);
|