harfbuzzjs 0.2.1 → 0.3.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/.github/workflows/build.yml +45 -0
- package/.gitmodules +3 -0
- package/LICENSE +0 -1
- package/README.md +2 -8
- package/build-subset.sh +22 -0
- package/build.sh +17 -57
- package/{subset/config-override.h → config-override-subset.h} +0 -0
- package/config-override.h +3 -3
- package/examples/Mada.abjad.otf +0 -0
- package/{subset/roboto-black.ttf → examples/Roboto-Black.ttf} +0 -0
- package/{subset/test.js → examples/hb-subset.example.node.js} +5 -5
- package/examples/hbjs.example.html +0 -1
- package/examples/hbjs.example.js +3 -2
- package/examples/hbjs.example.node.js +2 -0
- package/examples/nohbjs.html +0 -1
- package/harfbuzz.ts +0 -1
- package/hb-subset.symbols +28 -0
- package/hb-subset.wasm +0 -0
- package/hb.wasm +0 -0
- package/hbjs.cc +256 -0
- package/hbjs.js +26 -4
- package/hbjs.symbols +36 -0
- package/index.js +0 -1
- package/package.json +1 -1
- package/hbjs.c +0 -284
- package/libc/ctype.h +0 -73
- package/libc/emmalloc.cpp +0 -1202
- package/libc/fprintf.c +0 -65
- package/libc/include/assert.h +0 -14
- package/libc/include/cassert +0 -1
- package/libc/include/cfloat +0 -1
- package/libc/include/climits +0 -1
- package/libc/include/cmath +0 -1
- package/libc/include/cstdarg +0 -1
- package/libc/include/cstddef +0 -1
- package/libc/include/cstdio +0 -1
- package/libc/include/cstdlib +0 -1
- package/libc/include/cstring +0 -1
- package/libc/include/emscripten.h +0 -0
- package/libc/include/float.h +0 -6
- package/libc/include/limits.h +0 -2
- package/libc/include/locale.h +0 -0
- package/libc/include/malloc.h +0 -13
- package/libc/include/math.h +0 -0
- package/libc/include/raqm-version.h +0 -5
- package/libc/include/stdarg.h +0 -0
- package/libc/include/stdbool.h +0 -12
- package/libc/include/stddef.h +0 -0
- package/libc/include/stdint.h +0 -1
- package/libc/include/stdio.h +0 -0
- package/libc/include/stdlib.h +0 -110
- package/libc/include/string.h +0 -26
- package/libc/include/sys/types.h +0 -1
- package/libc/include/unistd.h +0 -14
- package/libc/main.c +0 -7
- package/libc/malloc.cc +0 -29
- package/libc/prf.c +0 -667
- package/libc/sprintf.c +0 -112
- package/libc/strtol.c +0 -79
- package/libc/zephyr-string.c +0 -381
- package/subset/build.sh +0 -48
- package/subset/hb-subset.wasm +0 -0
- package/subset/test.cc +0 -50
|
@@ -0,0 +1,45 @@
|
|
|
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
ADDED
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -5,13 +5,9 @@ library for client/server side JavaScript projects.
|
|
|
5
5
|
See the demo [here](https://harfbuzz.github.io/harfbuzzjs/).
|
|
6
6
|
|
|
7
7
|
## Building
|
|
8
|
-
1. Install
|
|
8
|
+
1. Install emscripten
|
|
9
9
|
2. `./build.sh`
|
|
10
10
|
|
|
11
|
-
Note that if building on Mac OS X, clang 11.0 needs to be installed from Homebrew (`brew install clang`). Also note that Homebrew clang is not in
|
|
12
|
-
the path by default, so you need to add `/usr/local/opt/llvm/bin` to your
|
|
13
|
-
path or you will get weird compiled errors.
|
|
14
|
-
|
|
15
11
|
## Download
|
|
16
12
|
Download the pack from [releases tab](https://github.com/harfbuzz/harfbuzzjs/releases)
|
|
17
13
|
of the project, or just download the [demo page](https://harfbuzz.github.io/harfbuzzjs/) (the
|
|
@@ -24,8 +20,6 @@ demo source is in [gh-pages](https://github.com/harfbuzz/harfbuzzjs/tree/gh-page
|
|
|
24
20
|
```javascript
|
|
25
21
|
hb = require("hbjs.js")
|
|
26
22
|
WebAssembly.instantiateStreaming(fetch("hb.wasm")).then(function (result) {
|
|
27
|
-
// WebAssembly needs its own heap - allocate 400 16k pages to do our work in.
|
|
28
|
-
result.instance.exports.memory.grow(400);
|
|
29
23
|
fetch('myfont.ttf').then(function (data) {
|
|
30
24
|
return data.arrayBuffer();
|
|
31
25
|
}).then(function (fontdata) {
|
|
@@ -84,7 +78,7 @@ how to use it.
|
|
|
84
78
|
harfbuzzjs uses a stripped-down version of Harfbuzz generated by compiling Harfbuzz with `-DHB_TINY`. This may mean that some functions you need are not available. Look at `src/hb-config.hh` in the Harfbuzz source directory to see what has been removed. For example, `HB_TINY` defines `HB_LEAN` which (amongst other things) defines `HB_NO_OT_GLYPH_NAMES`. If, for example, you really need to get at the glyph names:
|
|
85
79
|
|
|
86
80
|
1. First, undefine the macro in question, by adding e.g. `#undef HB_NO_OT_GLYPH_NAMES` to `config-override.h`.
|
|
87
|
-
2. Next, export any function that you need by adding a line to `
|
|
81
|
+
2. Next, export any function that you need by adding a line to `hbjs.symbols`; in this case `_hb_ot_get_glyph_name`.
|
|
88
82
|
3. Now the function will be exported through the WASM object, but you need to add Javascript to bridge to it - in this case, handling the memory allocation of the `char *` parameter `name` and marshalling it to a JavaScript string with `heapu8.subarray`. The best way to do this is to look at `hbjs.js` for functions which use similar signatures.
|
|
89
83
|
|
|
90
84
|
If you have extended harfbuzzjs in ways that you think others will also benefit from, please raise a pull request. If there are parts of Harfbuzz that you need but the instructions above don't work, describe what you are trying to do in an issue.
|
package/build-subset.sh
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
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-subset.h\" \
|
|
16
|
+
-DHB_EXPERIMENTAL_API \
|
|
17
|
+
--no-entry \
|
|
18
|
+
-s EXPORTED_FUNCTIONS=@hb-subset.symbols \
|
|
19
|
+
-s INITIAL_MEMORY=65MB \
|
|
20
|
+
-o hb-subset.wasm \
|
|
21
|
+
harfbuzz/src/harfbuzz.cc \
|
|
22
|
+
harfbuzz/src/hb-subset*.cc
|
package/build.sh
CHANGED
|
@@ -1,61 +1,21 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
set -e
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
clang \
|
|
11
|
-
-I./libc/include -Oz \
|
|
12
|
-
-fno-exceptions -fno-rtti -fno-threadsafe-statics -fvisibility-inlines-hidden \
|
|
13
|
-
--target=wasm32 \
|
|
14
|
-
-nostdlib -nostdinc \
|
|
15
|
-
-Wno-builtin-requires-header \
|
|
4
|
+
em++ \
|
|
5
|
+
-std=c++11 \
|
|
6
|
+
-fno-exceptions \
|
|
7
|
+
-fno-rtti \
|
|
8
|
+
-fno-threadsafe-statics \
|
|
9
|
+
-fvisibility-inlines-hidden \
|
|
16
10
|
-flto \
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
-Wl,--export=hb_font_create \
|
|
29
|
-
-Wl,--export=hb_buffer_create \
|
|
30
|
-
-Wl,--export=hb_buffer_add_utf8 \
|
|
31
|
-
-Wl,--export=hb_buffer_add_utf16 \
|
|
32
|
-
-Wl,--export=hb_buffer_guess_segment_properties \
|
|
33
|
-
-Wl,--export=hb_buffer_set_direction \
|
|
34
|
-
-Wl,--export=hb_buffer_set_cluster_level \
|
|
35
|
-
-Wl,--export=hb_buffer_set_flags \
|
|
36
|
-
-Wl,--export=hb_buffer_set_script \
|
|
37
|
-
-Wl,--export=hb_script_from_string \
|
|
38
|
-
-Wl,--export=hb_buffer_set_language \
|
|
39
|
-
-Wl,--export=hb_language_from_string \
|
|
40
|
-
-Wl,--export=hb_shape \
|
|
41
|
-
-Wl,--export=hb_buffer_get_glyph_infos \
|
|
42
|
-
-Wl,--export=hb_buffer_get_glyph_positions \
|
|
43
|
-
-Wl,--export=hb_buffer_get_length \
|
|
44
|
-
-Wl,--export=hb_buffer_destroy \
|
|
45
|
-
-Wl,--export=hb_font_destroy \
|
|
46
|
-
-Wl,--export=hb_face_destroy \
|
|
47
|
-
-Wl,--export=hb_face_get_upem \
|
|
48
|
-
-Wl,--export=hb_blob_destroy \
|
|
49
|
-
-Wl,--export=hb_blob_get_length \
|
|
50
|
-
-Wl,--export=hb_font_set_scale \
|
|
51
|
-
-Wl,--export=hb_face_get_upem \
|
|
52
|
-
-Wl,--export=hbjs_glyph_svg \
|
|
53
|
-
-Wl,--export=hbjs_shape_with_trace \
|
|
54
|
-
-Wl,--export=hb_ot_var_get_axis_infos \
|
|
55
|
-
-Wl,--export=hb_font_set_variations \
|
|
56
|
-
-Wl,--export=free \
|
|
57
|
-
-Wl,--export=free_ptr \
|
|
58
|
-
-Wl,--export=__heap_base \
|
|
59
|
-
hbjs.c -DHAVE_CONFIG_OVERRIDE_H -I. -DHB_EXPERIMENTAL_API \
|
|
60
|
-
libc/malloc.cc libc/zephyr-string.c libc/prf.c libc/strtol.c libc/sprintf.c libc/main.c harfbuzz/src/harfbuzz.cc \
|
|
61
|
-
-o hb.wasm $@
|
|
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 EXPORTED_FUNCTIONS=@hbjs.symbols \
|
|
19
|
+
-s INITIAL_MEMORY=65MB \
|
|
20
|
+
-o hb.wasm \
|
|
21
|
+
hbjs.cc
|
|
File without changes
|
package/config-override.h
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// #undef HB_NO_OT_FONT_CFF
|
|
1
|
+
#undef HB_NO_CFF
|
|
2
|
+
#undef HB_NO_OT_FONT_CFF
|
|
4
3
|
#undef HB_NO_DRAW
|
|
5
4
|
#undef HB_NO_BUFFER_MESSAGE
|
|
6
5
|
#undef HB_NO_BUFFER_SERIALIZE
|
|
7
6
|
#undef HB_NO_VAR
|
|
7
|
+
#undef HB_NO_OT_FONT_GLYPH_NAMES
|
|
Binary file
|
|
File without changes
|
|
@@ -5,9 +5,8 @@ const readFileAsync = require('util').promisify(fs.readFile);
|
|
|
5
5
|
const writeFileAsync = require('util').promisify(fs.writeFile);
|
|
6
6
|
|
|
7
7
|
(async () => {
|
|
8
|
-
const { instance: { exports } } = await WebAssembly.instantiate(await readFileAsync(__dirname + '
|
|
9
|
-
|
|
10
|
-
const fontBlob = await readFileAsync(__dirname + '/roboto-black.ttf');
|
|
8
|
+
const { instance: { exports } } = await WebAssembly.instantiate(await readFileAsync(__dirname + '/../hb-subset.wasm'));
|
|
9
|
+
const fontBlob = await readFileAsync(__dirname + '/Roboto-Black.ttf');
|
|
11
10
|
|
|
12
11
|
const heapu8 = new Uint8Array(exports.memory.buffer);
|
|
13
12
|
const fontBuffer = exports.malloc(fontBlob.byteLength);
|
|
@@ -26,7 +25,7 @@ const writeFileAsync = require('util').promisify(fs.writeFile);
|
|
|
26
25
|
exports.hb_set_add(unicode_set, 'c'.charCodeAt(0));
|
|
27
26
|
|
|
28
27
|
// exports.hb_subset_input_set_drop_hints(input, true);
|
|
29
|
-
const subset = exports.
|
|
28
|
+
const subset = exports.hb_subset_or_fail(face, input);
|
|
30
29
|
|
|
31
30
|
/* Clean up */
|
|
32
31
|
exports.hb_subset_input_destroy(input);
|
|
@@ -37,7 +36,8 @@ const writeFileAsync = require('util').promisify(fs.writeFile);
|
|
|
37
36
|
const data = exports.hb_blob_get_data(result, 0);
|
|
38
37
|
const subsetFontBlob = heapu8.subarray(data, data + exports.hb_blob_get_length(result));
|
|
39
38
|
|
|
40
|
-
await writeFileAsync(__dirname + '/
|
|
39
|
+
await writeFileAsync(__dirname + '/Roboto-Black.subset.ttf', subsetFontBlob);
|
|
40
|
+
console.log(`Wrote subset to: ${__dirname}/Roboto-Black.subset.ttf`);
|
|
41
41
|
|
|
42
42
|
/* Clean up */
|
|
43
43
|
exports.hb_blob_destroy(result);
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
<script>
|
|
4
4
|
// instantiateStreaming isn't supported in Safari yet, see nohbjs.html
|
|
5
5
|
WebAssembly.instantiateStreaming(fetch("../hb.wasm")).then(function (result) {
|
|
6
|
-
result.instance.exports.memory.grow(400); // each page is 64kb in size
|
|
7
6
|
fetch('Roboto.abc.ttf').then(function (x) {
|
|
8
7
|
return x.arrayBuffer();
|
|
9
8
|
}).then(function (blob) {
|
package/examples/hbjs.example.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
function example(hb, fontBlob) {
|
|
1
|
+
function example(hb, fontBlob, text) {
|
|
2
2
|
var blob = hb.createBlob(fontBlob);
|
|
3
3
|
var face = hb.createFace(blob, 0);
|
|
4
4
|
// console.log(face.getAxisInfos());
|
|
@@ -7,7 +7,7 @@ function example(hb, fontBlob) {
|
|
|
7
7
|
font.setScale(1000, 1000); // Optional, if not given will be in font upem
|
|
8
8
|
|
|
9
9
|
var buffer = hb.createBuffer();
|
|
10
|
-
buffer.addText('abc');
|
|
10
|
+
buffer.addText(text || 'abc');
|
|
11
11
|
buffer.guessSegmentProperties();
|
|
12
12
|
// buffer.setDirection('ltr'); // optional as can be set by guessSegmentProperties also
|
|
13
13
|
hb.shape(font, buffer); // features are not supported yet
|
|
@@ -18,6 +18,7 @@ function example(hb, fontBlob) {
|
|
|
18
18
|
result.forEach(function (x) {
|
|
19
19
|
if (glyphs[x.g]) return;
|
|
20
20
|
glyphs[x.g] = {
|
|
21
|
+
name: font.glyphName(x.g),
|
|
21
22
|
path: font.glyphToPath(x.g),
|
|
22
23
|
json: font.glyphToJson(x.g)
|
|
23
24
|
};
|
|
@@ -4,4 +4,6 @@ var example = require('./hbjs.example.js');
|
|
|
4
4
|
|
|
5
5
|
require('../').then(function (hbjs) {
|
|
6
6
|
console.log(example(hbjs, new Uint8Array(fs.readFileSync(path.resolve(__dirname, 'Roboto.abc.ttf')))));
|
|
7
|
+
console.log(example(hbjs, new Uint8Array(fs.readFileSync(path.resolve(__dirname, 'Roboto-Black.ttf')))));
|
|
8
|
+
console.log(example(hbjs, new Uint8Array(fs.readFileSync(path.resolve(__dirname, 'Mada.abjad.otf'))), "أبجد"));
|
|
7
9
|
}, console.log);
|
package/examples/nohbjs.html
CHANGED
|
@@ -9,7 +9,6 @@ fetch("../hb.wasm").then(function (x) {
|
|
|
9
9
|
return WebAssembly.instantiate(wasm);
|
|
10
10
|
}).then(function (result) {
|
|
11
11
|
var exports = result.instance.exports;
|
|
12
|
-
exports.memory.grow(400); // each page is 64kb in size
|
|
13
12
|
|
|
14
13
|
fetch('Roboto.abc.ttf').then(function (x) {
|
|
15
14
|
return x.arrayBuffer();
|
package/harfbuzz.ts
CHANGED
|
@@ -223,7 +223,6 @@ export function loadHarfbuzz(webAssemblyUrl: string): Promise<void> {
|
|
|
223
223
|
return WebAssembly.instantiate(wasm);
|
|
224
224
|
}).then(result => {
|
|
225
225
|
//@ts-ignore
|
|
226
|
-
result.instance.exports.memory.grow(1000); // each page is 64kb in size => 64mb allowed for webassembly, maybe we need more...
|
|
227
226
|
hb = new HarfBuzzExports(result.instance.exports);
|
|
228
227
|
});
|
|
229
228
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
_hb_blob_create
|
|
2
|
+
_hb_blob_destroy
|
|
3
|
+
_hb_blob_get_data
|
|
4
|
+
_hb_blob_get_length
|
|
5
|
+
_hb_face_create
|
|
6
|
+
_hb_face_destroy
|
|
7
|
+
_hb_face_get_empty
|
|
8
|
+
_hb_face_reference_blob
|
|
9
|
+
_hb_set_add
|
|
10
|
+
_hb_set_clear
|
|
11
|
+
_hb_set_create
|
|
12
|
+
_hb_set_del
|
|
13
|
+
_hb_set_destroy
|
|
14
|
+
_hb_set_invert
|
|
15
|
+
_hb_set_union
|
|
16
|
+
_hb_subset_input_create_or_fail
|
|
17
|
+
_hb_subset_input_destroy
|
|
18
|
+
_hb_subset_input_get_flags
|
|
19
|
+
_hb_subset_input_get_user_data
|
|
20
|
+
_hb_subset_input_glyph_set
|
|
21
|
+
_hb_subset_input_reference
|
|
22
|
+
_hb_subset_input_set
|
|
23
|
+
_hb_subset_input_set_flags
|
|
24
|
+
_hb_subset_input_set_user_data
|
|
25
|
+
_hb_subset_input_unicode_set
|
|
26
|
+
_hb_subset_or_fail
|
|
27
|
+
_malloc
|
|
28
|
+
_free
|
package/hb-subset.wasm
ADDED
|
Binary file
|
package/hb.wasm
CHANGED
|
Binary file
|
package/hbjs.cc
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#include "harfbuzz/src/harfbuzz.cc"
|
|
2
|
+
|
|
3
|
+
HB_BEGIN_DECLS
|
|
4
|
+
|
|
5
|
+
int
|
|
6
|
+
hbjs_glyph_svg (hb_font_t *font, hb_codepoint_t glyph, char *buf, unsigned buf_size);
|
|
7
|
+
|
|
8
|
+
unsigned
|
|
9
|
+
hbjs_shape_with_trace (hb_font_t *font, hb_buffer_t* buf,
|
|
10
|
+
char* featurestring,
|
|
11
|
+
unsigned int stop_at, unsigned int stop_phase,
|
|
12
|
+
char *outbuf, unsigned buf_size);
|
|
13
|
+
|
|
14
|
+
void *free_ptr(void);
|
|
15
|
+
|
|
16
|
+
HB_END_DECLS
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
void *free_ptr(void) { return (void *) free; }
|
|
20
|
+
|
|
21
|
+
enum {
|
|
22
|
+
HB_SHAPE_DONT_STOP,
|
|
23
|
+
HB_SHAPE_GSUB_PHASE,
|
|
24
|
+
HB_SHAPE_GPOS_PHASE
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
struct user_data_t {
|
|
28
|
+
user_data_t(char *str_,
|
|
29
|
+
unsigned size_,
|
|
30
|
+
unsigned stop_at_ = 0,
|
|
31
|
+
unsigned stop_phase_ = 0)
|
|
32
|
+
: str(str_)
|
|
33
|
+
, size(size_)
|
|
34
|
+
, stop_at(stop_at_)
|
|
35
|
+
, stop_phase(stop_phase_)
|
|
36
|
+
{}
|
|
37
|
+
char *str = nullptr;
|
|
38
|
+
unsigned size = 0;
|
|
39
|
+
unsigned consumed = 0;
|
|
40
|
+
hb_bool_t failure = false;
|
|
41
|
+
unsigned stop_at = 0;
|
|
42
|
+
unsigned stop_phase = 0;
|
|
43
|
+
hb_bool_t stopping = false;
|
|
44
|
+
unsigned current_phase = 0;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
static void
|
|
49
|
+
_user_data_printf (user_data_t *data, const char *format, ...)
|
|
50
|
+
{
|
|
51
|
+
#define BUFSIZE 1000
|
|
52
|
+
char buf[BUFSIZE];
|
|
53
|
+
int len;
|
|
54
|
+
va_list va;
|
|
55
|
+
|
|
56
|
+
if (!data || data->failure)
|
|
57
|
+
return;
|
|
58
|
+
|
|
59
|
+
va_start(va, format);
|
|
60
|
+
len = vsnprintf(buf, BUFSIZE, format, va);
|
|
61
|
+
va_end(va);
|
|
62
|
+
|
|
63
|
+
if (data->consumed + len >= data->size || len < 0 || len > BUFSIZE)
|
|
64
|
+
{
|
|
65
|
+
data->failure = true;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
memcpy (data->str + data->consumed, buf, len);
|
|
70
|
+
data->consumed += len;
|
|
71
|
+
#undef BUFSIZE
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static void
|
|
75
|
+
move_to (hb_draw_funcs_t *dfuncs, user_data_t *draw_data, hb_draw_state_t *,
|
|
76
|
+
float to_x, float to_y,
|
|
77
|
+
void *)
|
|
78
|
+
{
|
|
79
|
+
_user_data_printf (draw_data, "M%g,%g", (double)to_x, (double)to_y);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static void
|
|
83
|
+
line_to (hb_draw_funcs_t *dfuncs, user_data_t *draw_data, hb_draw_state_t *,
|
|
84
|
+
float to_x, float to_y,
|
|
85
|
+
void *)
|
|
86
|
+
{
|
|
87
|
+
_user_data_printf (draw_data, "L%g,%g", (double)to_x, (double)to_y);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static void
|
|
91
|
+
quadratic_to (hb_draw_funcs_t *dfuncs, user_data_t *draw_data, hb_draw_state_t *,
|
|
92
|
+
float control_x, float control_y,
|
|
93
|
+
float to_x, float to_y,
|
|
94
|
+
void *)
|
|
95
|
+
{
|
|
96
|
+
_user_data_printf (draw_data, "Q%g,%g %g,%g",
|
|
97
|
+
(double)control_x,
|
|
98
|
+
(double)control_y,
|
|
99
|
+
(double)to_x,
|
|
100
|
+
(double)to_y);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static void
|
|
104
|
+
cubic_to (hb_draw_funcs_t *dfuncs, user_data_t *draw_data, hb_draw_state_t *,
|
|
105
|
+
float control1_x, float control1_y,
|
|
106
|
+
float control2_x, float control2_y,
|
|
107
|
+
float to_x, float to_y,
|
|
108
|
+
void *)
|
|
109
|
+
{
|
|
110
|
+
_user_data_printf (draw_data, "C%g,%g %g,%g %g,%g",
|
|
111
|
+
(double)control1_x,
|
|
112
|
+
(double)control1_y,
|
|
113
|
+
(double)control2_x,
|
|
114
|
+
(double)control2_y,
|
|
115
|
+
(double)to_x,
|
|
116
|
+
(double)to_y);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static void
|
|
120
|
+
close_path (hb_draw_funcs_t *dfuncs, user_data_t *draw_data, hb_draw_state_t *, void *)
|
|
121
|
+
{
|
|
122
|
+
_user_data_printf (draw_data, "Z");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static hb_draw_funcs_t *funcs = 0;
|
|
126
|
+
|
|
127
|
+
int
|
|
128
|
+
hbjs_glyph_svg (hb_font_t *font, hb_codepoint_t glyph, char *buf, unsigned buf_size)
|
|
129
|
+
{
|
|
130
|
+
if (funcs == 0) /* not the best pattern for multi-threaded apps which is not a concern here */
|
|
131
|
+
{
|
|
132
|
+
funcs = hb_draw_funcs_create (); /* will be leaked */
|
|
133
|
+
hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to, nullptr, nullptr);
|
|
134
|
+
hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to, nullptr, nullptr);
|
|
135
|
+
hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to, nullptr, nullptr);
|
|
136
|
+
hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to, nullptr, nullptr);
|
|
137
|
+
hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path, nullptr, nullptr);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
user_data_t draw_data(buf, buf_size);
|
|
141
|
+
hb_font_get_glyph_shape (font, glyph, funcs, &draw_data);
|
|
142
|
+
if (draw_data.failure)
|
|
143
|
+
return -1;
|
|
144
|
+
|
|
145
|
+
buf[draw_data.consumed] = '\0';
|
|
146
|
+
return draw_data.consumed;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
static hb_bool_t do_trace (hb_buffer_t *buffer,
|
|
150
|
+
hb_font_t *font,
|
|
151
|
+
const char *message,
|
|
152
|
+
user_data_t *user_data) {
|
|
153
|
+
unsigned int consumed;
|
|
154
|
+
unsigned int num_glyphs = hb_buffer_get_length (buffer);
|
|
155
|
+
|
|
156
|
+
if (strcmp(message, "start table GSUB") == 0) {
|
|
157
|
+
user_data->current_phase = HB_SHAPE_GSUB_PHASE;
|
|
158
|
+
} else if (strcmp(message, "start table GPOS") == 0) {
|
|
159
|
+
user_data->current_phase = HB_SHAPE_GPOS_PHASE;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
if (user_data->current_phase != user_data->stop_phase) {
|
|
164
|
+
user_data->stopping = false;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// If we overflowed, keep going anyway.
|
|
168
|
+
if (user_data->failure) return 1;
|
|
169
|
+
|
|
170
|
+
if (user_data->stop_phase != HB_SHAPE_DONT_STOP) {
|
|
171
|
+
// Do we need to start stopping?
|
|
172
|
+
char buf[12];
|
|
173
|
+
snprintf (buf, 12, "%d", user_data->stop_at);
|
|
174
|
+
if ((user_data->current_phase == user_data->stop_phase) &&
|
|
175
|
+
(strncmp(message, "end lookup ", 11) == 0) &&
|
|
176
|
+
(strcmp(message + 11, buf) == 0)) {
|
|
177
|
+
user_data->stopping = true;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// If we need to stop, stop.
|
|
182
|
+
if (user_data->stopping) return 0;
|
|
183
|
+
|
|
184
|
+
_user_data_printf (user_data, "{\"m\":\"%s\",\"t\":", message);
|
|
185
|
+
hb_buffer_serialize_glyphs(buffer, 0, num_glyphs,
|
|
186
|
+
user_data->str + user_data->consumed,
|
|
187
|
+
user_data->size - user_data->consumed,
|
|
188
|
+
&consumed,
|
|
189
|
+
font,
|
|
190
|
+
HB_BUFFER_SERIALIZE_FORMAT_JSON,
|
|
191
|
+
HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES);
|
|
192
|
+
user_data->consumed += consumed;
|
|
193
|
+
_user_data_printf (user_data, "},\n");
|
|
194
|
+
|
|
195
|
+
return 1;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
unsigned
|
|
199
|
+
hbjs_shape_with_trace (hb_font_t *font, hb_buffer_t* buf,
|
|
200
|
+
char* featurestring,
|
|
201
|
+
unsigned int stop_at, unsigned int stop_phase,
|
|
202
|
+
char *outbuf, unsigned buf_size) {
|
|
203
|
+
user_data_t user_data(outbuf, buf_size, stop_at, stop_phase);
|
|
204
|
+
|
|
205
|
+
int num_features = 0;
|
|
206
|
+
hb_feature_t* features = nullptr;
|
|
207
|
+
|
|
208
|
+
if (*featurestring) {
|
|
209
|
+
/* count the features first, so we can allocate memory */
|
|
210
|
+
char* p = featurestring;
|
|
211
|
+
do {
|
|
212
|
+
num_features++;
|
|
213
|
+
p = strchr (p, ',');
|
|
214
|
+
if (p)
|
|
215
|
+
p++;
|
|
216
|
+
} while (p);
|
|
217
|
+
|
|
218
|
+
features = (hb_feature_t *) calloc (num_features, sizeof (*features));
|
|
219
|
+
|
|
220
|
+
/* now do the actual parsing */
|
|
221
|
+
p = featurestring;
|
|
222
|
+
num_features = 0;
|
|
223
|
+
while (p && *p) {
|
|
224
|
+
char *end = strchr (p, ',');
|
|
225
|
+
if (hb_feature_from_string (p, end ? end - p : -1, &features[num_features]))
|
|
226
|
+
num_features++;
|
|
227
|
+
p = end ? end + 1 : nullptr;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
hb_buffer_set_message_func (buf, (hb_buffer_message_func_t)do_trace, &user_data, nullptr);
|
|
232
|
+
user_data.str[user_data.consumed++] = '[';
|
|
233
|
+
hb_shape(font, buf, features, num_features);
|
|
234
|
+
|
|
235
|
+
if (user_data.failure) return -1;
|
|
236
|
+
|
|
237
|
+
user_data.str[user_data.consumed-2] = ']';
|
|
238
|
+
user_data.str[user_data.consumed-1] = '\0';
|
|
239
|
+
return user_data.consumed;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
#ifdef MAIN
|
|
243
|
+
#include <stdio.h>
|
|
244
|
+
int main() {
|
|
245
|
+
hb_blob_t *blob = hb_blob_create_from_file ("/home/ebrahim/Desktop/harfbuzzjs/harfbuzz/test/subset/data/fonts/Roboto-Regular.ttf");
|
|
246
|
+
hb_face_t *face = hb_face_create (blob, 0);
|
|
247
|
+
hb_blob_destroy (blob);
|
|
248
|
+
hb_font_t *font = hb_font_create (face);
|
|
249
|
+
hb_face_destroy (face);
|
|
250
|
+
char buf[1024];
|
|
251
|
+
buf[0] = '\0';
|
|
252
|
+
printf ("%d %d\n", hb_blob_get_length (blob), hbjs_ot_glyph_svg (font, 0, buf, sizeof (buf)));
|
|
253
|
+
puts (buf);
|
|
254
|
+
hb_font_destroy (font);
|
|
255
|
+
}
|
|
256
|
+
#endif
|
package/hbjs.js
CHANGED
|
@@ -110,6 +110,9 @@ function hbjs(instance) {
|
|
|
110
110
|
var pathBufferSize = 65536; // should be enough for most glyphs
|
|
111
111
|
var pathBuffer = exports.malloc(pathBufferSize); // permanently allocated
|
|
112
112
|
|
|
113
|
+
var nameBufferSize = 256; // should be enough for most glyphs
|
|
114
|
+
var nameBuffer = exports.malloc(nameBufferSize); // permanently allocated
|
|
115
|
+
|
|
113
116
|
/**
|
|
114
117
|
* Create an object representing a Harfbuzz font.
|
|
115
118
|
* @param {object} blob An object returned from `createFace`.
|
|
@@ -126,8 +129,24 @@ function hbjs(instance) {
|
|
|
126
129
|
return svgLength > 0 ? utf8Decoder.decode(heapu8.subarray(pathBuffer, pathBuffer + svgLength)) : "";
|
|
127
130
|
}
|
|
128
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Return glyph name.
|
|
134
|
+
* @param {number} glyphId ID of the requested glyph in the font.
|
|
135
|
+
**/
|
|
136
|
+
function glyphName(glyphId) {
|
|
137
|
+
exports.hb_font_glyph_to_string(
|
|
138
|
+
ptr,
|
|
139
|
+
glyphId,
|
|
140
|
+
nameBuffer,
|
|
141
|
+
nameBufferSize
|
|
142
|
+
);
|
|
143
|
+
var array = heapu8.subarray(nameBuffer, nameBuffer + nameBufferSize);
|
|
144
|
+
return utf8Decoder.decode(array.slice(0, array.indexOf(0)));
|
|
145
|
+
}
|
|
146
|
+
|
|
129
147
|
return {
|
|
130
148
|
ptr: ptr,
|
|
149
|
+
glyphName: glyphName,
|
|
131
150
|
glyphToPath: glyphToPath,
|
|
132
151
|
/**
|
|
133
152
|
* Return a glyph as a JSON path string
|
|
@@ -287,12 +306,14 @@ function hbjs(instance) {
|
|
|
287
306
|
* - ax: Advance width (width to advance after this glyph is painted)
|
|
288
307
|
* - ay: Advance height (height to advance after this glyph is painted)
|
|
289
308
|
* - dx: X displacement (adjustment in X dimension when painting this glyph)
|
|
290
|
-
* -
|
|
309
|
+
* - dy: Y displacement (adjustment in Y dimension when painting this glyph)
|
|
310
|
+
* - flags: Glyph flags like `HB_GLYPH_FLAG_UNSAFE_TO_BREAK` (0x1)
|
|
291
311
|
**/
|
|
292
|
-
json: function (
|
|
312
|
+
json: function () {
|
|
293
313
|
var length = exports.hb_buffer_get_length(ptr);
|
|
294
314
|
var result = [];
|
|
295
|
-
var
|
|
315
|
+
var infosPtr = exports.hb_buffer_get_glyph_infos(ptr, 0);
|
|
316
|
+
var infosPtr32 = infosPtr / 4;
|
|
296
317
|
var positionsPtr32 = exports.hb_buffer_get_glyph_positions(ptr, 0) / 4;
|
|
297
318
|
var infos = heapu32.subarray(infosPtr32, infosPtr32 + 5 * length);
|
|
298
319
|
var positions = heapi32.subarray(positionsPtr32, positionsPtr32 + 5 * length);
|
|
@@ -303,7 +324,8 @@ function hbjs(instance) {
|
|
|
303
324
|
ax: positions[i * 5 + 0],
|
|
304
325
|
ay: positions[i * 5 + 1],
|
|
305
326
|
dx: positions[i * 5 + 2],
|
|
306
|
-
dy: positions[i * 5 + 3]
|
|
327
|
+
dy: positions[i * 5 + 3],
|
|
328
|
+
flags: exports.hb_glyph_info_get_glyph_flags(infosPtr + i * 20)
|
|
307
329
|
});
|
|
308
330
|
}
|
|
309
331
|
return result;
|