harfbuzzjs 0.4.15 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harfbuzzjs",
3
- "version": "0.4.15",
3
+ "version": "0.5.0",
4
4
  "description": "Minimal version of HarfBuzz for JavaScript use",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/test/index.js CHANGED
@@ -2,7 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { expect } = require('chai');
4
4
  let hb;
5
- let blob, face, font, buffer;
5
+ let blob, face, font, buffer, fontFuncs;
6
6
 
7
7
  before(async function () {
8
8
  hb = await require('..');
@@ -13,7 +13,8 @@ afterEach(function () {
13
13
  if (face) face.destroy();
14
14
  if (font) font.destroy();
15
15
  if (buffer) buffer.destroy();
16
- blob = face = font = buffer = undefined;
16
+ if (fontFuncs) fontFuncs.destroy();
17
+ blob = face = font = buffer = fontFuncs = undefined;
17
18
  });
18
19
 
19
20
  describe('Face', function () {
@@ -45,9 +46,177 @@ describe('Face', function () {
45
46
  face = hb.createFace(blob);
46
47
  expect(Object.keys(face.getAxisInfos())).to.have.lengthOf(0);
47
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('listNames fetches all names', function () {
115
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
116
+ face = hb.createFace(blob);
117
+ let names = face.listNames();
118
+ expect(names.length).to.equal(38);
119
+ expect(names[0]).to.deep.equal({ nameId: 0, language: 'en' });
120
+ expect(names[37]).to.deep.equal({ nameId: 278, language: 'en' });
121
+ })
122
+
123
+ it('getName fetches a name', function () {
124
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
125
+ face = hb.createFace(blob);
126
+ expect(face.getName(1, 'en')).to.equal('Noto Sans');
127
+ expect(face.getName(256, 'en')).to.equal('florin symbol');
128
+ })
129
+
130
+ it('getFeatureNameIds returns valid name Ids for ssNN features', function () {
131
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
132
+ face = hb.createFace(blob);
133
+ expect(face.getFeatureNameIds("GSUB",
134
+ face.getTableFeatureTags("GSUB").indexOf("ss03"))).to.deep.equal({
135
+ uiLabelNameId: 256,
136
+ uiTooltipTextNameId: null,
137
+ sampleTextNameId: null,
138
+ paramUiLabelNameIds: []
139
+ });
140
+ })
141
+
142
+ it('getFeatureNameIds with getName', function () {
143
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
144
+ face = hb.createFace(blob);
145
+ expect(face.getName(face.getFeatureNameIds("GSUB",
146
+ face.getTableFeatureTags("GSUB").indexOf("ss03")).uiLabelNameId, 'en')).to.equal('florin symbol');
147
+ })
148
+
149
+ it('getFeatureNameIds not found', function () {
150
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
151
+ face = hb.createFace(blob);
152
+ expect(face.getFeatureNameIds("GSUB",
153
+ face.getTableFeatureTags("GSUB").indexOf("salt"))).to.equal(null);
154
+ })
155
+
156
+ it('getFeatureNameIds returns valid name Ids for cvNN features', function () {
157
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, '../harfbuzz/test/api/fonts/cv01.otf')));
158
+ face = hb.createFace(blob);
159
+ expect(face.getFeatureNameIds("GSUB",
160
+ face.getTableFeatureTags("GSUB").indexOf("cv01"))).to.deep.equal({
161
+ uiLabelNameId: 256,
162
+ uiTooltipTextNameId: 257,
163
+ sampleTextNameId: 258,
164
+ paramUiLabelNameIds: [259, 260]
165
+ });
166
+ })
48
167
  });
49
168
 
50
169
  describe('Font', function () {
170
+ it('subFont creates a sub font', function () {
171
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
172
+ face = hb.createFace(blob);
173
+ font = hb.createFont(face);
174
+ let subFont = font.subFont();
175
+ expect(subFont.ptr).to.not.equal(font.ptr);
176
+ subFont.destroy();
177
+ });
178
+
179
+ it('subFont font funcs fallback to parent', function () {
180
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
181
+ face = hb.createFace(blob);
182
+ font = hb.createFont(face);
183
+ let subFont = font.subFont();
184
+ expect(subFont.ptr).to.not.equal(font.ptr);
185
+
186
+ fontFuncs = hb.createFontFuncs();
187
+ fontFuncs.setGlyphNameFunc(function (font_, glyph) {
188
+ expect(font_.ptr).to.equal(subFont.ptr);
189
+ return null;
190
+ });
191
+ subFont.setFuncs(fontFuncs);
192
+
193
+ expect(subFont.glyphName(20)).to.equal("gid20");
194
+ expect(subFont.glyphHAdvance(20)).to.equal(font.glyphHAdvance(20));
195
+ subFont.destroy();
196
+ });
197
+
198
+ it('hExtents returns extents for the font', function () {
199
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
200
+ face = hb.createFace(blob);
201
+ font = hb.createFont(face);
202
+ expect(font.hExtents()).to.deep.equal({
203
+ ascender: 1069,
204
+ descender: -293,
205
+ lineGap: 0
206
+ });
207
+ });
208
+
209
+ it('vExtents returns extents for the font', function () {
210
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
211
+ face = hb.createFace(blob);
212
+ font = hb.createFont(face);
213
+ expect(font.vExtents()).to.deep.equal({
214
+ ascender: 0,
215
+ descender: 0,
216
+ lineGap: 0
217
+ });
218
+ });
219
+
51
220
  it('glyphName returns names for glyph ids', function () {
52
221
  blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
53
222
  face = hb.createFace(blob);
@@ -68,6 +237,54 @@ describe('Font', function () {
68
237
  expect(glyphs[0].ax).to.equal(561 * 2);
69
238
  });
70
239
 
240
+ it('glyphExtents returns extents for glyph ids', function () {
241
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
242
+ face = hb.createFace(blob);
243
+ font = hb.createFont(face);
244
+ expect(font.glyphExtents(20)).to.deep.equal({
245
+ xBearing: 89,
246
+ yBearing: 714,
247
+ width: 266,
248
+ height: -714
249
+ });
250
+ });
251
+
252
+ it('glyphHAdvance returns advances for glyph ids', function () {
253
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
254
+ face = hb.createFace(blob);
255
+ font = hb.createFont(face);
256
+ expect(font.glyphHAdvance(20)).to.equal(572);
257
+ });
258
+
259
+ it('glyphVAdvance returns advances for glyph ids', function () {
260
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
261
+ face = hb.createFace(blob);
262
+ font = hb.createFont(face);
263
+ expect(font.glyphVAdvance(20)).to.equal(-1000);
264
+ });
265
+
266
+ it('glyphHOrigin returns origins for glyph ids', function () {
267
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
268
+ face = hb.createFace(blob);
269
+ font = hb.createFont(face);
270
+ expect(font.glyphHOrigin(20)).to.deep.equal([0, 0]);
271
+ });
272
+
273
+ it('glyphVOrigin returns origins for glyph ids', function () {
274
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
275
+ face = hb.createFace(blob);
276
+ font = hb.createFont(face);
277
+ expect(font.glyphVOrigin(20)).to.equal(null);
278
+ });
279
+
280
+ it('glyphFromName returns ids for glyph names', function () {
281
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
282
+ face = hb.createFace(blob);
283
+ font = hb.createFont(face);
284
+ expect(font.glyphFromName('one')).to.equal(20);
285
+ expect(font.glyphFromName('NonExistentGlyph')).to.equal(null);
286
+ });
287
+
71
288
  it('setVariations affects advances', function () {
72
289
  blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansArabic-Variable.ttf')));
73
290
  face = hb.createFace(blob);
@@ -111,6 +328,206 @@ describe('Font', function () {
111
328
  });
112
329
  });
113
330
 
331
+ describe('FontFuncs', function () {
332
+ it('setGlyphExtentsFunc', function () {
333
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
334
+ face = hb.createFace(blob);
335
+ font = hb.createFont(face);
336
+ fontFuncs = hb.createFontFuncs();
337
+ fontFuncs.setGlyphExtentsFunc(function (font_, glyph) {
338
+ expect(font_.ptr).to.equal(font.ptr);
339
+ return {
340
+ xBearing: glyph,
341
+ yBearing: 0,
342
+ width: 100 * glyph,
343
+ height: 100
344
+ };
345
+ });
346
+ font.setFuncs(fontFuncs);
347
+ expect(font.glyphExtents(0)).to.deep.equal({
348
+ xBearing: 0,
349
+ yBearing: 0,
350
+ width: 0,
351
+ height: 100
352
+ });
353
+ expect(font.glyphExtents(20)).to.deep.equal({
354
+ xBearing: 20,
355
+ yBearing: 0,
356
+ width: 2000,
357
+ height: 100
358
+ });
359
+ });
360
+
361
+ it('setGlyphFromNameFunc', function () {
362
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
363
+ face = hb.createFace(blob);
364
+ font = hb.createFont(face);
365
+ fontFuncs = hb.createFontFuncs();
366
+ fontFuncs.setGlyphFromNameFunc(function (font_, name) {
367
+ expect(font_.ptr).to.equal(font.ptr);
368
+ return name == 'one' ? 20 : null;
369
+ });
370
+ font.setFuncs(fontFuncs);
371
+ expect(font.glyphFromName('one')).to.equal(20);
372
+ expect(font.glyphFromName('two')).to.equal(null);
373
+ });
374
+
375
+ it('setGlyphHAdvanceFunc', function () {
376
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
377
+ face = hb.createFace(blob);
378
+ font = hb.createFont(face);
379
+ fontFuncs = hb.createFontFuncs();
380
+ fontFuncs.setGlyphHAdvanceFunc(function (font_, glyph) {
381
+ expect(font_.ptr).to.equal(font.ptr);
382
+ return glyph == 20 ? 100 : 200;
383
+ });
384
+ font.setFuncs(fontFuncs);
385
+ expect(font.glyphHAdvance(20)).to.equal(100);
386
+ expect(font.glyphHAdvance(21)).to.equal(200);
387
+ });
388
+
389
+ it('setGlyphVAdvanceFunc', function () {
390
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
391
+ face = hb.createFace(blob);
392
+ font = hb.createFont(face);
393
+ fontFuncs = hb.createFontFuncs();
394
+ fontFuncs.setGlyphVAdvanceFunc(function (font_, glyph) {
395
+ expect(font_.ptr).to.equal(font.ptr);
396
+ return glyph == 20 ? 100 : 200;
397
+ });
398
+ font.setFuncs(fontFuncs);
399
+ expect(font.glyphVAdvance(20)).to.equal(100);
400
+ expect(font.glyphVAdvance(21)).to.equal(200);
401
+ });
402
+
403
+ it('setGlyphHOriginFunc', function () {
404
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
405
+ face = hb.createFace(blob);
406
+ font = hb.createFont(face);
407
+ fontFuncs = hb.createFontFuncs();
408
+ fontFuncs.setGlyphHOriginFunc(function (font_, glyph) {
409
+ expect(font_.ptr).to.equal(font.ptr);
410
+ return glyph == 20 ? [100, 200] : [300, 400];
411
+ });
412
+ font.setFuncs(fontFuncs);
413
+ expect(font.glyphHOrigin(20)).to.deep.equal([100, 200]);
414
+ expect(font.glyphHOrigin(21)).to.deep.equal([300, 400]);
415
+ });
416
+
417
+ it('setGlyphVOriginFunc', function () {
418
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
419
+ face = hb.createFace(blob);
420
+ font = hb.createFont(face);
421
+ fontFuncs = hb.createFontFuncs();
422
+ fontFuncs.setGlyphVOriginFunc(function (font_, glyph) {
423
+ expect(font_.ptr).to.equal(font.ptr);
424
+ return glyph == 20 ? [100, 200] : [300, 400];
425
+ });
426
+ font.setFuncs(fontFuncs);
427
+ expect(font.glyphVOrigin(20)).to.deep.equal([100, 200]);
428
+ expect(font.glyphVOrigin(21)).to.deep.equal([300, 400]);
429
+ });
430
+
431
+ it('setGlyphNameFunc', function () {
432
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
433
+ face = hb.createFace(blob);
434
+ font = hb.createFont(face);
435
+ fontFuncs = hb.createFontFuncs();
436
+ fontFuncs.setGlyphNameFunc(function (font_, glyph) {
437
+ expect(font_.ptr).to.equal(font.ptr);
438
+ return glyph == 20 ? 'one' : null;
439
+ });
440
+ font.setFuncs(fontFuncs);
441
+ expect(font.glyphName(20)).to.equal('one');
442
+ expect(font.glyphName(21)).to.equal('gid21');
443
+ });
444
+
445
+ it('setNominalGlyphFunc', function () {
446
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
447
+ face = hb.createFace(blob);
448
+ font = hb.createFont(face);
449
+ fontFuncs = hb.createFontFuncs();
450
+ fontFuncs.setNominalGlyphFunc(function (font_, unicode) {
451
+ expect(font_.ptr).to.equal(font.ptr);
452
+ return unicode == 49 ? 21 : 22;
453
+ });
454
+ font.setFuncs(fontFuncs);
455
+ buffer = hb.createBuffer();
456
+ buffer.addText('12');
457
+ buffer.guessSegmentProperties();
458
+ hb.shape(font, buffer)
459
+ const glyphs = buffer.json();
460
+ expect(glyphs[0].g).to.equal(21);
461
+ expect(glyphs[1].g).to.equal(22);
462
+ });
463
+
464
+ it('setVariationGlyphFunc', function () {
465
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
466
+ face = hb.createFace(blob);
467
+ font = hb.createFont(face);
468
+ fontFuncs = hb.createFontFuncs();
469
+ fontFuncs.setNominalGlyphFunc(function (font_, unicode) {
470
+ expect(font_.ptr).to.equal(font.ptr);
471
+ return unicode == 49 ? 21 : 22;
472
+ });
473
+ fontFuncs.setVariationGlyphFunc(function (font_, unicode, variationSelector) {
474
+ expect(font_.ptr).to.equal(font.ptr);
475
+ return unicode == 49 ? 23 : null;
476
+ });
477
+ font.setFuncs(fontFuncs);
478
+ buffer = hb.createBuffer();
479
+ buffer.addText('11\uFE002\uFE00');
480
+ buffer.guessSegmentProperties();
481
+ hb.shape(font, buffer)
482
+ const glyphs = buffer.json();
483
+ expect(glyphs[0].g).to.equal(21);
484
+ expect(glyphs[1].g).to.equal(23);
485
+ expect(glyphs[2].g).to.equal(22);
486
+ });
487
+
488
+ it('setFontHExtentsFunc', function () {
489
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
490
+ face = hb.createFace(blob);
491
+ font = hb.createFont(face);
492
+ fontFuncs = hb.createFontFuncs();
493
+ fontFuncs.setFontHExtentsFunc(function (font_) {
494
+ expect(font_.ptr).to.equal(font.ptr);
495
+ return {
496
+ ascender: 100,
497
+ descender: 200,
498
+ lineGap: 300,
499
+ };
500
+ });
501
+ font.setFuncs(fontFuncs);
502
+ expect(font.hExtents()).to.deep.equal({
503
+ ascender: 100,
504
+ descender: 200,
505
+ lineGap: 300,
506
+ });
507
+ });
508
+
509
+ it('setFontVExtentsFunc', function () {
510
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
511
+ face = hb.createFace(blob);
512
+ font = hb.createFont(face);
513
+ fontFuncs = hb.createFontFuncs();
514
+ fontFuncs.setFontVExtentsFunc(function (font_) {
515
+ expect(font_.ptr).to.equal(font.ptr);
516
+ return {
517
+ ascender: 100,
518
+ descender: 200,
519
+ lineGap: 300,
520
+ };
521
+ });
522
+ font.setFuncs(fontFuncs);
523
+ expect(font.vExtents()).to.deep.equal({
524
+ ascender: 100,
525
+ descender: 200,
526
+ lineGap: 300,
527
+ });
528
+ });
529
+ });
530
+
114
531
  describe('Buffer', function () {
115
532
  it('setDirection controls direction of glyphs', function () {
116
533
  blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));