harfbuzzjs 0.10.3 → 1.0.0-beta.1

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/test/index.js DELETED
@@ -1,1040 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const { expect } = require('chai');
4
- let hb;
5
- let blob, face, font, buffer, fontFuncs;
6
-
7
- before(async function () {
8
- hb = await require('..');
9
- });
10
-
11
- afterEach(function () {
12
- if (blob) blob.destroy();
13
- if (face) face.destroy();
14
- if (font) font.destroy();
15
- if (buffer) buffer.destroy();
16
- if (fontFuncs) fontFuncs.destroy();
17
- blob = face = font = buffer = fontFuncs = undefined;
18
- });
19
-
20
- describe('Face', function () {
21
- it('collectUnicodes reflects codepoints supported by the font', function () {
22
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
23
- face = hb.createFace(blob);
24
- const codepoints = [...face.collectUnicodes()];
25
- expect(codepoints).to.include('a'.codePointAt(0));
26
- expect(codepoints).not.to.include('ا'.codePointAt(0));
27
- });
28
-
29
- it('exposes upem', function () {
30
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
31
- face = hb.createFace(blob);
32
- expect(face.upem).to.equal(1000);
33
- });
34
-
35
- it('getAxisInfos returns details of a variable font', function () {
36
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansArabic-Variable.ttf')));
37
- face = hb.createFace(blob);
38
- expect(face.getAxisInfos()).to.deep.equal({
39
- wght: { min: 100, default: 400, max: 900 },
40
- wdth: { min: 62.5, default: 100, max: 100 }
41
- });
42
- });
43
-
44
- it('getAxisInfos returns an empty object for a non-variable font', function () {
45
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
46
- face = hb.createFace(blob);
47
- expect(Object.keys(face.getAxisInfos())).to.have.lengthOf(0);
48
- });
49
-
50
- it('getTableScriptTags returns tags for a font', function () {
51
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
52
- face = hb.createFace(blob);
53
- expect(face.getTableScriptTags('GSUB')).to.deep.equal(['DFLT', 'cyrl', 'dev2', 'deva', 'grek', 'latn']);
54
- expect(face.getTableScriptTags('GPOS')).to.deep.equal(['DFLT', 'cyrl', 'dev2', 'deva', 'grek', 'latn']);
55
- });
56
-
57
- it('getTableFeatureTags returns tags for a font', function () {
58
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
59
- face = hb.createFace(blob);
60
- expect(face.getTableFeatureTags('GSUB')).to.deep.equal([
61
- 'aalt', 'abvs', 'akhn', 'blwf', 'blwf', 'blws', 'c2sc', 'case', 'ccmp', 'ccmp',
62
- 'ccmp', 'ccmp', 'cjct', 'cjct', 'dnom', 'frac', 'half', 'half', 'half', 'half',
63
- 'haln', 'liga', 'lnum', 'locl', 'locl', 'locl', 'locl', 'locl', 'locl', 'locl',
64
- 'locl', 'locl', 'locl', 'locl', 'locl', 'nukt', 'numr', 'onum', 'ordn', 'pnum',
65
- 'pres', 'pres', 'psts', 'rkrf', 'rphf', 'rtlm', 'salt', 'sinf', 'smcp', 'ss03',
66
- 'ss04', 'ss06', 'ss07', 'subs', 'sups', 'tnum', 'vatu', 'zero'
67
- ]);
68
- expect(face.getTableFeatureTags('GPOS')).to.deep.equal(['abvm', 'blwm', 'dist', 'kern', 'mark', 'mkmk']);
69
- });
70
-
71
- it('getScriptLanguageTags returns tags for a font', function () {
72
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
73
- face = hb.createFace(blob);
74
- expect(face.getScriptLanguageTags('GSUB', 1)).to.deep.equal(['MKD ', 'SRB ']);
75
- expect(face.getScriptLanguageTags('GPOS', 5)).to.deep.equal([]);
76
- });
77
-
78
- it('getScriptLanguageTags returns tags for GPOS table', function () {
79
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansDevanagari-Regular.otf')));
80
- face = hb.createFace(blob);
81
- expect(face.getScriptLanguageTags('GPOS', 1)).to.deep.equal(['MAR ', 'NEP ', 'SAN ', 'SAT ']);
82
- });
83
-
84
- it('getLanguageFeatureTags returns tags for a font', function () {
85
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
86
- face = hb.createFace(blob);
87
- expect(face.getLanguageFeatureTags('GSUB', 1, 1)).to.deep.equal(['aalt', 'c2sc', 'case', 'ccmp', 'dnom', 'frac',
88
- 'liga', 'lnum', 'locl', 'numr', 'onum', 'ordn', 'pnum', 'rtlm', 'sinf', 'smcp', 'ss03', 'ss06', 'ss07', 'subs',
89
- 'sups', 'tnum', 'zero']);
90
- expect(face.getLanguageFeatureTags('GPOS', 5, 5)).to.deep.equal([]);
91
- });
92
-
93
- it('getTableScriptTags, getScriptLanguageTags, and getLanguageFeatureTags all together', function () {
94
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansArabic-Variable.ttf')));
95
- face = hb.createFace(blob);
96
- let result = {};
97
- face.getTableScriptTags('GSUB').forEach((script, scriptIndex) => {
98
- result[script] = { 'dflt': face.getLanguageFeatureTags('GSUB', scriptIndex, 0xFFFF) };
99
- face.getScriptLanguageTags('GSUB', scriptIndex).forEach((language, languageIndex) => {
100
- result[script][language] = face.getLanguageFeatureTags('GSUB', scriptIndex, languageIndex);
101
- });
102
- });
103
- expect(result).to.deep.equal({
104
- 'DFLT': {
105
- 'dflt': ['aalt', 'ccmp', 'dlig', 'fina', 'init', 'isol', 'medi']
106
- },
107
- 'arab': {
108
- 'dflt': ['aalt', 'ccmp', 'dlig', 'fina', 'init', 'isol', 'medi', 'rlig'],
109
- 'URD ': ['aalt', 'ccmp', 'dlig', 'fina', 'init', 'isol', 'locl', 'medi']
110
- }
111
- });
112
- });
113
-
114
- it('getGlyphClass returns the class of a glyph', function () {
115
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
116
- face = hb.createFace(blob);
117
- font = hb.createFont(face);
118
- expect(face.getGlyphClass(0)).to.equal('UNCLASSIFIED');
119
- expect(face.getGlyphClass(font.glyphFromName('w'))).to.equal('BASE_GLYPH');
120
- expect(face.getGlyphClass(font.glyphFromName('fi'))).to.equal('LIGATURE');
121
- expect(face.getGlyphClass(font.glyphFromName('gravecomb'))).to.equal('MARK');
122
- });
123
-
124
- it('listNames fetches all names', function () {
125
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
126
- face = hb.createFace(blob);
127
- let names = face.listNames();
128
- expect(names.length).to.equal(38);
129
- expect(names[0]).to.deep.equal({ nameId: 0, language: 'en' });
130
- expect(names[37]).to.deep.equal({ nameId: 278, language: 'en' });
131
- })
132
-
133
- it('getName fetches a name', function () {
134
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
135
- face = hb.createFace(blob);
136
- expect(face.getName(1, 'en')).to.equal('Noto Sans');
137
- expect(face.getName(256, 'en')).to.equal('florin symbol');
138
- })
139
-
140
- it('getFeatureNameIds returns valid name Ids for ssNN features', function () {
141
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
142
- face = hb.createFace(blob);
143
- expect(face.getFeatureNameIds("GSUB",
144
- face.getTableFeatureTags("GSUB").indexOf("ss03"))).to.deep.equal({
145
- uiLabelNameId: 256,
146
- uiTooltipTextNameId: null,
147
- sampleTextNameId: null,
148
- paramUiLabelNameIds: []
149
- });
150
- })
151
-
152
- it('getFeatureNameIds with getName', function () {
153
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
154
- face = hb.createFace(blob);
155
- expect(face.getName(face.getFeatureNameIds("GSUB",
156
- face.getTableFeatureTags("GSUB").indexOf("ss03")).uiLabelNameId, 'en')).to.equal('florin symbol');
157
- })
158
-
159
- it('getFeatureNameIds not found', function () {
160
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
161
- face = hb.createFace(blob);
162
- expect(face.getFeatureNameIds("GSUB",
163
- face.getTableFeatureTags("GSUB").indexOf("salt"))).to.equal(null);
164
- })
165
-
166
- it('getFeatureNameIds returns valid name Ids for cvNN features', function () {
167
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, '../harfbuzz/test/api/fonts/cv01.otf')));
168
- face = hb.createFace(blob);
169
- expect(face.getFeatureNameIds("GSUB",
170
- face.getTableFeatureTags("GSUB").indexOf("cv01"))).to.deep.equal({
171
- uiLabelNameId: 256,
172
- uiTooltipTextNameId: 257,
173
- sampleTextNameId: 258,
174
- paramUiLabelNameIds: [259, 260]
175
- });
176
- })
177
- });
178
-
179
- describe('Font', function () {
180
- it('subFont creates a sub font', function () {
181
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
182
- face = hb.createFace(blob);
183
- font = hb.createFont(face);
184
- let subFont = font.subFont();
185
- expect(subFont.ptr).to.not.equal(font.ptr);
186
- subFont.destroy();
187
- });
188
-
189
- it('subFont font funcs fallback to parent', function () {
190
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
191
- face = hb.createFace(blob);
192
- font = hb.createFont(face);
193
- let subFont = font.subFont();
194
- expect(subFont.ptr).to.not.equal(font.ptr);
195
-
196
- fontFuncs = hb.createFontFuncs();
197
- fontFuncs.setGlyphNameFunc(function (font_, glyph) {
198
- expect(font_.ptr).to.equal(subFont.ptr);
199
- return null;
200
- });
201
- subFont.setFuncs(fontFuncs);
202
-
203
- expect(subFont.glyphName(20)).to.equal("gid20");
204
- expect(subFont.glyphHAdvance(20)).to.equal(font.glyphHAdvance(20));
205
- subFont.destroy();
206
- });
207
-
208
- it('hExtents returns extents for the font', function () {
209
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
210
- face = hb.createFace(blob);
211
- font = hb.createFont(face);
212
- expect(font.hExtents()).to.deep.equal({
213
- ascender: 1069,
214
- descender: -293,
215
- lineGap: 0
216
- });
217
- });
218
-
219
- it('vExtents returns extents for the font', function () {
220
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
221
- face = hb.createFace(blob);
222
- font = hb.createFont(face);
223
- expect(font.vExtents()).to.deep.equal({
224
- ascender: 0,
225
- descender: 0,
226
- lineGap: 0
227
- });
228
- });
229
-
230
- it('glyphName returns names for glyph ids', function () {
231
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
232
- face = hb.createFace(blob);
233
- font = hb.createFont(face);
234
- expect(font.glyphName(20)).to.equal('one');
235
- });
236
-
237
- it('setScale affects advances', function () {
238
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
239
- face = hb.createFace(blob);
240
- font = hb.createFont(face);
241
- buffer = hb.createBuffer();
242
- buffer.addText('a');
243
- buffer.guessSegmentProperties();
244
- font.setScale(1000 * 2, 1000 * 2);
245
- hb.shape(font, buffer)
246
- const glyphs = buffer.json();
247
- expect(glyphs[0].ax).to.equal(561 * 2);
248
- });
249
-
250
- it('glyphExtents returns extents for glyph ids', function () {
251
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
252
- face = hb.createFace(blob);
253
- font = hb.createFont(face);
254
- expect(font.glyphExtents(20)).to.deep.equal({
255
- xBearing: 89,
256
- yBearing: 714,
257
- width: 266,
258
- height: -714
259
- });
260
- });
261
-
262
- it('glyphHAdvance returns advances for glyph ids', function () {
263
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
264
- face = hb.createFace(blob);
265
- font = hb.createFont(face);
266
- expect(font.glyphHAdvance(20)).to.equal(572);
267
- });
268
-
269
- it('glyphVAdvance returns advances for glyph ids', function () {
270
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
271
- face = hb.createFace(blob);
272
- font = hb.createFont(face);
273
- expect(font.glyphVAdvance(20)).to.equal(-1000);
274
- });
275
-
276
- it('glyphHOrigin returns origins for glyph ids', function () {
277
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
278
- face = hb.createFace(blob);
279
- font = hb.createFont(face);
280
- expect(font.glyphHOrigin(20)).to.deep.equal([0, 0]);
281
- });
282
-
283
- it('glyphVOrigin returns origins for glyph ids', function () {
284
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
285
- face = hb.createFace(blob);
286
- font = hb.createFont(face);
287
- expect(font.glyphVOrigin(20)).to.equal(null);
288
- });
289
-
290
- it('glyphFromName returns ids for glyph names', function () {
291
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
292
- face = hb.createFace(blob);
293
- font = hb.createFont(face);
294
- expect(font.glyphFromName('one')).to.equal(20);
295
- expect(font.glyphFromName('NonExistentGlyph')).to.equal(null);
296
- });
297
-
298
- it('setVariations affects advances', function () {
299
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansArabic-Variable.ttf')));
300
- face = hb.createFace(blob);
301
- font = hb.createFont(face);
302
- font.setVariations({ 'wght': 789 });
303
- buffer = hb.createBuffer();
304
- buffer.addText('آلو');
305
- buffer.guessSegmentProperties();
306
- hb.shape(font, buffer)
307
- const glyphs = buffer.json();
308
- expect(glyphs[0].ax).to.equal(526);
309
- });
310
-
311
- it('glyphToPath converts quadratic glyph to path', function () {
312
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
313
- face = hb.createFace(blob);
314
- font = hb.createFont(face);
315
- const expected21 = 'M520,0L48,0L48,73L235,262Q289,316 326,358Q363,400 382,440.5Q401,481 401,529Q401,\
316
- 588 366,618.5Q331,649 275,649Q223,649 183.5,631Q144,613 103,581L56,640Q98,675 152.5,699.5Q207,724 275,\
317
- 724Q375,724 433,673.5Q491,623 491,534Q491,478 468,429Q445,380 404,332.5Q363,285 308,231L159,84L159,80L520,80L520,0Z';
318
- expect(font.glyphToPath(21)).to.equal(expected21);
319
- const expected22 = 'M493,547Q493,475 453,432.5Q413,390 345,376L345,372Q431,362 473,318Q515,274 515,203Q515,\
320
- 141 486,92.5Q457,44 396.5,17Q336,-10 241,-10Q185,-10 137,-1.5Q89,7 45,29L45,111Q90,89 142,76.5Q194,64 242,64Q338,\
321
- 64 380.5,101.5Q423,139 423,205Q423,272 370.5,301.5Q318,331 223,331L154,331L154,406L224,406Q312,406 357.5,443Q403,\
322
- 480 403,541Q403,593 368,621.5Q333,650 273,650Q215,650 174,633Q133,616 93,590L49,650Q87,680 143.5,702Q200,724 272,\
323
- 724Q384,724 438.5,674Q493,624 493,547Z';
324
- expect(font.glyphToPath(22)).to.equal(expected22);
325
- });
326
-
327
- it('glyphToPath converts cubic glyph to path', function () {
328
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.otf')));
329
- face = hb.createFace(blob);
330
- font = hb.createFont(face);
331
- const expected21 = 'M520,0L520,80L159,80L159,84L308,231C418,338 491,422 491,534C491,652 408,724 275,724C184,724 112,\
332
- 687 56,640L103,581C158,624 205,649 275,649C350,649 401,607 401,529C401,432 342,370 235,262L48,73L48,0L520,0Z';
333
- expect(font.glyphToPath(21)).to.equal(expected21);
334
- const expected22 = 'M493,547C493,649 421,724 272,724C176,724 100,690 49,650L93,590C146,625 196,650 273,650C353,\
335
- 650 403,610 403,541C403,460 341,406 224,406L154,406L154,331L223,331C349,331 423,294 423,205C423,117 370,64 242,64C178,\
336
- 64 105,81 45,111L45,29C104,0 166,-10 241,-10C430,-10 515,78 515,203C515,297 459,358 345,372L345,376C435,394 493,451 493,547Z';
337
- expect(font.glyphToPath(22)).to.equal(expected22);
338
- });
339
- });
340
-
341
- describe('FontFuncs', function () {
342
- it('setGlyphExtentsFunc', function () {
343
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
344
- face = hb.createFace(blob);
345
- font = hb.createFont(face);
346
- fontFuncs = hb.createFontFuncs();
347
- fontFuncs.setGlyphExtentsFunc(function (font_, glyph) {
348
- expect(font_.ptr).to.equal(font.ptr);
349
- return {
350
- xBearing: glyph,
351
- yBearing: 0,
352
- width: 100 * glyph,
353
- height: 100
354
- };
355
- });
356
- font.setFuncs(fontFuncs);
357
- expect(font.glyphExtents(0)).to.deep.equal({
358
- xBearing: 0,
359
- yBearing: 0,
360
- width: 0,
361
- height: 100
362
- });
363
- expect(font.glyphExtents(20)).to.deep.equal({
364
- xBearing: 20,
365
- yBearing: 0,
366
- width: 2000,
367
- height: 100
368
- });
369
- });
370
-
371
- it('setGlyphFromNameFunc', function () {
372
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
373
- face = hb.createFace(blob);
374
- font = hb.createFont(face);
375
- fontFuncs = hb.createFontFuncs();
376
- fontFuncs.setGlyphFromNameFunc(function (font_, name) {
377
- expect(font_.ptr).to.equal(font.ptr);
378
- return name == 'one' ? 20 : null;
379
- });
380
- font.setFuncs(fontFuncs);
381
- expect(font.glyphFromName('one')).to.equal(20);
382
- expect(font.glyphFromName('two')).to.equal(null);
383
- });
384
-
385
- it('setGlyphHAdvanceFunc', function () {
386
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
387
- face = hb.createFace(blob);
388
- font = hb.createFont(face);
389
- fontFuncs = hb.createFontFuncs();
390
- fontFuncs.setGlyphHAdvanceFunc(function (font_, glyph) {
391
- expect(font_.ptr).to.equal(font.ptr);
392
- return glyph == 20 ? 100 : 200;
393
- });
394
- font.setFuncs(fontFuncs);
395
- expect(font.glyphHAdvance(20)).to.equal(100);
396
- expect(font.glyphHAdvance(21)).to.equal(200);
397
- });
398
-
399
- it('setGlyphVAdvanceFunc', function () {
400
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
401
- face = hb.createFace(blob);
402
- font = hb.createFont(face);
403
- fontFuncs = hb.createFontFuncs();
404
- fontFuncs.setGlyphVAdvanceFunc(function (font_, glyph) {
405
- expect(font_.ptr).to.equal(font.ptr);
406
- return glyph == 20 ? 100 : 200;
407
- });
408
- font.setFuncs(fontFuncs);
409
- expect(font.glyphVAdvance(20)).to.equal(100);
410
- expect(font.glyphVAdvance(21)).to.equal(200);
411
- });
412
-
413
- it('setGlyphHOriginFunc', function () {
414
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
415
- face = hb.createFace(blob);
416
- font = hb.createFont(face);
417
- fontFuncs = hb.createFontFuncs();
418
- fontFuncs.setGlyphHOriginFunc(function (font_, glyph) {
419
- expect(font_.ptr).to.equal(font.ptr);
420
- return glyph == 20 ? [100, 200] : [300, 400];
421
- });
422
- font.setFuncs(fontFuncs);
423
- expect(font.glyphHOrigin(20)).to.deep.equal([100, 200]);
424
- expect(font.glyphHOrigin(21)).to.deep.equal([300, 400]);
425
- });
426
-
427
- it('setGlyphVOriginFunc', function () {
428
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
429
- face = hb.createFace(blob);
430
- font = hb.createFont(face);
431
- fontFuncs = hb.createFontFuncs();
432
- fontFuncs.setGlyphVOriginFunc(function (font_, glyph) {
433
- expect(font_.ptr).to.equal(font.ptr);
434
- return glyph == 20 ? [100, 200] : [300, 400];
435
- });
436
- font.setFuncs(fontFuncs);
437
- expect(font.glyphVOrigin(20)).to.deep.equal([100, 200]);
438
- expect(font.glyphVOrigin(21)).to.deep.equal([300, 400]);
439
- });
440
-
441
- it('setGlyphNameFunc', function () {
442
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
443
- face = hb.createFace(blob);
444
- font = hb.createFont(face);
445
- fontFuncs = hb.createFontFuncs();
446
- fontFuncs.setGlyphNameFunc(function (font_, glyph) {
447
- expect(font_.ptr).to.equal(font.ptr);
448
- return glyph == 20 ? 'one' : null;
449
- });
450
- font.setFuncs(fontFuncs);
451
- expect(font.glyphName(20)).to.equal('one');
452
- expect(font.glyphName(21)).to.equal('gid21');
453
- });
454
-
455
- it('setNominalGlyphFunc', function () {
456
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
457
- face = hb.createFace(blob);
458
- font = hb.createFont(face);
459
- fontFuncs = hb.createFontFuncs();
460
- fontFuncs.setNominalGlyphFunc(function (font_, unicode) {
461
- expect(font_.ptr).to.equal(font.ptr);
462
- return unicode == 49 ? 21 : 22;
463
- });
464
- font.setFuncs(fontFuncs);
465
- buffer = hb.createBuffer();
466
- buffer.addText('12');
467
- buffer.guessSegmentProperties();
468
- hb.shape(font, buffer)
469
- const glyphs = buffer.json();
470
- expect(glyphs[0].g).to.equal(21);
471
- expect(glyphs[1].g).to.equal(22);
472
- });
473
-
474
- it('setVariationGlyphFunc', function () {
475
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
476
- face = hb.createFace(blob);
477
- font = hb.createFont(face);
478
- fontFuncs = hb.createFontFuncs();
479
- fontFuncs.setNominalGlyphFunc(function (font_, unicode) {
480
- expect(font_.ptr).to.equal(font.ptr);
481
- return unicode == 49 ? 21 : 22;
482
- });
483
- fontFuncs.setVariationGlyphFunc(function (font_, unicode, variationSelector) {
484
- expect(font_.ptr).to.equal(font.ptr);
485
- return unicode == 49 ? 23 : null;
486
- });
487
- font.setFuncs(fontFuncs);
488
- buffer = hb.createBuffer();
489
- buffer.addText('11\uFE002\uFE00');
490
- buffer.guessSegmentProperties();
491
- hb.shape(font, buffer)
492
- const glyphs = buffer.json();
493
- expect(glyphs[0].g).to.equal(21);
494
- expect(glyphs[1].g).to.equal(23);
495
- expect(glyphs[2].g).to.equal(22);
496
- });
497
-
498
- it('setFontHExtentsFunc', function () {
499
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
500
- face = hb.createFace(blob);
501
- font = hb.createFont(face);
502
- fontFuncs = hb.createFontFuncs();
503
- fontFuncs.setFontHExtentsFunc(function (font_) {
504
- expect(font_.ptr).to.equal(font.ptr);
505
- return {
506
- ascender: 100,
507
- descender: 200,
508
- lineGap: 300,
509
- };
510
- });
511
- font.setFuncs(fontFuncs);
512
- expect(font.hExtents()).to.deep.equal({
513
- ascender: 100,
514
- descender: 200,
515
- lineGap: 300,
516
- });
517
- });
518
-
519
- it('setFontVExtentsFunc', function () {
520
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
521
- face = hb.createFace(blob);
522
- font = hb.createFont(face);
523
- fontFuncs = hb.createFontFuncs();
524
- fontFuncs.setFontVExtentsFunc(function (font_) {
525
- expect(font_.ptr).to.equal(font.ptr);
526
- return {
527
- ascender: 100,
528
- descender: 200,
529
- lineGap: 300,
530
- };
531
- });
532
- font.setFuncs(fontFuncs);
533
- expect(font.vExtents()).to.deep.equal({
534
- ascender: 100,
535
- descender: 200,
536
- lineGap: 300,
537
- });
538
- });
539
- });
540
-
541
- describe('Buffer', function () {
542
- it('setDirection controls direction of glyphs', function () {
543
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
544
- face = hb.createFace(blob);
545
- font = hb.createFont(face);
546
- buffer = hb.createBuffer();
547
- buffer.addText('rtl');
548
- buffer.setDirection('rtl');
549
- hb.shape(font, buffer)
550
- const glyphs = buffer.json();
551
- expect(glyphs[0].g).to.equal(79); // l
552
- expect(glyphs[1].g).to.equal(87); // t
553
- expect(glyphs[2].g).to.equal(85); // r
554
- });
555
-
556
- it('setClusterLevel affects cluster merging', function () {
557
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
558
- face = hb.createFace(blob);
559
- font = hb.createFont(face);
560
- buffer = hb.createBuffer();
561
- buffer.setClusterLevel(1);
562
- buffer.addText('x́');
563
- buffer.guessSegmentProperties();
564
- hb.shape(font, buffer)
565
- const glyphs = buffer.json();
566
- expect(glyphs[0].cl).to.equal(0);
567
- expect(glyphs[1].cl).to.equal(1);
568
- });
569
-
570
- it('setFlags with PRESERVE_DEFAULT_IGNORABLES affects glyph ids', function () {
571
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
572
- face = hb.createFace(blob);
573
- font = hb.createFont(face);
574
- buffer = hb.createBuffer();
575
- buffer.addText('\u200dhi');
576
- buffer.setFlags(['PRESERVE_DEFAULT_IGNORABLES']);
577
- buffer.guessSegmentProperties();
578
- hb.shape(font, buffer)
579
- const glyphs = buffer.json();
580
- expect(glyphs[0].g).not.to.equal(3 /* space */);
581
- });
582
-
583
- it('setFlags ignores invalid flags', function () {
584
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
585
- face = hb.createFace(blob);
586
- font = hb.createFont(face);
587
- buffer = hb.createBuffer();
588
- buffer.addText('abc');
589
- buffer.setFlags(['invalidFlag']);
590
- buffer.guessSegmentProperties();
591
- hb.shape(font, buffer)
592
- const glyphs = buffer.json();
593
- expect(glyphs[0].g).to.equal(68 /* a */);
594
- });
595
-
596
- it('setFlags with PRODUCE_SAFE_TO_INSERT_TATWEEL affects glyph flags', function () {
597
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansArabic-Variable.ttf')));
598
- face = hb.createFace(blob);
599
- font = hb.createFont(face);
600
- buffer = hb.createBuffer();
601
- buffer.addText('بلا');
602
- buffer.setFlags(['PRODUCE_SAFE_TO_INSERT_TATWEEL']);
603
- buffer.guessSegmentProperties();
604
- hb.shape(font, buffer)
605
- const flags = Array.from(buffer.json().map(g => g.flags));
606
- expect(flags).to.deep.equal([5, 0]);
607
-
608
- buffer.clearContents();
609
- buffer.addText('بلا');
610
- buffer.setFlags([]);
611
- buffer.guessSegmentProperties();
612
- hb.shape(font, buffer)
613
- const flags2 = Array.from(buffer.json().map(g => g.flags));
614
- expect(flags2).to.deep.equal([1, 0]);
615
- });
616
-
617
- it('serialize ignores invalid flags', function () {
618
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
619
- face = hb.createFace(blob);
620
- font = hb.createFont(face);
621
- buffer = hb.createBuffer();
622
- buffer.addText('abc');
623
- buffer.guessSegmentProperties();
624
- hb.shape(font, buffer)
625
- const glyphs = buffer.serialize(font, 0, null, "TEXT", ["invalidFlag"]);
626
- expect(glyphs).to.deep.equal("[a=0+561|b=1+615|c=2+480]");
627
- });
628
-
629
- it('reset resets the buffer', function () {
630
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
631
- face = hb.createFace(blob);
632
- font = hb.createFont(face);
633
- buffer = hb.createBuffer();
634
- buffer.addText('abc');
635
- buffer.guessSegmentProperties();
636
- expect(buffer.getContentType()).to.equal("UNICODE");
637
- hb.shape(font, buffer)
638
- expect(buffer.getContentType()).to.equal("GLYPHS");
639
- buffer.reset();
640
- expect(buffer.getContentType()).to.equal("INVALID");
641
- });
642
-
643
- it('getLength gets the length before and after shaping', function () {
644
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
645
- face = hb.createFace(blob);
646
- font = hb.createFont(face);
647
- buffer = hb.createBuffer();
648
- buffer.addText('fi');
649
- expect(buffer.getLength()).to.equal(2);
650
- buffer.guessSegmentProperties();
651
- hb.shape(font, buffer)
652
- expect(buffer.getLength()).to.equal(1);
653
- });
654
-
655
- it('getInfos and getPositions return empty arrays for empty buffer', function () {
656
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
657
- face = hb.createFace(blob);
658
- font = hb.createFont(face);
659
- buffer = hb.createBuffer();
660
- expect(buffer.getGlyphInfos()).to.deep.equal([]);
661
- expect(buffer.getGlyphPositions()).to.deep.equal([]);
662
- expect(buffer.getGlyphInfosAndPositions()).to.deep.equal([]);
663
- });
664
-
665
- it('getInfos and getPositions return non empty arrays for non empty buffer', function () {
666
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
667
- face = hb.createFace(blob);
668
- font = hb.createFont(face);
669
- buffer = hb.createBuffer();
670
- buffer.addText('x\u0300fi'); // combining mark and ligature to make the test more interesting
671
- buffer.guessSegmentProperties();
672
-
673
- // before shaping
674
- let infos = buffer.getGlyphInfos();
675
- let positions = buffer.getGlyphPositions();
676
- let infosAndPositions = buffer.getGlyphInfosAndPositions();
677
-
678
- expect(infos).to.deep.equal([
679
- { codepoint: 120, cluster: 0 },
680
- { codepoint: 768, cluster: 1 },
681
- { codepoint: 102, cluster: 2 },
682
- { codepoint: 105, cluster: 3 }
683
- ]);
684
- expect(positions).to.deep.equal([
685
- { x_advance: 0, y_advance: 0, x_offset: 0, y_offset: 0 },
686
- { x_advance: 0, y_advance: 0, x_offset: 0, y_offset: 0 },
687
- { x_advance: 0, y_advance: 0, x_offset: 0, y_offset: 0 },
688
- { x_advance: 0, y_advance: 0, x_offset: 0, y_offset: 0 }
689
- ]);
690
-
691
- for (let i = 0; i < infosAndPositions.length; i++) {
692
- expect(infosAndPositions[i]).to.deep.equal({ ...infos[i], ...positions[i] });
693
- }
694
-
695
- hb.shape(font, buffer);
696
- // after shaping
697
- infos = buffer.getGlyphInfos();
698
- positions = buffer.getGlyphPositions();
699
- infosAndPositions = buffer.getGlyphInfosAndPositions();
700
-
701
- expect(infos).to.deep.equal([
702
- { codepoint: 91, cluster: 0 },
703
- { codepoint: 2662, cluster: 0 },
704
- { codepoint: 1652, cluster: 2 }
705
- ]);
706
- expect(positions).to.deep.equal([
707
- { x_advance: 529, y_advance: 0, x_offset: 0, y_offset: 0 },
708
- { x_advance: 0, y_advance: 0, x_offset: 97, y_offset: 0 },
709
- { x_advance: 602, y_advance: 0, x_offset: 0, y_offset: 0 }
710
- ]);
711
- for (let i = 0; i < infosAndPositions.length; i++) {
712
- expect(infosAndPositions[i]).to.deep.equal({ ...infos[i], ...positions[i] });
713
- }
714
- });
715
-
716
- it('glyph infos and positions have private properties', function () {
717
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
718
- face = hb.createFace(blob);
719
- font = hb.createFont(face);
720
- buffer = hb.createBuffer();
721
- buffer.addText('fi');
722
- buffer.guessSegmentProperties();
723
- hb.shape(font, buffer);
724
- const infosAndPositions = buffer.getGlyphInfosAndPositions();
725
-
726
- expect(infosAndPositions.length).to.equal(1);
727
- expect(Object.keys(infosAndPositions[0])).to.deep.equal(['codepoint', 'cluster', 'x_advance', 'y_advance', 'x_offset', 'y_offset']);
728
- expect(infosAndPositions[0].mask).to.not.be.undefined;
729
- expect(infosAndPositions[0].var1).to.not.be.undefined;
730
- expect(infosAndPositions[0].var2).to.not.be.undefined;
731
- expect(infosAndPositions[0].var).to.not.be.undefined;
732
- });
733
-
734
- it('getPositions returns empty array for buffer without positions', function () {
735
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
736
- face = hb.createFace(blob);
737
- font = hb.createFont(face);
738
- buffer = hb.createBuffer();
739
- buffer.addText('abc');
740
- buffer.guessSegmentProperties();
741
- var currentPhase = "";
742
- buffer.setMessageFunc((buffer, font, message) => {
743
- if (message.startsWith("start table GSUB"))
744
- currentPhase = "GSUB";
745
- else if (message.startsWith("start table GPOS"))
746
- currentPhase = "GPOS";
747
-
748
- if (currentPhase === "GSUB")
749
- expect(buffer.getGlyphPositions()).to.deep.equal([]);
750
- else if (currentPhase === "GPOS")
751
- expect(buffer.getGlyphPositions()).to.not.deep.equal([]);
752
-
753
- return true;
754
- });
755
- hb.shape(font, buffer);
756
- });
757
-
758
- it('updateGlyphPositions updates the glyph positions', function () {
759
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
760
- face = hb.createFace(blob);
761
- font = hb.createFont(face);
762
- buffer = hb.createBuffer();
763
-
764
- // text with a base glyph and two marks to test mkmk after manually updating glyph positions
765
- var text = 'x\u0302\u0300';
766
-
767
- // without updateGlyphPositions
768
- buffer.addText(text);
769
- buffer.guessSegmentProperties();
770
- hb.shape(font, buffer);
771
- var positions = buffer.getGlyphPositions();
772
- expect(positions[1].y_offset).to.equal(0);
773
- expect(positions[2].y_offset).to.equal(229);
774
-
775
- // with updateGlyphPositions inside buffer message callback
776
- buffer.clearContents();
777
- buffer.addText(text);
778
- buffer.guessSegmentProperties();
779
- var currentPhase = "";
780
- buffer.setMessageFunc((buffer, font, message) => {
781
- if (message.startsWith("start table GSUB"))
782
- currentPhase = "GSUB";
783
- else if (message.startsWith("start table GPOS"))
784
- currentPhase = "GPOS";
785
-
786
- // modify the 2nd glyph y_offset after the last mark lookup and before mkmk lookups
787
- if (currentPhase === "GPOS" && message.startsWith("end lookup 4 feature 'mark'")) {
788
- var positions = buffer.getGlyphPositions();
789
- expect(positions[1].y_offset).to.equal(0);
790
- expect(positions[2].y_offset).to.equal(0);
791
- positions[1].y_offset += 10;
792
- buffer.updateGlyphPositions(positions);
793
- }
794
-
795
- return true;
796
- });
797
-
798
- hb.shape(font, buffer);
799
- var positions = buffer.getGlyphPositions();
800
-
801
- // both mark glyphs now be offset vertically by 10, since the second mark attaches to the first mark
802
- expect(positions[1].y_offset).to.equal(10);
803
- expect(positions[2].y_offset).to.equal(239);
804
- });
805
- });
806
-
807
- describe('shape', function () {
808
- it('shape Latin string', function () {
809
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
810
- face = hb.createFace(blob);
811
- font = hb.createFont(face);
812
- buffer = hb.createBuffer();
813
- buffer.addText('abc');
814
- buffer.guessSegmentProperties();
815
- hb.shape(font, buffer)
816
- const glyphs = buffer.json();
817
- expect(glyphs[0]).to.deep.equal({ cl: 0, g: 68, ax: 561, ay: 0, dx: 0, dy: 0, flags: 0 } /* a */);
818
- expect(glyphs[1]).to.deep.equal({ cl: 1, g: 69, ax: 615, ay: 0, dx: 0, dy: 0, flags: 0 } /* b */);
819
- expect(glyphs[2]).to.deep.equal({ cl: 2, g: 70, ax: 480, ay: 0, dx: 0, dy: 0, flags: 0 } /* c */);
820
- });
821
-
822
- it('shape Latin string code points', function () {
823
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
824
- face = hb.createFace(blob);
825
- font = hb.createFont(face);
826
- buffer = hb.createBuffer();
827
- buffer.addCodePoints([...'abc'].map(c => c.codePointAt(0)));
828
- buffer.guessSegmentProperties();
829
- hb.shape(font, buffer)
830
- const glyphs = buffer.json();
831
- expect(glyphs[0]).to.deep.equal({ cl: 0, g: 68, ax: 561, ay: 0, dx: 0, dy: 0, flags: 0 } /* a */);
832
- expect(glyphs[1]).to.deep.equal({ cl: 1, g: 69, ax: 615, ay: 0, dx: 0, dy: 0, flags: 0 } /* b */);
833
- expect(glyphs[2]).to.deep.equal({ cl: 2, g: 70, ax: 480, ay: 0, dx: 0, dy: 0, flags: 0 } /* c */);
834
- });
835
-
836
- it('shape Arabic string', function () {
837
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansArabic-Variable.ttf')));
838
- face = hb.createFace(blob);
839
- font = hb.createFont(face);
840
- buffer = hb.createBuffer();
841
- buffer.addText('أبجد');
842
- buffer.guessSegmentProperties();
843
- hb.shape(font, buffer)
844
- const glyphs = buffer.json();
845
- expect(glyphs[0]).to.deep.equal({ cl: 3, g: 213, ax: 532, ay: 0, dx: 0, dy: 0, flags: 1 } /* د */);
846
- expect(glyphs[1]).to.deep.equal({ cl: 2, g: 529, ax: 637, ay: 0, dx: 0, dy: 0, flags: 1 } /* ج */);
847
- expect(glyphs[2]).to.deep.equal({ cl: 1, g: 101, ax: 269, ay: 0, dx: 0, dy: 0, flags: 0 } /* ب */);
848
- expect(glyphs[3]).to.deep.equal({ cl: 0, g: 50, ax: 235, ay: 0, dx: 0, dy: 0, flags: 0 } /* أ */);
849
- });
850
-
851
- it('shape Arabic string item', function () {
852
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansArabic-Variable.ttf')));
853
- face = hb.createFace(blob);
854
- font = hb.createFont(face);
855
- buffer = hb.createBuffer();
856
- buffer.addText('أبجد', 1, 2);
857
- buffer.guessSegmentProperties();
858
- hb.shape(font, buffer)
859
- const glyphs = buffer.json();
860
- expect(glyphs[0]).to.deep.equal({ cl: 2, g: 529, ax: 637, ay: 0, dx: 0, dy: 0, flags: 1 } /* ج */);
861
- expect(glyphs[1]).to.deep.equal({ cl: 1, g: 101, ax: 269, ay: 0, dx: 0, dy: 0, flags: 0 } /* ب */);
862
- });
863
-
864
- it('shape Arabic code points item', function () {
865
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansArabic-Variable.ttf')));
866
- face = hb.createFace(blob);
867
- font = hb.createFont(face);
868
- buffer = hb.createBuffer();
869
- buffer.addCodePoints([...'أبجد'].map(c => c.codePointAt(0)), 1, 2);
870
- buffer.guessSegmentProperties();
871
- hb.shape(font, buffer)
872
- const glyphs = buffer.json();
873
- expect(glyphs[0]).to.deep.equal({ cl: 2, g: 529, ax: 637, ay: 0, dx: 0, dy: 0, flags: 1 } /* ج */);
874
- expect(glyphs[1]).to.deep.equal({ cl: 1, g: 101, ax: 269, ay: 0, dx: 0, dy: 0, flags: 0 } /* ب */);
875
- });
876
-
877
- it('shape with tracing', function () {
878
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
879
- face = hb.createFace(blob);
880
- font = hb.createFont(face);
881
- buffer = hb.createBuffer();
882
- buffer.addText('abc');
883
- buffer.guessSegmentProperties();
884
- const result = hb.shapeWithTrace(font, buffer, "", 0, 0)
885
- expect(result).to.have.lengthOf(59);
886
- expect(result[2]).to.deep.equal({
887
- "m": "start table GSUB script tag 'latn'",
888
- "glyphs": true,
889
- "t": [
890
- { cl: 0, g: 68 },
891
- { cl: 1, g: 69 },
892
- { cl: 2, g: 70 },
893
- ],
894
- });
895
- expect(result[58]).to.deep.equal({
896
- "m": "end table GPOS script tag 'latn'",
897
- "glyphs": true,
898
- "t": [
899
- { cl: 0, g: 68, ax: 561, ay: 0, dx: 0, dy: 0 },
900
- { cl: 1, g: 69, ax: 615, ay: 0, dx: 0, dy: 0 },
901
- { cl: 2, g: 70, ax: 480, ay: 0, dx: 0, dy: 0 },
902
- ],
903
- });
904
- });
905
-
906
- it('shape with tracing and features', function () {
907
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
908
- face = hb.createFace(blob);
909
- font = hb.createFont(face);
910
- buffer = hb.createBuffer();
911
- buffer.addText('fi AV');
912
- buffer.guessSegmentProperties();
913
- const result = hb.shapeWithTrace(font, buffer, "-liga,-kern", 0, 0)
914
- expect(result).to.have.lengthOf(46);
915
- expect(result[2]).to.deep.equal({
916
- "m": "start table GSUB script tag 'latn'",
917
- "glyphs": true,
918
- "t": [
919
- { cl: 0, g: 73 },
920
- { cl: 1, g: 76 },
921
- { cl: 2, g: 3 },
922
- { cl: 3, g: 36 },
923
- { cl: 4, g: 57 },
924
- ],
925
- });
926
- expect(result[45]).to.deep.equal({
927
- "m": "end table GPOS script tag 'latn'",
928
- "glyphs": true,
929
- "t": [
930
- { cl: 0, g: 73, ax: 344, ay: 0, dx: 0, dy: 0 },
931
- { cl: 1, g: 76, ax: 258, ay: 0, dx: 0, dy: 0 },
932
- { cl: 2, g: 3, ax: 260, ay: 0, dx: 0, dy: 0 },
933
- { cl: 3, g: 36, ax: 639, ay: 0, dx: 0, dy: 0 },
934
- { cl: 4, g: 57, ax: 600, ay: 0, dx: 0, dy: 0 },
935
- ],
936
- });
937
- });
938
-
939
- it('shape with 3-letter languae tag', function () {
940
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansDevanagari-Regular.otf')));
941
- face = hb.createFace(blob);
942
- font = hb.createFont(face);
943
- buffer = hb.createBuffer();
944
- buffer.addText('५ल');
945
- buffer.guessSegmentProperties();
946
- hb.shape(font, buffer)
947
- var glyphs = buffer.json();
948
- expect(glyphs).to.have.lengthOf(2);
949
- expect(glyphs[0].g).to.equal(118);
950
-
951
- buffer.clearContents();
952
- buffer.addText('५ल');
953
- buffer.setLanguage('dty');
954
- buffer.guessSegmentProperties();
955
- hb.shape(font, buffer)
956
- var glyphs = buffer.json();
957
- expect(glyphs).to.have.lengthOf(2);
958
- expect(glyphs[0].g).to.equal(123);
959
- });
960
-
961
- it('shape with OpenType language tag', function () {
962
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansDevanagari-Regular.otf')));
963
- face = hb.createFace(blob);
964
- font = hb.createFont(face);
965
- buffer = hb.createBuffer();
966
- buffer.addText('५ल');
967
- buffer.guessSegmentProperties();
968
- hb.shape(font, buffer)
969
- var glyphs = buffer.json();
970
- expect(glyphs).to.have.lengthOf(2);
971
- expect(glyphs[0].g).to.equal(118);
972
-
973
- buffer.clearContents();
974
- buffer.addText('५ल');
975
- buffer.setLanguage('x-hbot-4e455020'); // 'NEP '
976
- buffer.guessSegmentProperties();
977
- hb.shape(font, buffer)
978
- var glyphs = buffer.json();
979
- expect(glyphs).to.have.lengthOf(2);
980
- expect(glyphs[0].g).to.equal(123);
981
- });
982
- });
983
-
984
- describe('misc', function () {
985
- it('get version', function () {
986
- const version = hb.version();
987
- expect(version).to.have.property('major').that.is.a('number');
988
- expect(version).to.have.property('minor').that.is.a('number');
989
- expect(version).to.have.property('micro').that.is.a('number');
990
- expect(version.major).to.be.at.least(10);
991
- });
992
-
993
- it('get version string', function () {
994
- const version_string = hb.version_string();
995
- expect(version_string).to.match(/^\d+\.\d+\.\d+$/);
996
- });
997
-
998
- it('convert OpenType tag to script', function () {
999
- expect(hb.otTagToScript('arab')).to.equal('Arab');
1000
- expect(hb.otTagToScript('latn')).to.equal('Latn');
1001
- expect(hb.otTagToScript('dev2')).to.equal('Deva');
1002
- expect(hb.otTagToScript('nko ')).to.equal('Nkoo');
1003
- expect(hb.otTagToScript('DFLT')).to.equal('\0\0\0\0');
1004
- });
1005
-
1006
- it('convert OpenType tag to language', function () {
1007
- expect(hb.otTagToLanguage('ARA ')).to.equal('ar');
1008
- expect(hb.otTagToLanguage('ENG ')).to.equal('en');
1009
- expect(hb.otTagToLanguage('BAD0')).to.equal('bad');
1010
- expect(hb.otTagToLanguage('SYRE')).to.equal('und-syre');
1011
- });
1012
-
1013
- it("test that calling functions repeatedly doesn't exhaust memory", function () {
1014
- blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
1015
- face = hb.createFace(blob);
1016
- font = hb.createFont(face);
1017
- for (let i = 0; i < 10000; i++) {
1018
- expect(face.listNames()).to.not.be.null;
1019
- expect(face.getName(0, "en")).to.not.be.null;
1020
- expect(font.hExtents()).to.not.be.null;
1021
- expect(font.vExtents()).to.not.be.null;
1022
- expect(font.glyphHOrigin(0)).to.not.be.null;
1023
- expect(font.glyphVOrigin(0)).to.be.null;
1024
- expect(font.glyphExtents(0)).to.not.be.null;
1025
- expect(font.glyphFromName("a")).to.not.be.null;
1026
- for (let tableTag of ["GSUB", "GPOS"]) {
1027
- expect(face.getTableFeatureTags(tableTag)).to.not.be.null;
1028
- expect(face.getTableScriptTags(tableTag)).to.not.be.null;
1029
- expect(face.getScriptLanguageTags(tableTag, 0)).to.not.be.null;
1030
- expect(face.getLanguageFeatureTags(tableTag, 0, 0)).to.not.be.null;
1031
- if (tableTag === "GSUB") {
1032
- expect(face.getFeatureNameIds(tableTag, 50)).to.not.be.null;
1033
- } else {
1034
- expect(face.getFeatureNameIds(tableTag, 50)).to.be.null;
1035
- }
1036
- }
1037
- }
1038
- });
1039
- });
1040
-