harfbuzzjs 0.4.15 → 0.6.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,37 +1,38 @@
1
1
  {
2
- "name": "harfbuzzjs",
3
- "version": "0.4.15",
4
- "description": "Minimal version of HarfBuzz for JavaScript use",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "mocha test/index.js"
8
- },
9
- "keywords": [
10
- "harfbuzz",
11
- "opentype",
12
- "truetype",
13
- "ttf",
14
- "otf",
15
- "graphics",
16
- "complex scripts",
17
- "typography",
18
- "font rendering",
19
- "font",
20
- "fonts",
21
- "emoji"
22
- ],
23
- "repository": {
24
- "type": "git",
25
- "url": "git+https://github.com/harfbuzz/harfbuzzjs.git"
26
- },
27
- "author": "Ebrahim Byagowi <ebrahim@gnu.org>",
28
- "license": "MIT",
29
- "bugs": {
30
- "url": "https://github.com/harfbuzz/harfbuzzjs/issues"
31
- },
32
- "homepage": "https://github.com/harfbuzz/harfbuzzjs#readme",
33
- "devDependencies": {
34
- "chai": "^4.3.7",
35
- "mocha": "^10.2.0"
36
- }
37
- }
2
+ "name": "harfbuzzjs",
3
+ "version": "0.6.0",
4
+ "description": "Minimal version of HarfBuzz for JavaScript use",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "prepare": "make",
8
+ "test": "make test"
9
+ },
10
+ "keywords": [
11
+ "harfbuzz",
12
+ "opentype",
13
+ "truetype",
14
+ "ttf",
15
+ "otf",
16
+ "graphics",
17
+ "complex scripts",
18
+ "typography",
19
+ "font rendering",
20
+ "font",
21
+ "fonts",
22
+ "emoji"
23
+ ],
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/harfbuzz/harfbuzzjs.git"
27
+ },
28
+ "author": "Ebrahim Byagowi <ebrahim@gnu.org>",
29
+ "license": "MIT",
30
+ "bugs": {
31
+ "url": "https://github.com/harfbuzz/harfbuzzjs/issues"
32
+ },
33
+ "homepage": "https://github.com/harfbuzz/harfbuzzjs#readme",
34
+ "devDependencies": {
35
+ "chai": "^4.3.7",
36
+ "mocha": "^10.2.0"
37
+ }
38
+ }
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')));
@@ -169,6 +586,20 @@ describe('shape', function () {
169
586
  expect(glyphs[2]).to.deep.equal({ cl: 2, g: 70, ax: 480, ay: 0, dx: 0, dy: 0, flags: 0 } /* c */);
170
587
  });
171
588
 
589
+ it('shape Latin string code points', function () {
590
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
591
+ face = hb.createFace(blob);
592
+ font = hb.createFont(face);
593
+ buffer = hb.createBuffer();
594
+ buffer.addCodePoints([...'abc'].map(c => c.codePointAt(0)));
595
+ buffer.guessSegmentProperties();
596
+ hb.shape(font, buffer)
597
+ const glyphs = buffer.json();
598
+ expect(glyphs[0]).to.deep.equal({ cl: 0, g: 68, ax: 561, ay: 0, dx: 0, dy: 0, flags: 0 } /* a */);
599
+ expect(glyphs[1]).to.deep.equal({ cl: 1, g: 69, ax: 615, ay: 0, dx: 0, dy: 0, flags: 0 } /* b */);
600
+ expect(glyphs[2]).to.deep.equal({ cl: 2, g: 70, ax: 480, ay: 0, dx: 0, dy: 0, flags: 0 } /* c */);
601
+ });
602
+
172
603
  it('shape Arabic string', function () {
173
604
  blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansArabic-Variable.ttf')));
174
605
  face = hb.createFace(blob);
@@ -184,6 +615,32 @@ describe('shape', function () {
184
615
  expect(glyphs[3]).to.deep.equal({ cl: 0, g: 50, ax: 235, ay: 0, dx: 0, dy: 0, flags: 0 } /* أ */);
185
616
  });
186
617
 
618
+ it('shape Arabic string item', function () {
619
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansArabic-Variable.ttf')));
620
+ face = hb.createFace(blob);
621
+ font = hb.createFont(face);
622
+ buffer = hb.createBuffer();
623
+ buffer.addText('أبجد', 1, 2);
624
+ buffer.guessSegmentProperties();
625
+ hb.shape(font, buffer)
626
+ const glyphs = buffer.json();
627
+ expect(glyphs[0]).to.deep.equal({ cl: 2, g: 529, ax: 637, ay: 0, dx: 0, dy: 0, flags: 1 } /* ج */);
628
+ expect(glyphs[1]).to.deep.equal({ cl: 1, g: 101, ax: 269, ay: 0, dx: 0, dy: 0, flags: 0 } /* ب */);
629
+ });
630
+
631
+ it('shape Arabic code points item', function () {
632
+ blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSansArabic-Variable.ttf')));
633
+ face = hb.createFace(blob);
634
+ font = hb.createFont(face);
635
+ buffer = hb.createBuffer();
636
+ buffer.addCodePoints([...'أبجد'].map(c => c.codePointAt(0)), 1, 2);
637
+ buffer.guessSegmentProperties();
638
+ hb.shape(font, buffer)
639
+ const glyphs = buffer.json();
640
+ expect(glyphs[0]).to.deep.equal({ cl: 2, g: 529, ax: 637, ay: 0, dx: 0, dy: 0, flags: 1 } /* ج */);
641
+ expect(glyphs[1]).to.deep.equal({ cl: 1, g: 101, ax: 269, ay: 0, dx: 0, dy: 0, flags: 0 } /* ب */);
642
+ });
643
+
187
644
  it('shape with tracing', function () {
188
645
  blob = hb.createBlob(fs.readFileSync(path.join(__dirname, 'fonts/noto/NotoSans-Regular.ttf')));
189
646
  face = hb.createFace(blob);
package/build-subset.sh DELETED
@@ -1,20 +0,0 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- em++ \
5
- -std=c++11 \
6
- -fno-exceptions \
7
- -fno-rtti \
8
- -fno-threadsafe-statics \
9
- -fvisibility-inlines-hidden \
10
- -Oz \
11
- -I. \
12
- -DHB_TINY \
13
- -DHB_USE_INTERNAL_QSORT \
14
- -DHB_CONFIG_OVERRIDE_H=\"config-override-subset.h\" \
15
- -DHB_EXPERIMENTAL_API \
16
- --no-entry \
17
- -s EXPORTED_FUNCTIONS=@hb-subset.symbols \
18
- -s INITIAL_MEMORY=65MB \
19
- -o hb-subset.wasm \
20
- harfbuzz/src/harfbuzz-subset.cc
package/build.sh DELETED
@@ -1,27 +0,0 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- em++ \
5
- -std=c++11 \
6
- -fno-exceptions \
7
- -fno-rtti \
8
- -fno-threadsafe-statics \
9
- -fvisibility-inlines-hidden \
10
- -flto \
11
- -Oz \
12
- -I. \
13
- -DHB_TINY \
14
- -DHB_USE_INTERNAL_QSORT \
15
- -DHB_CONFIG_OVERRIDE_H=\"config-override.h\" \
16
- -DHB_EXPERIMENTAL_API \
17
- --no-entry \
18
- -s MODULARIZE \
19
- -s EXPORT_NAME=createHarfBuzz \
20
- -s EXPORTED_FUNCTIONS=@hb.symbols \
21
- -s EXPORTED_RUNTIME_METHODS='["addFunction", "removeFunction", "wasmMemory", "wasmExports", "HEAP8", "HEAPU8", "HEAP32", "HEAPU32", "HEAPF32"]' \
22
- -s INITIAL_MEMORY=256KB \
23
- -s ALLOW_MEMORY_GROWTH \
24
- -s ALLOW_TABLE_GROWTH \
25
- -lexports.js \
26
- -o hb.js \
27
- harfbuzz/src/harfbuzz.cc