harfbuzzjs 0.3.0 → 0.3.2
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/build-subset.sh +1 -2
- package/config-override-subset.h +1 -0
- package/config-override.h +1 -0
- package/examples/hb-subset.example.node.js +33 -14
- package/examples/hbjs.example.js +3 -1
- package/harfbuzz.ts +46 -0
- package/hb-subset.symbols +4 -0
- package/hb-subset.wasm +0 -0
- package/hb.wasm +0 -0
- package/hbjs.js +47 -0
- package/hbjs.symbols +5 -0
- package/package.json +1 -1
- package/.github/workflows/build.yml +0 -45
- package/.gitmodules +0 -3
- package/wapm.toml +0 -8
package/build-subset.sh
CHANGED
package/config-override-subset.h
CHANGED
package/config-override.h
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
// Based on https://github.com/harfbuzz/harfbuzzjs/issues/9#issuecomment-507874962
|
|
2
2
|
// Which was based on https://github.com/harfbuzz/harfbuzzjs/issues/9#issuecomment-507622485
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
3
|
+
const { readFile, writeFile } = require('fs').promises;
|
|
4
|
+
const { join, extname, basename } = require('path');
|
|
5
|
+
const { performance } = require('node:perf_hooks');
|
|
6
|
+
|
|
7
|
+
const SUBSET_TEXT = 'abc';
|
|
6
8
|
|
|
7
9
|
(async () => {
|
|
8
|
-
const { instance: { exports } } = await WebAssembly.instantiate(await
|
|
9
|
-
const
|
|
10
|
+
const { instance: { exports } } = await WebAssembly.instantiate(await readFile(join(__dirname, '../hb-subset.wasm')));
|
|
11
|
+
const fileName = 'Roboto-Black.ttf';
|
|
12
|
+
const fontBlob = await readFile(join(__dirname, '/', fileName));
|
|
10
13
|
|
|
14
|
+
const t = performance.now();
|
|
11
15
|
const heapu8 = new Uint8Array(exports.memory.buffer);
|
|
12
16
|
const fontBuffer = exports.malloc(fontBlob.byteLength);
|
|
13
17
|
heapu8.set(new Uint8Array(fontBlob), fontBuffer);
|
|
@@ -20,9 +24,9 @@ const writeFileAsync = require('util').promisify(fs.writeFile);
|
|
|
20
24
|
/* Add your glyph indices here and subset */
|
|
21
25
|
const input = exports.hb_subset_input_create_or_fail();
|
|
22
26
|
const unicode_set = exports.hb_subset_input_unicode_set(input);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
for (const text of SUBSET_TEXT) {
|
|
28
|
+
exports.hb_set_add(unicode_set, text.codePointAt(0));
|
|
29
|
+
}
|
|
26
30
|
|
|
27
31
|
// exports.hb_subset_input_set_drop_hints(input, true);
|
|
28
32
|
const subset = exports.hb_subset_or_fail(face, input);
|
|
@@ -31,16 +35,31 @@ const writeFileAsync = require('util').promisify(fs.writeFile);
|
|
|
31
35
|
exports.hb_subset_input_destroy(input);
|
|
32
36
|
|
|
33
37
|
/* Get result blob */
|
|
34
|
-
const
|
|
38
|
+
const resultBlob = exports.hb_face_reference_blob(subset);
|
|
35
39
|
|
|
36
|
-
const
|
|
37
|
-
const
|
|
40
|
+
const offset = exports.hb_blob_get_data(resultBlob, 0);
|
|
41
|
+
const subsetByteLength = exports.hb_blob_get_length(resultBlob);
|
|
42
|
+
if (subsetByteLength === 0) {
|
|
43
|
+
exports.hb_blob_destroy(resultBlob);
|
|
44
|
+
exports.hb_face_destroy(subset);
|
|
45
|
+
exports.hb_face_destroy(face);
|
|
46
|
+
exports.free(fontBuffer);
|
|
47
|
+
throw new Error(
|
|
48
|
+
'Failed to create subset font, maybe the input file is corrupted?'
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Output font data(Uint8Array)
|
|
53
|
+
const subsetFontBlob = heapu8.subarray(offset, offset + exports.hb_blob_get_length(resultBlob));
|
|
54
|
+
console.info('✨ Subset done in', performance.now() - t, 'ms');
|
|
38
55
|
|
|
39
|
-
|
|
40
|
-
|
|
56
|
+
const extName = extname(fileName).toLowerCase();
|
|
57
|
+
const fontName = basename(fileName, extName);
|
|
58
|
+
await writeFile(join(__dirname, '/', `${fontName}.subset${extName}`), subsetFontBlob);
|
|
59
|
+
console.info(`Wrote subset to: ${__dirname}/${fontName}.subset${extName}`);
|
|
41
60
|
|
|
42
61
|
/* Clean up */
|
|
43
|
-
exports.hb_blob_destroy(
|
|
62
|
+
exports.hb_blob_destroy(resultBlob);
|
|
44
63
|
exports.hb_face_destroy(subset);
|
|
45
64
|
exports.hb_face_destroy(face);
|
|
46
65
|
exports.free(fontBuffer);
|
package/examples/hbjs.example.js
CHANGED
|
@@ -24,11 +24,13 @@ function example(hb, fontBlob, text) {
|
|
|
24
24
|
};
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
+
var unicodes = face.collectUnicodes()
|
|
28
|
+
|
|
27
29
|
buffer.destroy();
|
|
28
30
|
font.destroy();
|
|
29
31
|
face.destroy();
|
|
30
32
|
blob.destroy();
|
|
31
|
-
return { shape: result, glyphs: glyphs };
|
|
33
|
+
return { shape: result, glyphs: glyphs, unicodes: unicodes };
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
// Should be replaced with something more reliable
|
package/harfbuzz.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
type Pointer = number;
|
|
2
2
|
|
|
3
3
|
const HB_MEMORY_MODE_WRITABLE: number = 2;
|
|
4
|
+
const HB_SET_VALUE_INVALID: Pointer = -1;
|
|
4
5
|
|
|
5
6
|
class HarfBuzzExports {
|
|
6
7
|
readonly heapu8: Uint8Array;
|
|
@@ -20,6 +21,16 @@ class HarfBuzzExports {
|
|
|
20
21
|
readonly hb_font_create: (facePtr: Pointer) => Pointer
|
|
21
22
|
readonly hb_font_set_scale: (fontPtr: Pointer, xScale: number, yScale: number) => void
|
|
22
23
|
readonly hb_font_destroy: (ptr: Pointer) => void
|
|
24
|
+
readonly hb_face_collect_unicodes: (facePtr: Pointer, setPtr: Pointer) => void
|
|
25
|
+
readonly hb_set_create: () => Pointer
|
|
26
|
+
readonly hb_set_destroy: (setPtr: Pointer) => void
|
|
27
|
+
readonly hb_set_get_population: (setPtr: Pointer) => number
|
|
28
|
+
readonly hb_set_next_many: (
|
|
29
|
+
setPtr: Pointer,
|
|
30
|
+
greaterThanUnicodePtr: Pointer,
|
|
31
|
+
outputU32ArrayPtr: Pointer,
|
|
32
|
+
size: number,
|
|
33
|
+
) => number
|
|
23
34
|
readonly hb_buffer_create: () => Pointer
|
|
24
35
|
readonly hb_buffer_add_utf8: (bufferPtr: Pointer, stringPtr: Pointer, stringLength: number, itemOffset: number, itemLength: number) => void
|
|
25
36
|
readonly hb_buffer_guess_segment_properties: (bufferPtr: Pointer) => void
|
|
@@ -44,6 +55,11 @@ class HarfBuzzExports {
|
|
|
44
55
|
this.hb_face_create = exports.hb_face_create;
|
|
45
56
|
this.hb_face_get_upem = exports.hb_face_get_upem;
|
|
46
57
|
this.hb_face_destroy = exports.hb_face_destroy;
|
|
58
|
+
this.hb_face_collect_unicodes = exports.hb_face_collect_unicodes;
|
|
59
|
+
this.hb_set_create = exports.hb_set_create;
|
|
60
|
+
this.hb_set_destroy = exports.hb_set_destroy;
|
|
61
|
+
this.hb_set_get_population = exports.hb_set_get_population;
|
|
62
|
+
this.hb_set_next_many = exports.hb_set_next_many;
|
|
47
63
|
this.hb_font_create = exports.hb_font_create;
|
|
48
64
|
this.hb_font_set_scale = exports.hb_font_set_scale;
|
|
49
65
|
this.hb_font_destroy = exports.hb_font_destroy;
|
|
@@ -92,6 +108,28 @@ export class HarfBuzzBlob {
|
|
|
92
108
|
}
|
|
93
109
|
}
|
|
94
110
|
|
|
111
|
+
function typedArrayFromSet<T extends 'u8' | 'u32' | 'i32'>(setPtr: Pointer, arrayType: T) {
|
|
112
|
+
const heap = hb[`heap${arrayType}`];
|
|
113
|
+
const bytesPerElment = heap.BYTES_PER_ELEMENT;
|
|
114
|
+
const setCount = hb.hb_set_get_population(setPtr);
|
|
115
|
+
const arrayPtr = hb.malloc(
|
|
116
|
+
setCount * bytesPerElment,
|
|
117
|
+
);
|
|
118
|
+
const arrayOffset = arrayPtr / bytesPerElment;
|
|
119
|
+
const array = heap.subarray(
|
|
120
|
+
arrayOffset,
|
|
121
|
+
arrayOffset + setCount,
|
|
122
|
+
) as typeof hb[`heap${T}`];
|
|
123
|
+
heap.set(array, arrayOffset);
|
|
124
|
+
hb.hb_set_next_many(
|
|
125
|
+
setPtr,
|
|
126
|
+
HB_SET_VALUE_INVALID,
|
|
127
|
+
arrayPtr,
|
|
128
|
+
setCount,
|
|
129
|
+
);
|
|
130
|
+
return array;
|
|
131
|
+
}
|
|
132
|
+
|
|
95
133
|
export class HarfBuzzFace {
|
|
96
134
|
readonly ptr: Pointer;
|
|
97
135
|
|
|
@@ -103,6 +141,14 @@ export class HarfBuzzFace {
|
|
|
103
141
|
return hb.hb_face_get_upem(this.ptr);
|
|
104
142
|
}
|
|
105
143
|
|
|
144
|
+
collectUnicodes() {
|
|
145
|
+
const unicodeSetPtr = hb.hb_set_create();
|
|
146
|
+
hb.hb_face_collect_unicodes(this.ptr, unicodeSetPtr);
|
|
147
|
+
const result = typedArrayFromSet(unicodeSetPtr, 'u32');
|
|
148
|
+
hb.hb_set_destroy(unicodeSetPtr);
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
|
|
106
152
|
destroy() {
|
|
107
153
|
hb.hb_face_destroy(this.ptr);
|
|
108
154
|
}
|
package/hb-subset.symbols
CHANGED
|
@@ -18,11 +18,15 @@ _hb_subset_input_destroy
|
|
|
18
18
|
_hb_subset_input_get_flags
|
|
19
19
|
_hb_subset_input_get_user_data
|
|
20
20
|
_hb_subset_input_glyph_set
|
|
21
|
+
_hb_subset_input_pin_axis_location
|
|
22
|
+
_hb_subset_input_pin_axis_to_default
|
|
21
23
|
_hb_subset_input_reference
|
|
22
24
|
_hb_subset_input_set
|
|
23
25
|
_hb_subset_input_set_flags
|
|
24
26
|
_hb_subset_input_set_user_data
|
|
25
27
|
_hb_subset_input_unicode_set
|
|
28
|
+
_hb_subset_input_keep_everything
|
|
26
29
|
_hb_subset_or_fail
|
|
30
|
+
_hb_subset_preprocess
|
|
27
31
|
_malloc
|
|
28
32
|
_free
|
package/hb-subset.wasm
CHANGED
|
Binary file
|
package/hb.wasm
CHANGED
|
Binary file
|
package/hbjs.js
CHANGED
|
@@ -9,6 +9,7 @@ function hbjs(instance) {
|
|
|
9
9
|
var utf8Decoder = new TextDecoder("utf8");
|
|
10
10
|
|
|
11
11
|
var HB_MEMORY_MODE_WRITABLE = 2;
|
|
12
|
+
var HB_SET_VALUE_INVALID = -1;
|
|
12
13
|
|
|
13
14
|
function hb_tag(s) {
|
|
14
15
|
return (
|
|
@@ -54,6 +55,42 @@ function hbjs(instance) {
|
|
|
54
55
|
};
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Return the typed array of HarfBuzz set contents.
|
|
60
|
+
* @template {typeof Uint8Array | typeof Uint32Array | typeof Int32Array | typeof Float32Array} T
|
|
61
|
+
* @param {number} setPtr Pointer of set
|
|
62
|
+
* @param {T} arrayClass Typed array class
|
|
63
|
+
* @returns {InstanceType<T>} Typed array instance
|
|
64
|
+
*/
|
|
65
|
+
function typedArrayFromSet(setPtr, arrayClass) {
|
|
66
|
+
let heap = heapu8;
|
|
67
|
+
if (arrayClass === Uint32Array) {
|
|
68
|
+
heap = heapu32;
|
|
69
|
+
} else if (arrayClass === Int32Array) {
|
|
70
|
+
heap = heapi32;
|
|
71
|
+
} else if (arrayClass === Float32Array) {
|
|
72
|
+
heap = heapf32;
|
|
73
|
+
}
|
|
74
|
+
const bytesPerElment = arrayClass.BYTES_PER_ELEMENT;
|
|
75
|
+
const setCount = exports.hb_set_get_population(setPtr);
|
|
76
|
+
const arrayPtr = exports.malloc(
|
|
77
|
+
setCount * bytesPerElment,
|
|
78
|
+
);
|
|
79
|
+
const arrayOffset = arrayPtr / bytesPerElment;
|
|
80
|
+
const array = heap.subarray(
|
|
81
|
+
arrayOffset,
|
|
82
|
+
arrayOffset + setCount,
|
|
83
|
+
);
|
|
84
|
+
heap.set(array, arrayOffset);
|
|
85
|
+
exports.hb_set_next_many(
|
|
86
|
+
setPtr,
|
|
87
|
+
HB_SET_VALUE_INVALID,
|
|
88
|
+
arrayPtr,
|
|
89
|
+
setCount,
|
|
90
|
+
);
|
|
91
|
+
return array;
|
|
92
|
+
}
|
|
93
|
+
|
|
57
94
|
/**
|
|
58
95
|
* Create an object representing a Harfbuzz face.
|
|
59
96
|
* @param {object} blob An object returned from `createBlob`.
|
|
@@ -98,6 +135,16 @@ function hbjs(instance) {
|
|
|
98
135
|
exports.free(axis);
|
|
99
136
|
return result;
|
|
100
137
|
},
|
|
138
|
+
/**
|
|
139
|
+
* Return unicodes the face supports
|
|
140
|
+
*/
|
|
141
|
+
collectUnicodes: function() {
|
|
142
|
+
var unicodeSetPtr = exports.hb_set_create();
|
|
143
|
+
exports.hb_face_collect_unicodes(ptr, unicodeSetPtr);
|
|
144
|
+
var result = typedArrayFromSet(unicodeSetPtr, Uint32Array);
|
|
145
|
+
exports.hb_set_destroy(ptr);
|
|
146
|
+
return result;
|
|
147
|
+
},
|
|
101
148
|
/**
|
|
102
149
|
* Free the object.
|
|
103
150
|
*/
|
package/hbjs.symbols
CHANGED
|
@@ -16,6 +16,7 @@ _hb_buffer_set_flags
|
|
|
16
16
|
_hb_buffer_set_language
|
|
17
17
|
_hb_buffer_set_script
|
|
18
18
|
_hb_face_create
|
|
19
|
+
_hb_face_collect_unicodes
|
|
19
20
|
_hb_face_destroy
|
|
20
21
|
_hb_face_get_upem
|
|
21
22
|
_hb_face_reference_table
|
|
@@ -28,6 +29,10 @@ _hb_glyph_info_get_glyph_flags
|
|
|
28
29
|
_hb_language_from_string
|
|
29
30
|
_hb_ot_var_get_axis_infos
|
|
30
31
|
_hb_script_from_string
|
|
32
|
+
_hb_set_create
|
|
33
|
+
_hb_set_destroy
|
|
34
|
+
_hb_set_get_population
|
|
35
|
+
_hb_set_next_many
|
|
31
36
|
_hb_shape
|
|
32
37
|
_hbjs_glyph_svg
|
|
33
38
|
_hbjs_shape_with_trace
|
package/package.json
CHANGED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
name: Build
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [ "main" ]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [ "main" ]
|
|
8
|
-
|
|
9
|
-
env:
|
|
10
|
-
EM_VERSION: 3.1.16
|
|
11
|
-
EM_CACHE_FOLDER: 'emsdk-cache'
|
|
12
|
-
|
|
13
|
-
jobs:
|
|
14
|
-
build:
|
|
15
|
-
|
|
16
|
-
runs-on: ubuntu-latest
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- name: Checkout
|
|
20
|
-
uses: actions/checkout@v3
|
|
21
|
-
with:
|
|
22
|
-
submodules: true
|
|
23
|
-
|
|
24
|
-
- name: Setup cache
|
|
25
|
-
id: cache-system-libraries
|
|
26
|
-
uses: actions/cache@v3
|
|
27
|
-
with:
|
|
28
|
-
path: ${{env.EM_CACHE_FOLDER}}
|
|
29
|
-
key: ${{env.EM_VERSION}}-${{runner.os}}
|
|
30
|
-
- name: Setup Emscripten
|
|
31
|
-
uses: mymindstorm/setup-emsdk@v11
|
|
32
|
-
with:
|
|
33
|
-
version: ${{env.EM_VERSION}}
|
|
34
|
-
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
|
|
35
|
-
- name: Build hb.wasm
|
|
36
|
-
run: ./build.sh
|
|
37
|
-
- name: Build hb-subset.wasm
|
|
38
|
-
run: ./build-subset.sh
|
|
39
|
-
|
|
40
|
-
- name: Setup Node.js
|
|
41
|
-
uses: actions/setup-node@v3
|
|
42
|
-
- name: Test hb.wasm
|
|
43
|
-
run: node examples/hbjs.example.node.js
|
|
44
|
-
- name: Test hb-subset.wasm
|
|
45
|
-
run: node examples/hb-subset.example.node.js
|
package/.gitmodules
DELETED