Compare commits
147 Commits
Author | SHA1 | Date |
---|---|---|
Behdad Esfahbod | 2663a9b6f9 | |
Behdad Esfahbod | d2fb583a5a | |
Behdad Esfahbod | f9dd402ef8 | |
Simon Cozens | 85a1fdd93f | |
Simon Cozens | 0bfad127c3 | |
Simon Cozens | 3fc48d4ada | |
Simon Cozens | 0a16c60b42 | |
Behdad Esfahbod | 6ff994f31d | |
Behdad Esfahbod | b6c1814410 | |
Simon Cozens | e78d8653ce | |
Behdad Esfahbod | 74a2f338c6 | |
Behdad Esfahbod | 7df9b3dd89 | |
Behdad Esfahbod | f5a0bd223b | |
Behdad Esfahbod | 7e5064ac1b | |
Behdad Esfahbod | 5235ee68ad | |
Behdad Esfahbod | e89415b5b9 | |
Behdad Esfahbod | 6aea77c643 | |
Behdad Esfahbod | 142ceaf246 | |
Simon Cozens | 7e397d8695 | |
Simon Cozens | d942f72c2a | |
Simon Cozens | 52b11546c8 | |
Simon Cozens | 0c90555e59 | |
Behdad Esfahbod | 4f537df67d | |
Behdad Esfahbod | 2482bb120b | |
Behdad Esfahbod | a53690a937 | |
Behdad Esfahbod | 3226b4342b | |
Behdad Esfahbod | 4096115b48 | |
Behdad Esfahbod | 7b1c5e86ae | |
Behdad Esfahbod | 196c6b6c1f | |
Behdad Esfahbod | b9d4758bf9 | |
Behdad Esfahbod | 3c59943433 | |
Behdad Esfahbod | 6311b72fcc | |
Behdad Esfahbod | 9b66e45481 | |
Behdad Esfahbod | c5a88a068b | |
Behdad Esfahbod | 8215e70632 | |
Behdad Esfahbod | faaae04359 | |
Behdad Esfahbod | d5d8fc046f | |
Behdad Esfahbod | 1f86890b75 | |
Behdad Esfahbod | f95c2cc6d5 | |
Behdad Esfahbod | 65f7bac73c | |
Behdad Esfahbod | d894a10699 | |
Behdad Esfahbod | 91eb2f49db | |
Behdad Esfahbod | 4260de12c1 | |
Behdad Esfahbod | 1537e252ba | |
Behdad Esfahbod | 918df8ccaf | |
Behdad Esfahbod | 7fff4a19ad | |
Behdad Esfahbod | 41362cc339 | |
Behdad Esfahbod | 6746ca4ae2 | |
Behdad Esfahbod | b08026187a | |
Behdad Esfahbod | f2d227ad9f | |
Behdad Esfahbod | e7540043de | |
Behdad Esfahbod | 65966e0c3d | |
Simon Cozens | 92a57b4b4a | |
Simon Cozens | db789eacb4 | |
Behdad Esfahbod | 0d237d062e | |
Behdad Esfahbod | 2004528cf8 | |
Simon Cozens | 83b9c34f0b | |
Simon Cozens | 840b5dff73 | |
Behdad Esfahbod | 28a7c1f932 | |
Behdad Esfahbod | b5b577f29f | |
Behdad Esfahbod | 1023a80d39 | |
Behdad Esfahbod | 4ad659a608 | |
Simon Cozens | 514a8d58d8 | |
Simon Cozens | 74deaa9e78 | |
Behdad Esfahbod | 4bdfaeecef | |
Behdad Esfahbod | 77f0f3c11a | |
Behdad Esfahbod | 16ecb96922 | |
Behdad Esfahbod | 2568890d15 | |
Behdad Esfahbod | cb382e489d | |
Behdad Esfahbod | 73de7d4d05 | |
Behdad Esfahbod | a267249930 | |
Behdad Esfahbod | 99d2dab30f | |
Behdad Esfahbod | ed39e07661 | |
Behdad Esfahbod | c5af08c0dc | |
Behdad Esfahbod | aa8f9eed63 | |
Behdad Esfahbod | 8d960dfe68 | |
Behdad Esfahbod | 1c6d640e1f | |
Behdad Esfahbod | 9f8ad3928a | |
Behdad Esfahbod | 2327fe9d8a | |
Behdad Esfahbod | b130b2b331 | |
Behdad Esfahbod | ec3270c7bb | |
Behdad Esfahbod | cbc71c56bc | |
Behdad Esfahbod | 39f8703df1 | |
Behdad Esfahbod | fea3ffe031 | |
Behdad Esfahbod | fe557e2f21 | |
Behdad Esfahbod | b3b6e8da86 | |
Behdad Esfahbod | 863ec70e12 | |
Behdad Esfahbod | 1acff90b03 | |
Behdad Esfahbod | 7537d48f08 | |
Behdad Esfahbod | d7f76f30b0 | |
Behdad Esfahbod | 5738851b1c | |
Behdad Esfahbod | 2bde2f66f1 | |
Behdad Esfahbod | a08dbf41cd | |
Behdad Esfahbod | 0a51ed31b0 | |
Behdad Esfahbod | a5c844a1de | |
Behdad Esfahbod | 23b58b5667 | |
Behdad Esfahbod | 149199ee26 | |
Behdad Esfahbod | 2d295183b8 | |
Behdad Esfahbod | 07ece17495 | |
Behdad Esfahbod | ae981eec8e | |
Behdad Esfahbod | 5ab7f7a7d4 | |
Behdad Esfahbod | 551528a6e6 | |
Behdad Esfahbod | 926f8a326e | |
Behdad Esfahbod | c1dc112121 | |
Simon Cozens | e0fec1dda0 | |
Behdad Esfahbod | af1f41a43e | |
Behdad Esfahbod | 099a0150e1 | |
Behdad Esfahbod | 851ef1380a | |
Behdad Esfahbod | d38f02ab30 | |
Behdad Esfahbod | cbd5c554fb | |
Behdad Esfahbod | 3bec8dca1c | |
Behdad Esfahbod | d45a13f101 | |
Behdad Esfahbod | 5cecfe8659 | |
Behdad Esfahbod | 50b22368d0 | |
Simon Cozens | 743cd2c46e | |
Behdad Esfahbod | 3b88bd9742 | |
Behdad Esfahbod | d7a6671676 | |
Behdad Esfahbod | 108995bbc6 | |
Behdad Esfahbod | 69b1707d82 | |
Behdad Esfahbod | e87b1b3ec3 | |
Behdad Esfahbod | e03726d269 | |
Behdad Esfahbod | 747dcf561d | |
Behdad Esfahbod | 6b72a18c7b | |
Behdad Esfahbod | 42d121ae79 | |
Behdad Esfahbod | 980706441b | |
Behdad Esfahbod | 65efad6b59 | |
Behdad Esfahbod | bb8a04cbad | |
Simon Cozens | 11fc83c0ba | |
Simon Cozens | 36dd27bf3f | |
Behdad Esfahbod | 3bc0ecf28c | |
Behdad Esfahbod | 62f3c7cf67 | |
Behdad Esfahbod | 4c8a414a10 | |
Behdad Esfahbod | 63904538c8 | |
Behdad Esfahbod | bd28d01a6a | |
Simon Cozens | ed1a70c7e8 | |
Simon Cozens | 89c50b0ccb | |
Simon Cozens | f0200445d0 | |
Behdad Esfahbod | fd1f7f46f4 | |
Behdad Esfahbod | 9f4dc2e103 | |
Behdad Esfahbod | e79a7318c4 | |
Behdad Esfahbod | 829ba74284 | |
Behdad Esfahbod | 11c6d46086 | |
Simon Cozens | 05bf984212 | |
Behdad Esfahbod | bdbc1568ba | |
Behdad Esfahbod | db8e51e01b | |
Behdad Esfahbod | fcc8be409b | |
Behdad Esfahbod | 425fc7f3ee |
|
@ -1,9 +1,5 @@
|
|||
name: CIFuzz
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
20
SECURITY.md
20
SECURITY.md
|
@ -1,20 +0,0 @@
|
|||
# Security Policy
|
||||
|
||||
If you have discovered a security vulnerability in this project, please report it
|
||||
privately. **Do not disclose it as a public issue.** This gives me time to work with you
|
||||
to fix the issue before public exposure, reducing the chance that the exploit will be
|
||||
used before a patch is released.
|
||||
|
||||
You may submit the report in the following ways:
|
||||
|
||||
- send an email to behdad@behdad.org and harfbuzz-admin@googlegroups.com; and/or
|
||||
- send me a [private vulnerability report](https://github.com/harfbuzz/harfbuzz/security/advisories/new)
|
||||
|
||||
Please provide the following information in your report:
|
||||
|
||||
- A description of the vulnerability and its impact
|
||||
- How to reproduce the issue
|
||||
|
||||
This project is mostly maintained by two developers, working on a reasonable effort
|
||||
basis. As such, we ask that you give us 90 days to work on a fix before public
|
||||
disclosure.
|
23
configure.ac
23
configure.ac
|
@ -417,6 +417,28 @@ AM_CONDITIONAL(HAVE_CORETEXT, $have_coretext)
|
|||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(wasm,
|
||||
[AS_HELP_STRING([--with-wasm=@<:@yes/no/auto@:>@],
|
||||
[Use the wasm-micro-runtime library @<:@default=no@:>@])],,
|
||||
[with_wasm=no])
|
||||
have_wasm=false
|
||||
if test "x$with_wasm" = "xyes" -o "x$with_wasm" = "xauto"; then
|
||||
AC_CHECK_HEADERS(wasm_export.h, have_wasm=true)
|
||||
fi
|
||||
if test "x$with_wasm" = "xyes" -a "x$have_wasm" != "xtrue"; then
|
||||
AC_MSG_ERROR([wasm support requested but not found])
|
||||
fi
|
||||
if $have_wasm; then
|
||||
WASM_CFLAGS=
|
||||
WASM_LIBS="-liwasm"
|
||||
AC_SUBST(WASM_CFLAGS)
|
||||
AC_SUBST(WASM_LIBS)
|
||||
AC_DEFINE(HAVE_WASM, 1, [Have wasm-micro-runtime library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_WASM, $have_wasm)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
|
@ -478,6 +500,7 @@ Platform shapers (not normally needed):
|
|||
DirectWrite: ${have_directwrite}
|
||||
GDI: ${have_gdi}
|
||||
Uniscribe: ${have_uniscribe}
|
||||
WebAssembly: ${have_wasm}
|
||||
|
||||
Other features:
|
||||
Documentation: ${enable_gtk_doc}
|
||||
|
|
|
@ -197,6 +197,7 @@ HB_HAS_GOBJECT
|
|||
HB_HAS_GRAPHITE
|
||||
HB_HAS_ICU
|
||||
HB_HAS_UNISCRIBE
|
||||
HB_HAS_WASM
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
|
|
@ -41,6 +41,7 @@ ignore_headers = [
|
|||
'hb-gobject-enums.h',
|
||||
'hb-gobject-enums-tmp.h',
|
||||
'hb-gobject-structs.h',
|
||||
'hb-wasm-api.h',
|
||||
]
|
||||
|
||||
gnome.gtkdoc('harfbuzz',
|
||||
|
|
|
@ -174,9 +174,7 @@
|
|||
<para>
|
||||
HarfBuzz provides integration points with FreeType at the
|
||||
face-object and font-object level and for the font-functions
|
||||
virtual-method structure of a font object. These functions
|
||||
make it easy for clients that use FreeType for rasterization
|
||||
or font-loading, to use HarfBuzz for shaping. To use the
|
||||
virtual-method structure of a font object. To use the
|
||||
FreeType-integration API, include the
|
||||
<filename>hb-ft.h</filename> header.
|
||||
</para>
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
# The web assembly shaper
|
||||
|
||||
If the standard OpenType shaping engine doesn't give you enough flexibility, Harfbuzz allows you to write your own shaping engine in WebAssembly and embed it into your font! Any font which contains a `Wasm` table will be passed to the WebAssembly shaper.
|
||||
|
||||
## How to write a shaping engine in Rust
|
||||
|
||||
Here are the steps to create an example shaping engine in Rust: (These examples can also be found in `src/wasm/sample/rust`)
|
||||
|
||||
* First, install wasm-pack, which helps us to generate optimized WASM files. It writes some Javascript bridge code that we don't need, but it makes the build and deployment process much easier:
|
||||
|
||||
```
|
||||
$ cargo install wasm-pack
|
||||
```
|
||||
|
||||
* Now let's create a new library:
|
||||
|
||||
```
|
||||
$ cargo new --lib hello-wasm
|
||||
```
|
||||
|
||||
* We need the target to be a dynamic library, and we're going to use `bindgen` to export our Rust function to WASM, so let's put these lines in the `Cargo.toml`. The Harfbuzz sources contain a Rust crate which makes it easy to create the shaper, so we'll specify that as a dependency as well:
|
||||
|
||||
```toml
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
[dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
harfbuzz-wasm = { path = "your-harfbuzz-source/src/wasm/rust/harfbuzz-wasm"}
|
||||
```
|
||||
|
||||
*
|
||||
* And now we'll create our shaper code. In `src/lib.rs`:
|
||||
|
||||
```rust
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn shape(_shape_plan:u32, font_ref: u32, buf_ref: u32, _features: u32, _num_features: u32) -> i32 {
|
||||
1 // success!
|
||||
}
|
||||
```
|
||||
|
||||
This exports a shaping function which takes four arguments, tokens representing the shaping plan, the font and the buffer, and returns a status value. We can pass these tokens back to Harfbuzz in order to use its native functions on the font and buffer objects. More on native functions later - let's get this shaper compiled and added into a font:
|
||||
|
||||
* To compile the shaper, run `wasm-pack build --target nodejs`:
|
||||
|
||||
```
|
||||
INFO]: 🎯 Checking for the Wasm target...
|
||||
[INFO]: 🌀 Compiling to Wasm...
|
||||
Compiling hello-wasm v0.1.0 (...)
|
||||
Finished release [optimized] target(s) in 0.20s
|
||||
[WARN]: ⚠️ origin crate has no README
|
||||
[INFO]: ⬇️ Installing wasm-bindgen...
|
||||
[INFO]: Optimizing wasm binaries with `wasm-opt`...
|
||||
[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended
|
||||
[INFO]: ✨ Done in 0.40s
|
||||
```
|
||||
|
||||
You'll find the output WASM file in `pkg/hello_wasm_bg.wasm`
|
||||
|
||||
* Now we need to get it into a font.
|
||||
|
||||
We provide a utility to do this called `addTable.py` in the `src/` directory:
|
||||
|
||||
```
|
||||
% python3 ~/harfbuzz/src/addTable.py test.ttf test-wasm.ttf pkg/hello_wasm_bg.wasm
|
||||
```
|
||||
|
||||
And now we can run it!
|
||||
|
||||
```
|
||||
% hb-shape test-wasm.ttf abc --shapers=wasm
|
||||
[cent=0|sterling=1|fraction=2]
|
||||
```
|
||||
|
||||
(The `--shapers=wasm` isn't necessary, as any font with a `Wasm` table will be sent to the WASM shaper if it's enabled, but it proves the point.)
|
||||
|
||||
Congratulations! Our shaper did nothing, but in Rust! Now let's do something - it's time for the Hello World of WASM shaping.
|
||||
|
||||
* To say hello world, we're going to have to use a native function.
|
||||
|
||||
In debugging builds of Harfbuzz, we can print some output from the web assembly module to the host's standard output using the `debug` function. To make this easier, we've got the `harfbuzz-wasm` crate:
|
||||
|
||||
```rust
|
||||
use harfbuzz_wasm::debug;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn shape(_shape_plan:u32, _font_ref: u32, _buf_ref: u32, _features: u32, _num_features: u32) -> i32 {
|
||||
debug("Hello from Rust!\n");
|
||||
1
|
||||
}
|
||||
```
|
||||
|
||||
With this compiled into a WASM module, and installed into our font again, finally our fonts can talk to us!
|
||||
|
||||
```
|
||||
$ hb-shape test-wasm.ttf abc
|
||||
Hello from Rust!
|
||||
[cent=0|sterling=1|fraction=2]
|
||||
```
|
||||
|
||||
Now let's start to do some actual, you know, *shaping*. The first thing a shaping engine normally does is (a) map the items in the buffer from Unicode codepoints into glyphs in the font, and (b) set the advance width of the buffer items to the default advance width for those glyphs. We're going to need to interrogate the font for this information, and write back to the buffer. Harfbuzz provides us with opaque pointers to the memory for the font and buffer, but we can turn those into useful Rust structures using the `harfbuzz-wasm` crate again:
|
||||
|
||||
```rust
|
||||
use wasm_bindgen::prelude::*;
|
||||
use harfbuzz_wasm::{Font, GlyphBuffer};
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn shape(_shape_plan:u32, font_ref: u32, buf_ref: u32, _features: u32, _num_features: u32) -> i32 {
|
||||
let font = Font::from_ref(font_ref);
|
||||
let mut buffer = GlyphBuffer::from_ref(buf_ref);
|
||||
for mut item in buffer.glyphs.iter_mut() {
|
||||
// Map character to glyph
|
||||
item.codepoint = font.get_glyph(codepoint, 0);
|
||||
// Set advance width
|
||||
item.h_advance = font.get_glyph_h_advance(item.codepoint);
|
||||
}
|
||||
1
|
||||
}
|
||||
```
|
||||
|
||||
The `GlyphBuffer`, unlike in Harfbuzz, combines positioning and information in a single structure, to save you having to zip and unzip all the time. It also takes care of marshalling the buffer back to Harfbuzz-land; when a GlyphBuffer is dropped, it writes its contents back through the reference into Harfbuzz's address space. (If you want a different representation of buffer items, you can have one: `GlyphBuffer` is implemented as a `Buffer<Glyph>`, and if you make your own struct which implements the `BufferItem` trait, you can make a buffer out of that instead.)
|
||||
|
||||
One easy way to write your own shapers is to make use of OpenType shaping for the majority of your shaping work, and then make changes to the pre-shaped buffer afterwards. You can do this using the `Font.shape_with` method. Run this on a buffer reference, and then construct your `GlyphBuffer` object afterwards:
|
||||
|
||||
```rust
|
||||
use harfbuzz_wasm::{Font, GlyphBuffer};
|
||||
use tiny_rng::{Rand, Rng};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn shape(_shape_plan:u32, font_ref: u32, buf_ref: u32, _features: u32, _num_features: u32) -> i32 {
|
||||
let mut rng = Rng::from_seed(123456);
|
||||
|
||||
// Use the default OpenType shaper
|
||||
let font = Font::from_ref(font_ref);
|
||||
font.shape_with(buf_ref, "ot");
|
||||
|
||||
// Now we have a buffer with glyph ids, advance widths etc.
|
||||
// already filled in.
|
||||
let mut buffer = GlyphBuffer::from_ref(buf_ref);
|
||||
for mut item in buffer.glyphs.iter_mut() {
|
||||
// Randomize it!
|
||||
item.x_offset = ((rng.rand_u32() as i32) >> 24) - 120;
|
||||
item.y_offset = ((rng.rand_u32() as i32) >> 24) - 120;
|
||||
}
|
||||
|
||||
1
|
||||
}
|
||||
```
|
||||
|
||||
See the documentation for the `harfbuzz-wasm` crate for all the other
|
11
meson.build
11
meson.build
|
@ -114,6 +114,9 @@ glib_dep = dependency('glib-2.0', required: get_option('glib'))
|
|||
gobject_dep = dependency('gobject-2.0', required: get_option('gobject'))
|
||||
graphite2_dep = dependency('graphite2', required: get_option('graphite2'))
|
||||
graphite_dep = dependency('graphite2', required: get_option('graphite'))
|
||||
wasm_dep = cpp.find_library('iwasm', required: get_option('wasm'))
|
||||
# How to check whether iwasm was built, and hence requires, LLVM?
|
||||
#llvm_dep = cpp.find_library('LLVM-15', required: get_option('wasm'))
|
||||
|
||||
if meson.version().version_compare('>=0.60.0')
|
||||
# pkg-config: icu-uc, cmake: ICU but with components
|
||||
|
@ -229,6 +232,11 @@ if chafa_dep.found()
|
|||
conf.set('HAVE_CHAFA', 1)
|
||||
endif
|
||||
|
||||
if wasm_dep.found()
|
||||
conf.set('HAVE_WASM', 1)
|
||||
conf.set('HB_WASM_MODULE_DIR', '"'+get_option('prefix')+'/'+get_option('libdir')+'/harfbuzz/wasm"')
|
||||
endif
|
||||
|
||||
if graphite2_dep.found() or graphite_dep.found()
|
||||
conf.set('HAVE_GRAPHITE2', 1)
|
||||
endif
|
||||
|
@ -373,10 +381,7 @@ foreach check : check_funcs
|
|||
endforeach
|
||||
|
||||
subdir('src')
|
||||
|
||||
if not get_option('utilities').disabled()
|
||||
subdir('util')
|
||||
endif
|
||||
|
||||
if not get_option('tests').disabled()
|
||||
subdir('test')
|
||||
|
|
|
@ -21,6 +21,8 @@ option('directwrite', type: 'feature', value: 'disabled',
|
|||
description: 'Enable DirectWrite shaper backend on Windows (experimental)')
|
||||
option('coretext', type: 'feature', value: 'disabled',
|
||||
description: 'Enable CoreText shaper backend on macOS')
|
||||
option('wasm', type: 'feature', value: 'disabled',
|
||||
description: 'Enable WebAssembly shaper backend')
|
||||
|
||||
# Common feature options
|
||||
option('tests', type: 'feature', value: 'enabled', yield: true,
|
||||
|
@ -31,8 +33,6 @@ option('docs', type: 'feature', value: 'auto', yield: true,
|
|||
description: 'Generate documentation with gtk-doc')
|
||||
option('doc_tests', type: 'boolean', value: false,
|
||||
description: 'Run gtkdoc-check tests')
|
||||
option('utilities', type: 'feature', value: 'enabled', yield: true,
|
||||
description: 'Build harfbuzz utils')
|
||||
|
||||
option('benchmark', type: 'feature', value: 'disabled',
|
||||
description: 'Enable benchmark tests')
|
||||
|
|
|
@ -114,6 +114,16 @@ else
|
|||
HB_HAS_CORETEXT_DEF = undef HB_HAS_CORETEXT
|
||||
endif
|
||||
|
||||
if HAVE_WASM
|
||||
HBCFLAGS += $(WASM_CFLAGS)
|
||||
HBNONPCLIBS += $(WASM_LIBS)
|
||||
HBSOURCES += $(HB_WASM_sources)
|
||||
HBHEADERS += $(HB_WASM_headers)
|
||||
HB_HAS_WASM_DEF = define HB_HAS_WASM 1
|
||||
else
|
||||
HB_HAS_WASM_DEF = undef HB_HAS_WASM
|
||||
endif
|
||||
|
||||
|
||||
BUILT_SOURCES += \
|
||||
hb-version.h
|
||||
|
@ -273,16 +283,17 @@ DISTCLEANFILES += \
|
|||
hb-features.h: hb-features.h.in $(top_builddir)/config.status
|
||||
$(AM_V_GEN) $(SED) \
|
||||
-e 's/mesondefine HB_HAS_CAIRO/$(HB_HAS_CAIRO_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_CORETEXT/$(HB_HAS_CORETEXT_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_DIRECTWRITE/$(HB_HAS_DIRECTWRITE_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_FREETYPE/$(HB_HAS_FREETYPE_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_GRAPHITE/$(HB_HAS_GRAPHITE_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_GLIB/$(HB_HAS_GLIB_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_GOBJECT/$(HB_HAS_GOBJECT_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_UNISCRIBE/$(HB_HAS_UNISCRIBE_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_DIRECTWRITE/$(HB_HAS_DIRECTWRITE_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_CORETEXT/$(HB_HAS_CORETEXT_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_GRAPHITE/$(HB_HAS_GRAPHITE_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_ICU/$(HB_HAS_ICU_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_UNISCRIBE/$(HB_HAS_UNISCRIBE_DEF)/' \
|
||||
-e 's/mesondefine HB_HAS_WASM/$(HB_HAS_WASM_DEF)/' \
|
||||
"$<" > "$@" || ($(RM) "$@"; false)
|
||||
|
||||
|
||||
|
|
|
@ -338,10 +338,22 @@ HB_GDI_headers = hb-gdi.h
|
|||
HB_UNISCRIBE_sources = hb-uniscribe.cc
|
||||
HB_UNISCRIBE_headers = hb-uniscribe.h
|
||||
|
||||
# Sources for libharfbuzz-gobject and libharfbuzz-icu
|
||||
HB_ICU_sources = hb-icu.cc
|
||||
HB_ICU_headers = hb-icu.h
|
||||
|
||||
HB_WASM_sources = \
|
||||
hb-wasm-api.cc \
|
||||
hb-wasm-api.hh \
|
||||
hb-wasm-api-blob.hh \
|
||||
hb-wasm-api-buffer.hh \
|
||||
hb-wasm-api-common.hh \
|
||||
hb-wasm-api-face.hh \
|
||||
hb-wasm-api-font.hh \
|
||||
hb-wasm-api-shape.hh \
|
||||
hb-wasm-shape.cc \
|
||||
$(NULL)
|
||||
HB_WASM_headers = hb-wasm-api.h
|
||||
|
||||
# Sources for libharfbuzz-subset
|
||||
HB_SUBSET_sources = \
|
||||
hb-number.cc \
|
||||
|
|
|
@ -2213,7 +2213,6 @@ struct COLR
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
#ifndef HB_NO_PAINT
|
||||
bool
|
||||
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
|
||||
{
|
||||
|
@ -2252,7 +2251,6 @@ struct COLR
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
has_paint_for_glyph (hb_codepoint_t glyph) const
|
||||
|
@ -2276,7 +2274,6 @@ struct COLR
|
|||
instancer);
|
||||
}
|
||||
|
||||
#ifndef HB_NO_PAINT
|
||||
bool
|
||||
paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
|
||||
{
|
||||
|
@ -2363,7 +2360,6 @@ struct COLR
|
|||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Table version number (starts at 0). */
|
||||
|
|
|
@ -29,9 +29,6 @@ struct Ligature
|
|||
bool intersects (const hb_set_t *glyphs) const
|
||||
{ return hb_all (component, glyphs); }
|
||||
|
||||
bool intersects_lig_glyph (const hb_set_t *glyphs) const
|
||||
{ return glyphs->has(ligGlyph); }
|
||||
|
||||
void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
if (!intersects (c->glyphs)) return;
|
||||
|
|
|
@ -34,18 +34,6 @@ struct LigatureSet
|
|||
;
|
||||
}
|
||||
|
||||
bool intersects_lig_glyph (const hb_set_t *glyphs) const
|
||||
{
|
||||
return
|
||||
+ hb_iter (ligature)
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([glyphs] (const Ligature<Types> &_) {
|
||||
return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs);
|
||||
})
|
||||
| hb_any
|
||||
;
|
||||
}
|
||||
|
||||
void closure (hb_closure_context_t *c) const
|
||||
{
|
||||
+ hb_iter (ligature)
|
||||
|
|
|
@ -130,7 +130,7 @@ struct LigatureSubstFormat1_2
|
|||
+ hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
|
||||
| hb_filter (glyphset, hb_first)
|
||||
| hb_filter ([&] (const LigatureSet<Types>& _) {
|
||||
return _.intersects_lig_glyph (&glyphset);
|
||||
return _.intersects (&glyphset);
|
||||
}, hb_second)
|
||||
| hb_map (hb_first)
|
||||
| hb_sink (new_coverage);
|
||||
|
|
|
@ -87,9 +87,11 @@ struct CompositeGlyphRecord
|
|||
}
|
||||
}
|
||||
|
||||
void transform_points (contour_point_vector_t &points,
|
||||
const float (&matrix)[4],
|
||||
const contour_point_t &trans) const
|
||||
void transform_points (contour_point_vector_t &points) const
|
||||
{
|
||||
float matrix[4];
|
||||
contour_point_t trans;
|
||||
if (get_transformation (matrix, trans))
|
||||
{
|
||||
if (scaled_offsets ())
|
||||
{
|
||||
|
@ -102,18 +104,9 @@ struct CompositeGlyphRecord
|
|||
points.translate (trans);
|
||||
}
|
||||
}
|
||||
|
||||
bool get_points (contour_point_vector_t &points) const
|
||||
{
|
||||
float matrix[4];
|
||||
contour_point_t trans;
|
||||
get_transformation (matrix, trans);
|
||||
if (unlikely (!points.resize (points.length + 1))) return false;
|
||||
points[points.length - 1] = trans;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned compile_with_point (const contour_point_t &point,
|
||||
unsigned compile_with_deltas (const contour_point_t &p_delta,
|
||||
char *out) const
|
||||
{
|
||||
const HBINT8 *p = &StructAfter<const HBINT8> (flags);
|
||||
|
@ -128,17 +121,18 @@ struct CompositeGlyphRecord
|
|||
unsigned len_before_val = (const char *)p - (const char *)this;
|
||||
if (flags & ARG_1_AND_2_ARE_WORDS)
|
||||
{
|
||||
// no overflow, copy value
|
||||
// no overflow, copy and update value with deltas
|
||||
hb_memcpy (out, this, len);
|
||||
|
||||
const HBINT16 *px = reinterpret_cast<const HBINT16 *> (p);
|
||||
HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val);
|
||||
o[0] = roundf (point.x);
|
||||
o[1] = roundf (point.y);
|
||||
o[0] = px[0] + roundf (p_delta.x);
|
||||
o[1] = px[1] + roundf (p_delta.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
int new_x = roundf (point.x);
|
||||
int new_y = roundf (point.y);
|
||||
int new_x = p[0] + roundf (p_delta.x);
|
||||
int new_y = p[1] + roundf (p_delta.y);
|
||||
if (new_x <= 127 && new_x >= -128 &&
|
||||
new_y <= 127 && new_y >= -128)
|
||||
{
|
||||
|
@ -149,7 +143,7 @@ struct CompositeGlyphRecord
|
|||
}
|
||||
else
|
||||
{
|
||||
// new point value has an int8 overflow
|
||||
// int8 overflows after deltas applied
|
||||
hb_memcpy (out, this, len_before_val);
|
||||
|
||||
//update flags
|
||||
|
@ -177,7 +171,6 @@ struct CompositeGlyphRecord
|
|||
bool scaled_offsets () const
|
||||
{ return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
|
||||
|
||||
public:
|
||||
bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
|
||||
{
|
||||
matrix[0] = matrix[3] = 1.f;
|
||||
|
@ -232,6 +225,7 @@ struct CompositeGlyphRecord
|
|||
return tx || ty;
|
||||
}
|
||||
|
||||
public:
|
||||
hb_codepoint_t get_gid () const
|
||||
{
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
|
@ -252,27 +246,6 @@ struct CompositeGlyphRecord
|
|||
StructAfter<HBGlyphID16> (flags) = gid;
|
||||
}
|
||||
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
void lower_gid_24_to_16 ()
|
||||
{
|
||||
hb_codepoint_t gid = get_gid ();
|
||||
if (!(flags & GID_IS_24BIT) || gid > 0xFFFFu)
|
||||
return;
|
||||
|
||||
/* Lower the flag and move the rest of the struct down. */
|
||||
|
||||
unsigned size = get_size ();
|
||||
char *end = (char *) this + size;
|
||||
char *p = &StructAfter<char> (flags);
|
||||
p += HBGlyphID24::static_size;
|
||||
|
||||
flags = flags & ~GID_IS_24BIT;
|
||||
set_gid (gid);
|
||||
|
||||
memmove (p - HBGlyphID24::static_size + HBGlyphID16::static_size, p, end - p);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
HBUINT16 flags;
|
||||
HBUINT24 pad;
|
||||
|
@ -331,7 +304,7 @@ struct CompositeGlyph
|
|||
}
|
||||
|
||||
bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes,
|
||||
const contour_point_vector_t &points_with_deltas,
|
||||
const contour_point_vector_t &deltas,
|
||||
hb_bytes_t &dest_bytes /* OUT */)
|
||||
{
|
||||
if (source_bytes.length <= GlyphHeader::static_size ||
|
||||
|
@ -346,7 +319,7 @@ struct CompositeGlyph
|
|||
/* try to allocate more memories than source glyph bytes
|
||||
* in case that there might be an overflow for int8 value
|
||||
* and we would need to use int16 instead */
|
||||
char *o = (char *) hb_calloc (source_len * 2, sizeof (char));
|
||||
char *o = (char *) hb_calloc (source_len + source_len/2, sizeof (char));
|
||||
if (unlikely (!o)) return false;
|
||||
|
||||
const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size);
|
||||
|
@ -356,8 +329,8 @@ struct CompositeGlyph
|
|||
unsigned i = 0, source_comp_len = 0;
|
||||
for (const auto &component : it)
|
||||
{
|
||||
/* last 4 points in points_with_deltas are phantom points and should not be included */
|
||||
if (i >= points_with_deltas.length - 4) {
|
||||
/* last 4 points in deltas are phantom points and should not be included */
|
||||
if (i >= deltas.length - 4) {
|
||||
free (o);
|
||||
return false;
|
||||
}
|
||||
|
@ -370,7 +343,7 @@ struct CompositeGlyph
|
|||
}
|
||||
else
|
||||
{
|
||||
unsigned new_len = component.compile_with_point (points_with_deltas[i], p);
|
||||
unsigned new_len = component.compile_with_deltas (deltas[i], p);
|
||||
p += new_len;
|
||||
}
|
||||
i++;
|
||||
|
|
|
@ -29,14 +29,7 @@ enum phantom_point_index_t
|
|||
|
||||
struct Glyph
|
||||
{
|
||||
enum glyph_type_t {
|
||||
EMPTY,
|
||||
SIMPLE,
|
||||
COMPOSITE,
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
VAR_COMPOSITE,
|
||||
#endif
|
||||
};
|
||||
enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE, VAR_COMPOSITE };
|
||||
|
||||
public:
|
||||
composite_iter_t get_composite_iterator () const
|
||||
|
@ -46,23 +39,15 @@ struct Glyph
|
|||
}
|
||||
var_composite_iter_t get_var_composite_iterator () const
|
||||
{
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
if (type != VAR_COMPOSITE) return var_composite_iter_t ();
|
||||
return VarCompositeGlyph (*header, bytes).iter ();
|
||||
#else
|
||||
return var_composite_iter_t ();
|
||||
#endif
|
||||
}
|
||||
|
||||
const hb_bytes_t trim_padding () const
|
||||
{
|
||||
switch (type) {
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE: return VarCompositeGlyph (*header, bytes).trim_padding ();
|
||||
#endif
|
||||
case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
|
||||
case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding ();
|
||||
case EMPTY: return bytes;
|
||||
default: return bytes;
|
||||
}
|
||||
}
|
||||
|
@ -70,36 +55,27 @@ struct Glyph
|
|||
void drop_hints ()
|
||||
{
|
||||
switch (type) {
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE: return; // No hinting
|
||||
#endif
|
||||
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
|
||||
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return;
|
||||
case EMPTY: return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
void set_overlaps_flag ()
|
||||
{
|
||||
switch (type) {
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE: return; // No overlaps flag
|
||||
#endif
|
||||
case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
|
||||
case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
|
||||
case EMPTY: return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
|
||||
{
|
||||
switch (type) {
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE: return; // No hinting
|
||||
#endif
|
||||
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
|
||||
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
|
||||
case EMPTY: return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,7 +181,7 @@ struct Glyph
|
|||
hb_bytes_t &dest_start, /* IN/OUT */
|
||||
hb_bytes_t &dest_end /* OUT */)
|
||||
{
|
||||
contour_point_vector_t all_points, points_with_deltas;
|
||||
contour_point_vector_t all_points, deltas;
|
||||
unsigned composite_contours = 0;
|
||||
head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
|
||||
unsigned *composite_contours_p = &composite_contours;
|
||||
|
@ -219,7 +195,7 @@ struct Glyph
|
|||
composite_contours_p = nullptr;
|
||||
}
|
||||
|
||||
if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
|
||||
if (!get_points (font, glyf, all_points, &deltas, head_maxp_info_p, composite_contours_p, false, false))
|
||||
return false;
|
||||
|
||||
// .notdef, set type to empty so we only update metrics and don't compile bytes for
|
||||
|
@ -233,20 +209,11 @@ struct Glyph
|
|||
}
|
||||
|
||||
//dont compile bytes when pinned at default, just recalculate bounds
|
||||
if (!plan->pinned_at_default)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
case VAR_COMPOSITE:
|
||||
// TODO
|
||||
dest_end = hb_bytes_t ();
|
||||
break;
|
||||
#endif
|
||||
|
||||
if (!plan->pinned_at_default) {
|
||||
switch (type) {
|
||||
case COMPOSITE:
|
||||
if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
|
||||
points_with_deltas,
|
||||
deltas,
|
||||
dest_end))
|
||||
return false;
|
||||
break;
|
||||
|
@ -256,7 +223,7 @@ struct Glyph
|
|||
dest_end))
|
||||
return false;
|
||||
break;
|
||||
case EMPTY:
|
||||
default:
|
||||
/* set empty bytes for empty glyph
|
||||
* do not use source glyph's pointers */
|
||||
dest_start = hb_bytes_t ();
|
||||
|
@ -280,7 +247,7 @@ struct Glyph
|
|||
template <typename accelerator_t>
|
||||
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
|
||||
contour_point_vector_t &all_points /* OUT */,
|
||||
contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
|
||||
contour_point_vector_t *deltas = nullptr, /* OUT */
|
||||
head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
|
||||
unsigned *composite_contours = nullptr, /* OUT */
|
||||
bool shift_points_hori = true,
|
||||
|
@ -320,8 +287,9 @@ struct Glyph
|
|||
break;
|
||||
case COMPOSITE:
|
||||
{
|
||||
for (auto &item : get_composite_iterator ())
|
||||
if (unlikely (!item.get_points (points))) return false;
|
||||
/* pseudo component points for each component in composite glyph */
|
||||
unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ());
|
||||
if (unlikely (!points.resize (num_points))) return false;
|
||||
break;
|
||||
}
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
|
@ -331,7 +299,7 @@ struct Glyph
|
|||
if (unlikely (!item.get_points (points))) return false;
|
||||
}
|
||||
#endif
|
||||
case EMPTY:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -359,11 +327,17 @@ struct Glyph
|
|||
#endif
|
||||
;
|
||||
phantoms[PHANTOM_LEFT].x = h_delta;
|
||||
phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
|
||||
phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
|
||||
phantoms[PHANTOM_TOP].y = v_orig;
|
||||
phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
|
||||
}
|
||||
|
||||
if (deltas != nullptr && depth == 0 && type == COMPOSITE)
|
||||
{
|
||||
if (unlikely (!deltas->resize (points.length))) return false;
|
||||
deltas->copy_vector (points);
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
glyf_accelerator.gvar->apply_deltas_to_points (gid,
|
||||
coords,
|
||||
|
@ -372,10 +346,13 @@ struct Glyph
|
|||
|
||||
// mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
|
||||
// with child glyphs' points
|
||||
if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
|
||||
if (deltas != nullptr && depth == 0 && type == COMPOSITE)
|
||||
{
|
||||
if (unlikely (!points_with_deltas->resize (points.length))) return false;
|
||||
points_with_deltas->copy_vector (points);
|
||||
for (unsigned i = 0 ; i < points.length; i++)
|
||||
{
|
||||
deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x;
|
||||
deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y;
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
@ -396,7 +373,7 @@ struct Glyph
|
|||
.get_points (font,
|
||||
glyf_accelerator,
|
||||
comp_points,
|
||||
points_with_deltas,
|
||||
deltas,
|
||||
head_maxp_info,
|
||||
composite_contours,
|
||||
shift_points_hori,
|
||||
|
@ -412,12 +389,11 @@ struct Glyph
|
|||
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
|
||||
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
|
||||
|
||||
float matrix[4];
|
||||
contour_point_t default_trans;
|
||||
item.get_transformation (matrix, default_trans);
|
||||
/* Apply component transformation & translation */
|
||||
item.transform_points (comp_points);
|
||||
|
||||
/* Apply component transformation & translation (with deltas applied) */
|
||||
item.transform_points (comp_points, matrix, points[comp_index]);
|
||||
/* Apply translation from gvar */
|
||||
comp_points.translate (points[comp_index]);
|
||||
|
||||
if (item.is_anchored ())
|
||||
{
|
||||
|
@ -472,7 +448,7 @@ struct Glyph
|
|||
.get_points (font,
|
||||
glyf_accelerator,
|
||||
comp_points,
|
||||
points_with_deltas,
|
||||
deltas,
|
||||
head_maxp_info,
|
||||
nullptr,
|
||||
shift_points_hori,
|
||||
|
@ -501,7 +477,7 @@ struct Glyph
|
|||
all_points.extend (phantoms);
|
||||
} break;
|
||||
#endif
|
||||
case EMPTY:
|
||||
default:
|
||||
all_points.extend (phantoms);
|
||||
break;
|
||||
}
|
||||
|
@ -527,8 +503,6 @@ struct Glyph
|
|||
}
|
||||
|
||||
hb_bytes_t get_bytes () const { return bytes; }
|
||||
glyph_type_t get_type () const { return type; }
|
||||
const GlyphHeader *get_header () const { return header; }
|
||||
|
||||
Glyph () : bytes (),
|
||||
header (bytes.as<GlyphHeader> ()),
|
||||
|
@ -544,9 +518,7 @@ struct Glyph
|
|||
int num_contours = header->numberOfContours;
|
||||
if (unlikely (num_contours == 0)) type = EMPTY;
|
||||
else if (num_contours > 0) type = SIMPLE;
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
else if (num_contours == -2) type = VAR_COMPOSITE;
|
||||
#endif
|
||||
else type = COMPOSITE; /* negative numbers */
|
||||
}
|
||||
|
||||
|
@ -554,7 +526,7 @@ struct Glyph
|
|||
hb_bytes_t bytes;
|
||||
const GlyphHeader *header;
|
||||
hb_codepoint_t gid;
|
||||
glyph_type_t type;
|
||||
unsigned type;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -34,11 +34,6 @@ struct SimpleGlyph
|
|||
unsigned int length (unsigned int instruction_len) const
|
||||
{ return instruction_len_offset () + 2 + instruction_len; }
|
||||
|
||||
bool has_instructions_length () const
|
||||
{
|
||||
return instruction_len_offset () + 2 <= bytes.length;
|
||||
}
|
||||
|
||||
unsigned int instructions_length () const
|
||||
{
|
||||
unsigned int instruction_length_offset = instruction_len_offset ();
|
||||
|
@ -99,7 +94,6 @@ struct SimpleGlyph
|
|||
/* zero instruction length */
|
||||
void drop_hints ()
|
||||
{
|
||||
if (!has_instructions_length ()) return;
|
||||
GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
|
||||
(HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
|
||||
}
|
||||
|
|
|
@ -27,12 +27,7 @@ struct SubsetGlyph
|
|||
TRACE_SERIALIZE (this);
|
||||
|
||||
hb_bytes_t dest_glyph = dest_start.copy (c);
|
||||
hb_bytes_t end_copy = dest_end.copy (c);
|
||||
if (!end_copy.arrayZ || !dest_glyph.arrayZ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + end_copy.length);
|
||||
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
|
||||
unsigned int pad_length = use_short_loca ? padding () : 0;
|
||||
DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
|
||||
|
||||
|
@ -46,68 +41,13 @@ struct SubsetGlyph
|
|||
|
||||
if (unlikely (!dest_glyph.length)) return_trace (true);
|
||||
|
||||
/* update components gids. */
|
||||
/* update components gids */
|
||||
for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
|
||||
{
|
||||
hb_codepoint_t new_gid;
|
||||
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
|
||||
const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid);
|
||||
}
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ())
|
||||
{
|
||||
hb_codepoint_t new_gid;
|
||||
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
|
||||
const_cast<VarCompositeGlyphRecord &> (_).set_gid (new_gid);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
auto it = Glyph (dest_glyph).get_composite_iterator ();
|
||||
if (it)
|
||||
{
|
||||
/* lower GID24 to GID16 in components if possible.
|
||||
*
|
||||
* TODO: VarComposite. Not as critical, since VarComposite supports
|
||||
* gid24 from the first version. */
|
||||
char *p = it ? (char *) &*it : nullptr;
|
||||
char *q = p;
|
||||
const char *end = dest_glyph.arrayZ + dest_glyph.length;
|
||||
while (it)
|
||||
{
|
||||
auto &rec = const_cast<CompositeGlyphRecord &> (*it);
|
||||
++it;
|
||||
|
||||
q += rec.get_size ();
|
||||
|
||||
rec.lower_gid_24_to_16 ();
|
||||
|
||||
unsigned size = rec.get_size ();
|
||||
|
||||
memmove (p, &rec, size);
|
||||
|
||||
p += size;
|
||||
}
|
||||
memmove (p, q, end - q);
|
||||
p += end - q;
|
||||
|
||||
/* We want to shorten the glyph, but we can't do that without
|
||||
* updating the length in the loca table, which is already
|
||||
* written out :-(. So we just fill the rest of the glyph with
|
||||
* harmless instructions, since that's what they will be
|
||||
* interpreted as.
|
||||
*
|
||||
* Should move the lowering to _populate_subset_glyphs() to
|
||||
* fix this issue. */
|
||||
|
||||
hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p);
|
||||
p += end - p;
|
||||
dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ);
|
||||
|
||||
// TODO: Padding; & trim serialized bytes.
|
||||
// TODO: Update length in loca. Ugh.
|
||||
}
|
||||
#endif
|
||||
|
||||
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||
Glyph (dest_glyph).drop_hints ();
|
||||
|
|
|
@ -71,14 +71,6 @@ struct VarCompositeGlyphRecord
|
|||
return StructAfter<const HBGlyphID16> (numAxes);
|
||||
}
|
||||
|
||||
void set_gid (hb_codepoint_t gid)
|
||||
{
|
||||
if (flags & GID_IS_24BIT)
|
||||
StructAfter<HBGlyphID24> (numAxes) = gid;
|
||||
else
|
||||
StructAfter<HBGlyphID16> (numAxes) = gid;
|
||||
}
|
||||
|
||||
unsigned get_numAxes () const
|
||||
{
|
||||
return numAxes;
|
||||
|
@ -352,13 +344,6 @@ struct VarCompositeGlyph
|
|||
var_composite_iter_t iter () const
|
||||
{ return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); }
|
||||
|
||||
const hb_bytes_t trim_padding () const
|
||||
{
|
||||
unsigned length = GlyphHeader::static_size;
|
||||
for (auto &comp : iter ())
|
||||
length += comp.get_size ();
|
||||
return bytes.sub_array (0, length);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -241,8 +241,6 @@ struct glyf_accelerator_t
|
|||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
struct points_aggregator_t
|
||||
{
|
||||
|
@ -306,6 +304,7 @@ struct glyf_accelerator_t
|
|||
contour_point_t *get_phantoms_sink () { return phantoms; }
|
||||
};
|
||||
|
||||
public:
|
||||
unsigned
|
||||
get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
|
||||
{
|
||||
|
@ -347,15 +346,6 @@ struct glyf_accelerator_t
|
|||
}
|
||||
#endif
|
||||
|
||||
bool get_leading_bearing_without_var_unscaled (hb_codepoint_t gid, bool is_vertical, int *lsb) const
|
||||
{
|
||||
if (unlikely (gid >= num_glyphs)) return false;
|
||||
if (is_vertical) return false; // TODO Humm, what to do here?
|
||||
|
||||
*lsb = glyph_for_gid (gid).get_header ()->xMin;
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
|
||||
{
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import sys
|
||||
from fontTools.ttLib import TTFont
|
||||
from fontTools.ttLib.tables.DefaultTable import DefaultTable
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
print("usage: python addTable.py input.ttf output.ttf Wasm.bin")
|
||||
sys.exit(1)
|
||||
|
||||
font = TTFont(sys.argv[1])
|
||||
|
||||
wasm_table = DefaultTable("Wasm")
|
||||
wasm_table.data = open(sys.argv[3], "rb").read()
|
||||
|
||||
font["Wasm"] = wasm_table
|
||||
|
||||
font.save(sys.argv[2])
|
|
@ -58,3 +58,5 @@
|
|||
#include "hb-ucd.cc"
|
||||
#include "hb-unicode.cc"
|
||||
#include "hb-uniscribe.cc"
|
||||
#include "hb-wasm-api.cc"
|
||||
#include "hb-wasm-shape.cc"
|
||||
|
|
|
@ -464,8 +464,7 @@ enum { DELETED_GLYPH = 0xFFFF };
|
|||
template <typename T>
|
||||
struct Entry
|
||||
{
|
||||
// This does seem like it's ever called.
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
/* Note, we don't recurse-sanitize data because we don't access it.
|
||||
|
@ -493,8 +492,7 @@ struct Entry
|
|||
template <>
|
||||
struct Entry<void>
|
||||
{
|
||||
// This does seem like it's ever called.
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this));
|
||||
|
|
|
@ -38,10 +38,6 @@
|
|||
|
||||
/*
|
||||
* Atomic integers and pointers.
|
||||
*
|
||||
* hb_atomic_int_t and hb_atomic_ptr_t are typedefs to the actual
|
||||
* atomic type. They are guaranteed to be at least 32 bits wide.
|
||||
* hb_atomic_int_t is signed.
|
||||
*/
|
||||
|
||||
|
||||
|
|
|
@ -40,11 +40,6 @@
|
|||
* Buffers serve a dual role in HarfBuzz; before shaping, they hold
|
||||
* the input characters that are passed to hb_shape(), and after
|
||||
* shaping they hold the output glyphs.
|
||||
*
|
||||
* The input buffer is a sequence of Unicode codepoints, with
|
||||
* associated attributes such as direction and script. The output
|
||||
* buffer is a sequence of glyphs, with associated attributes such
|
||||
* as position and cluster.
|
||||
**/
|
||||
|
||||
|
||||
|
|
|
@ -493,6 +493,13 @@ struct hb_buffer_t
|
|||
|
||||
HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size);
|
||||
|
||||
HB_NODISCARD bool resize (unsigned length)
|
||||
{
|
||||
assert (!have_output);
|
||||
if (unlikely (!ensure (length))) return false;
|
||||
len = length;
|
||||
return true;
|
||||
}
|
||||
HB_NODISCARD bool ensure (unsigned int size)
|
||||
{ return likely (!size || size < allocated) ? true : enlarge (size); }
|
||||
|
||||
|
|
|
@ -30,19 +30,7 @@
|
|||
#include "hb.hh"
|
||||
|
||||
|
||||
/* Implements a lockfree cache for int->int functions.
|
||||
*
|
||||
* The cache is a fixed-size array of 16-bit or 32-bit integers.
|
||||
* The key is split into two parts: the cache index and the rest.
|
||||
*
|
||||
* The cache index is used to index into the array. The rest is used
|
||||
* to store the key and the value.
|
||||
*
|
||||
* The value is stored in the least significant bits of the integer.
|
||||
* The key is stored in the most significant bits of the integer.
|
||||
* The key is shifted by cache_bits to the left to make room for the
|
||||
* value.
|
||||
*/
|
||||
/* Implements a lockfree cache for int->int functions. */
|
||||
|
||||
template <unsigned int key_bits=16,
|
||||
unsigned int value_bits=8 + 32 - key_bits,
|
||||
|
|
|
@ -389,6 +389,10 @@ struct hb_no_trace_t {
|
|||
#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
|
||||
#endif
|
||||
|
||||
#ifndef HB_DEBUG_WASM
|
||||
#define HB_DEBUG_WASM (HB_DEBUG+0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* With tracing.
|
||||
*/
|
||||
|
|
|
@ -47,12 +47,6 @@
|
|||
* More precisely, a font face represents a single face in a binary font file.
|
||||
* Font faces are typically built from a binary blob and a face index.
|
||||
* Font faces are used to create fonts.
|
||||
*
|
||||
* A font face can be created from a binary blob using hb_face_create().
|
||||
* The face index is used to select a face from a binary blob that contains
|
||||
* multiple faces. For example, a binary blob that contains both a regular
|
||||
* and a bold face can be used to create two font faces, one for each face
|
||||
* index.
|
||||
**/
|
||||
|
||||
|
||||
|
@ -203,7 +197,7 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
|
|||
* a face index into that blob.
|
||||
*
|
||||
* The face index is used for blobs of file formats such as TTC and
|
||||
* DFont that can contain more than one face. Face indices within
|
||||
* and DFont that can contain more than one face. Face indices within
|
||||
* such collections are zero-based.
|
||||
*
|
||||
* <note>Note: If the blob font format is not a collection, @index
|
||||
|
|
|
@ -76,7 +76,7 @@ struct hb_face_t
|
|||
if (unlikely (!reference_table_func))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
blob = reference_table_func (/*Oh, well.*/const_cast<hb_face_t *> (this), tag, user_data);
|
||||
blob = reference_table_func (/*XXX*/const_cast<hb_face_t *> (this), tag, user_data);
|
||||
if (unlikely (!blob))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
|
|
|
@ -106,6 +106,13 @@ HB_BEGIN_DECLS
|
|||
*/
|
||||
#mesondefine HB_HAS_UNISCRIBE
|
||||
|
||||
/**
|
||||
* HB_HAS_WASM:
|
||||
*
|
||||
* Defined if Harfbuzz has been built with WebAssembly support.
|
||||
*/
|
||||
#mesondefine HB_HAS_WASM
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
|
|
|
@ -59,11 +59,6 @@
|
|||
*
|
||||
* HarfBuzz provides a built-in set of lightweight default
|
||||
* functions for each method in #hb_font_funcs_t.
|
||||
*
|
||||
* The default font functions are implemented in terms of the
|
||||
* #hb_font_funcs_t methods of the parent font object. This allows
|
||||
* client programs to override only the methods they need to, and
|
||||
* otherwise inherit the parent font's implementation, if any.
|
||||
**/
|
||||
|
||||
|
||||
|
|
|
@ -248,6 +248,21 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
|
|||
gr_fref_set_feature_value (fref, features[i].value, feats);
|
||||
}
|
||||
|
||||
hb_direction_t direction = buffer->props.direction;
|
||||
hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script);
|
||||
/* TODO vertical:
|
||||
* The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
|
||||
* Ogham fonts are supposed to be implemented BTT or not. Need to research that
|
||||
* first. */
|
||||
if ((HB_DIRECTION_IS_HORIZONTAL (direction) &&
|
||||
direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) ||
|
||||
(HB_DIRECTION_IS_VERTICAL (direction) &&
|
||||
direction != HB_DIRECTION_TTB))
|
||||
{
|
||||
hb_buffer_reverse_clusters (buffer);
|
||||
direction = HB_DIRECTION_REVERSE (direction);
|
||||
}
|
||||
|
||||
gr_segment *seg = nullptr;
|
||||
const gr_slot *is;
|
||||
unsigned int ci = 0, ic = 0;
|
||||
|
@ -261,21 +276,11 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
|
|||
for (unsigned int i = 0; i < buffer->len; ++i)
|
||||
chars[i] = buffer->info[i].codepoint;
|
||||
|
||||
/* TODO ensure_native_direction. */
|
||||
|
||||
hb_tag_t script_tag[HB_OT_MAX_TAGS_PER_SCRIPT];
|
||||
unsigned int count = HB_OT_MAX_TAGS_PER_SCRIPT;
|
||||
hb_ot_tags_from_script_and_language (hb_buffer_get_script (buffer),
|
||||
HB_LANGUAGE_INVALID,
|
||||
&count,
|
||||
script_tag,
|
||||
nullptr, nullptr);
|
||||
|
||||
seg = gr_make_seg (nullptr, grface,
|
||||
count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT,
|
||||
HB_TAG_NONE, // https://github.com/harfbuzz/harfbuzz/issues/3439#issuecomment-1442650148
|
||||
feats,
|
||||
gr_utf32, chars, buffer->len,
|
||||
2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
|
||||
2 | (direction == HB_DIRECTION_RTL ? 1 : 0));
|
||||
|
||||
if (unlikely (!seg)) {
|
||||
if (feats) gr_featureval_destroy (feats);
|
||||
|
@ -327,7 +332,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
|
|||
float yscale = (float) font->y_scale / upem;
|
||||
yscale *= yscale / xscale;
|
||||
unsigned int curradv = 0;
|
||||
if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
|
||||
if (HB_DIRECTION_IS_BACKWARD (direction))
|
||||
{
|
||||
curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale;
|
||||
clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv;
|
||||
|
@ -356,7 +361,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
|
|||
c->num_chars = before - c->base_char;
|
||||
c->base_glyph = ic;
|
||||
c->num_glyphs = 0;
|
||||
if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
|
||||
if (HB_DIRECTION_IS_BACKWARD (direction))
|
||||
{
|
||||
c->advance = curradv - gr_slot_origin_X(is) * xscale;
|
||||
curradv -= c->advance;
|
||||
|
@ -375,7 +380,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
|
|||
clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
|
||||
}
|
||||
|
||||
if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
|
||||
if (HB_DIRECTION_IS_BACKWARD (direction))
|
||||
clusters[ci].advance += curradv;
|
||||
else
|
||||
clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv;
|
||||
|
@ -397,7 +402,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
|
|||
unsigned int currclus = UINT_MAX;
|
||||
const hb_glyph_info_t *info = buffer->info;
|
||||
hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr);
|
||||
if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
|
||||
if (!HB_DIRECTION_IS_BACKWARD (direction))
|
||||
{
|
||||
curradvx = 0;
|
||||
for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
|
||||
|
|
|
@ -413,7 +413,7 @@ hb_ot_get_glyph_extents (hb_font_t *font,
|
|||
if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
|
||||
if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
|
||||
#endif
|
||||
#if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT)
|
||||
#if !defined(HB_NO_COLOR)
|
||||
if (ot_face->COLR->get_extents (font, glyph, extents)) return true;
|
||||
#endif
|
||||
if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
|
||||
|
@ -633,4 +633,20 @@ hb_ot_font_set_funcs (hb_font_t *font)
|
|||
_hb_ot_font_destroy);
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
bool
|
||||
_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
|
||||
int *lsb)
|
||||
{
|
||||
return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
|
||||
}
|
||||
|
||||
unsigned
|
||||
_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
|
||||
{
|
||||
return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -76,7 +76,7 @@ struct DeviceRecord
|
|||
HBUINT8 maxWidth; /* Maximum width. */
|
||||
UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */
|
||||
public:
|
||||
DEFINE_SIZE_UNBOUNDED (2);
|
||||
DEFINE_SIZE_ARRAY (2, widthsZ);
|
||||
};
|
||||
|
||||
|
||||
|
@ -87,6 +87,14 @@ struct hdmx
|
|||
unsigned int get_size () const
|
||||
{ return min_size + numRecords * sizeDeviceRecord; }
|
||||
|
||||
const DeviceRecord& operator [] (unsigned int i) const
|
||||
{
|
||||
/* XXX Null(DeviceRecord) is NOT safe as it's num-glyphs lengthed.
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/1300 */
|
||||
if (unlikely (i >= numRecords)) return Null (DeviceRecord);
|
||||
return StructAtOffset<DeviceRecord> (&this->firstDeviceRecord, i * sizeDeviceRecord);
|
||||
}
|
||||
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)
|
||||
|
|
|
@ -63,25 +63,7 @@ struct head
|
|||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
head *out = c->serializer->embed (this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
if (c->plan->normalized_coords)
|
||||
{
|
||||
if (unlikely (!c->serializer->check_assign (out->xMin, c->plan->head_maxp_info.xMin,
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
|
||||
return_trace (false);
|
||||
if (unlikely (!c->serializer->check_assign (out->xMax, c->plan->head_maxp_info.xMax,
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
|
||||
return_trace (false);
|
||||
if (unlikely (!c->serializer->check_assign (out->yMin, c->plan->head_maxp_info.yMin,
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
|
||||
return_trace (false);
|
||||
if (unlikely (!c->serializer->check_assign (out->yMax, c->plan->head_maxp_info.yMax,
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
return_trace (serialize (c->serializer));
|
||||
}
|
||||
|
||||
enum mac_style_flag_t {
|
||||
|
|
|
@ -50,9 +50,6 @@ _glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gly
|
|||
HB_INTERNAL unsigned
|
||||
_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
|
||||
|
||||
HB_INTERNAL bool
|
||||
_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb);
|
||||
|
||||
|
||||
namespace OT {
|
||||
|
||||
|
@ -95,7 +92,7 @@ struct hmtxvmtx
|
|||
|
||||
unsigned int length;
|
||||
H *table = (H *) hb_blob_get_data (dest_blob, &length);
|
||||
c->serializer->check_assign (table->numberOfLongMetrics, num_hmetrics, HB_SERIALIZE_ERROR_INT_OVERFLOW);
|
||||
table->numberOfLongMetrics = num_hmetrics;
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
if (c->plan->normalized_coords)
|
||||
|
@ -168,19 +165,12 @@ struct hmtxvmtx
|
|||
lm.sb = _.second;
|
||||
if (unlikely (!c->embed<LongMetric> (&lm))) return;
|
||||
}
|
||||
else if (idx < 0x10000u)
|
||||
else
|
||||
{
|
||||
FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
|
||||
if (unlikely (!sb)) return;
|
||||
*sb = _.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: This does not do tail optimization.
|
||||
UFWORD *adv = c->allocate_size<UFWORD> (UFWORD::static_size);
|
||||
if (unlikely (!adv)) return;
|
||||
*adv = _.first;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +189,7 @@ struct hmtxvmtx
|
|||
/* Determine num_long_metrics to encode. */
|
||||
auto& plan = c->plan;
|
||||
|
||||
num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu);
|
||||
num_long_metrics = plan->num_output_glyphs ();
|
||||
unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx);
|
||||
while (num_long_metrics > 1 &&
|
||||
last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx))
|
||||
|
@ -218,8 +208,7 @@ struct hmtxvmtx
|
|||
if (!c->plan->old_gid_for_new_gid (_, &old_gid))
|
||||
return hb_pair (0u, 0);
|
||||
int lsb = 0;
|
||||
if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
|
||||
(void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb);
|
||||
(void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
|
||||
return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
|
||||
}
|
||||
return mtx_map->get (_);
|
||||
|
|
|
@ -64,8 +64,6 @@ using OT::Layout::GPOS;
|
|||
* @include: hb-ot.h
|
||||
*
|
||||
* Functions for querying OpenType Layout features in the font face.
|
||||
* See the <ulink url="http://www.microsoft.com/typography/otspec/">OpenType
|
||||
* specification</ulink> for details.
|
||||
**/
|
||||
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ struct maxp
|
|||
maxp *maxp_prime = c->serializer->embed (this);
|
||||
if (unlikely (!maxp_prime)) return_trace (false);
|
||||
|
||||
maxp_prime->numGlyphs = hb_min (c->plan->num_output_glyphs (), 0xFFFFu);
|
||||
maxp_prime->numGlyphs = c->plan->num_output_glyphs ();
|
||||
if (maxp_prime->version.major == 1)
|
||||
{
|
||||
const maxpV1Tail *src_v1 = &StructAfter<maxpV1Tail> (*this);
|
||||
|
|
|
@ -181,4 +181,6 @@ hb_ot_name_get_utf32 (hb_face_t *face,
|
|||
return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
|
||||
}
|
||||
|
||||
#include "hb-ot-name-language-static.hh"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -265,9 +265,6 @@ struct HVARVVAR
|
|||
rsbMap.sanitize (c, this));
|
||||
}
|
||||
|
||||
const VariationStore& get_var_store () const
|
||||
{ return this+varStore; }
|
||||
|
||||
void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
|
||||
{
|
||||
index_maps.push (&(this+advMap));
|
||||
|
|
|
@ -29,16 +29,7 @@
|
|||
|
||||
#include "hb.hh"
|
||||
|
||||
/* Memory pool for persistent allocation of small objects.
|
||||
*
|
||||
* Some AI musings on this, not necessarily true:
|
||||
*
|
||||
* This is a very simple implementation, but it's good enough for our
|
||||
* purposes. It's not thread-safe. It's not very fast. It's not
|
||||
* very memory efficient. It's not very cache efficient. It's not
|
||||
* very anything efficient. But it's simple and it works. And it's
|
||||
* good enough for our purposes. If you need something more
|
||||
* sophisticated, use a real allocator. Or use a real language. */
|
||||
/* Memory pool for persistent allocation of small objects. */
|
||||
|
||||
template <typename T, unsigned ChunkLen = 32>
|
||||
struct hb_pool_t
|
||||
|
|
|
@ -35,12 +35,6 @@
|
|||
*
|
||||
* Priority queue implemented as a binary heap. Supports extract minimum
|
||||
* and insert operations.
|
||||
*
|
||||
* The priority queue is implemented as a binary heap, which is a complete
|
||||
* binary tree. The root of the tree is the minimum element. The heap
|
||||
* property is that the priority of a node is less than or equal to the
|
||||
* priority of its children. The heap is stored in an array, with the
|
||||
* children of node i stored at indices 2i + 1 and 2i + 2.
|
||||
*/
|
||||
struct hb_priority_queue_t
|
||||
{
|
||||
|
|
|
@ -33,6 +33,11 @@
|
|||
|
||||
/* v--- Add new shapers in the right place here. */
|
||||
|
||||
#ifdef HAVE_WASM
|
||||
/* Only picks up fonts that have a "Wasm" table. */
|
||||
HB_SHAPER_IMPLEMENT (wasm)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GRAPHITE2
|
||||
/* Only picks up fonts that have a "Silf" table. */
|
||||
HB_SHAPER_IMPLEMENT (graphite2)
|
||||
|
|
|
@ -36,11 +36,9 @@
|
|||
#include "OT/Color/COLR/COLR.hh"
|
||||
#include "hb-ot-glyf-table.hh"
|
||||
#include "hb-ot-head-table.hh"
|
||||
#include "hb-ot-hmtx-table.hh"
|
||||
#include "hb-ot-maxp-table.hh"
|
||||
|
||||
#ifndef HB_NO_VISIBILITY
|
||||
#include "hb-ot-name-language-static.hh"
|
||||
|
||||
uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
|
||||
/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
|
||||
|
@ -110,26 +108,4 @@ hb_face_t::load_upem () const
|
|||
}
|
||||
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
bool
|
||||
_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
|
||||
int *lsb)
|
||||
{
|
||||
return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
|
||||
}
|
||||
|
||||
unsigned
|
||||
_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
|
||||
{
|
||||
return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb)
|
||||
{
|
||||
return face->table.glyf->get_leading_bearing_without_var_unscaled (gid, is_vertical, lsb);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -125,7 +125,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
|
|||
return result_t{}; // No overlap
|
||||
|
||||
/* case 2: Only the peak and outermost bound fall outside the new limit;
|
||||
* we keep the deltaset, update peak and outermost bound and scale deltas
|
||||
* we keep the deltaset, update peak and outermost bound and and scale deltas
|
||||
* by the scalar value for the restricted axis at the new limit, and solve
|
||||
* recursively.
|
||||
*
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include "hb-ot-layout-gpos-table.hh"
|
||||
#include "hb-ot-layout-gsub-table.hh"
|
||||
#include "hb-ot-cff1-table.hh"
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
#include "OT/Color/COLR/COLR.hh"
|
||||
#include "OT/Color/COLR/colrv1-closure.hh"
|
||||
#include "OT/Color/CPAL/CPAL.hh"
|
||||
|
@ -295,7 +294,7 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
|
|||
feature_record_cond_idx_map,
|
||||
feature_substitutes_map);
|
||||
|
||||
if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE))
|
||||
if (table_tag == HB_OT_TAG_GSUB)
|
||||
hb_ot_layout_lookups_substitute_closure (plan->source,
|
||||
&lookup_indices,
|
||||
gids_to_retain);
|
||||
|
@ -623,7 +622,7 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
|
|||
|
||||
gids_to_retain->add (gid);
|
||||
|
||||
for (auto &item : glyf.glyph_for_gid (gid).get_composite_iterator ())
|
||||
for (auto item : glyf.glyph_for_gid (gid).get_composite_iterator ())
|
||||
operation_count =
|
||||
_glyf_add_gid_and_children (glyf,
|
||||
item.get_gid (),
|
||||
|
@ -631,18 +630,6 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
|
|||
operation_count,
|
||||
depth);
|
||||
|
||||
#ifndef HB_NO_VAR_COMPOSITES
|
||||
for (auto &item : glyf.glyph_for_gid (gid).get_var_composite_iterator ())
|
||||
{
|
||||
operation_count =
|
||||
_glyf_add_gid_and_children (glyf,
|
||||
item.get_gid (),
|
||||
gids_to_retain,
|
||||
operation_count,
|
||||
depth);
|
||||
}
|
||||
#endif
|
||||
|
||||
return operation_count;
|
||||
}
|
||||
|
||||
|
@ -657,10 +644,9 @@ _nameid_closure (hb_subset_plan_t* plan,
|
|||
if (!plan->all_axes_pinned)
|
||||
plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->name_ids);
|
||||
#endif
|
||||
#ifndef HB_NO_COLOR
|
||||
|
||||
if (!drop_tables->has (HB_OT_TAG_CPAL))
|
||||
plan->source->table.CPAL->collect_name_ids (&plan->colr_palettes, &plan->name_ids);
|
||||
#endif
|
||||
|
||||
#ifndef HB_NO_SUBSET_LAYOUT
|
||||
if (!drop_tables->has (HB_OT_TAG_GPOS))
|
||||
|
@ -868,89 +854,6 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
|
|||
}
|
||||
plan->all_axes_pinned = !axis_not_pinned;
|
||||
}
|
||||
|
||||
static void
|
||||
_update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
|
||||
{
|
||||
if (!plan->normalized_coords) return;
|
||||
OT::cff2::accelerator_t cff2 (plan->source);
|
||||
if (!cff2.is_valid ()) return;
|
||||
|
||||
hb_font_t *font = nullptr;
|
||||
if (unlikely (!plan->check_success (font = _get_hb_font_with_variations (plan))))
|
||||
{
|
||||
hb_font_destroy (font);
|
||||
return;
|
||||
}
|
||||
|
||||
hb_glyph_extents_t extents = {0x7FFF, -0x7FFF};
|
||||
OT::hmtx_accelerator_t _hmtx (plan->source);
|
||||
float *hvar_store_cache = nullptr;
|
||||
if (_hmtx.has_data () && _hmtx.var_table.get_length ())
|
||||
hvar_store_cache = _hmtx.var_table->get_var_store ().create_cache ();
|
||||
|
||||
OT::vmtx_accelerator_t _vmtx (plan->source);
|
||||
float *vvar_store_cache = nullptr;
|
||||
if (_vmtx.has_data () && _vmtx.var_table.get_length ())
|
||||
vvar_store_cache = _vmtx.var_table->get_var_store ().create_cache ();
|
||||
|
||||
for (auto p : *plan->glyph_map)
|
||||
{
|
||||
hb_codepoint_t old_gid = p.first;
|
||||
hb_codepoint_t new_gid = p.second;
|
||||
if (!cff2.get_extents (font, old_gid, &extents)) continue;
|
||||
bool has_bounds_info = true;
|
||||
if (extents.x_bearing == 0 && extents.width == 0 &&
|
||||
extents.height == 0 && extents.y_bearing == 0)
|
||||
has_bounds_info = false;
|
||||
|
||||
if (has_bounds_info)
|
||||
{
|
||||
plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, extents.x_bearing);
|
||||
plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, extents.x_bearing + extents.width);
|
||||
plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, extents.y_bearing);
|
||||
plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, extents.y_bearing + extents.height);
|
||||
}
|
||||
|
||||
if (_hmtx.has_data ())
|
||||
{
|
||||
int hori_aw = _hmtx.get_advance_without_var_unscaled (old_gid);
|
||||
if (_hmtx.var_table.get_length ())
|
||||
hori_aw += (int) roundf (_hmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords,
|
||||
hvar_store_cache));
|
||||
int lsb = extents.x_bearing;
|
||||
if (!has_bounds_info)
|
||||
{
|
||||
if (!_hmtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
|
||||
continue;
|
||||
}
|
||||
plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
|
||||
plan->bounds_width_map.set (new_gid, extents.width);
|
||||
}
|
||||
|
||||
if (_vmtx.has_data ())
|
||||
{
|
||||
int vert_aw = _vmtx.get_advance_without_var_unscaled (old_gid);
|
||||
if (_vmtx.var_table.get_length ())
|
||||
vert_aw += (int) roundf (_vmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords,
|
||||
vvar_store_cache));
|
||||
|
||||
int tsb = extents.y_bearing;
|
||||
if (!has_bounds_info)
|
||||
{
|
||||
if (!_vmtx.get_leading_bearing_without_var_unscaled (old_gid, &tsb))
|
||||
continue;
|
||||
}
|
||||
plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
|
||||
plan->bounds_height_map.set (new_gid, extents.height);
|
||||
}
|
||||
}
|
||||
hb_font_destroy (font);
|
||||
if (hvar_store_cache)
|
||||
_hmtx.var_table->get_var_store ().destroy_cache (hvar_store_cache);
|
||||
if (vvar_store_cache)
|
||||
_vmtx.var_table->get_var_store ().destroy_cache (vvar_store_cache);
|
||||
}
|
||||
#endif
|
||||
|
||||
hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
|
||||
|
@ -1039,10 +942,6 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
|
|||
if (unlikely (in_error ()))
|
||||
return;
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
_update_instance_metrics_map_from_cff2 (this);
|
||||
#endif
|
||||
|
||||
if (attach_accelerator_data)
|
||||
{
|
||||
hb_multimap_t gid_to_unicodes;
|
||||
|
|
|
@ -637,3 +637,8 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
|
|||
end:
|
||||
return success ? hb_face_reference (plan->dest) : nullptr;
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VISIBILITY
|
||||
/* If NO_VISIBILITY, libharfbuzz has this. */
|
||||
#include "hb-ot-name-language-static.hh"
|
||||
#endif
|
||||
|
|
|
@ -71,8 +71,6 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
|
|||
* in the final subset.
|
||||
* @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
|
||||
* OS/2 will not be recalculated.
|
||||
* @HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE: If set don't perform glyph closure on layout
|
||||
* substitution rules (GSUB).
|
||||
*
|
||||
* List of boolean properties that can be configured on the subset input.
|
||||
*
|
||||
|
@ -89,7 +87,6 @@ typedef enum { /*< flags >*/
|
|||
HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u,
|
||||
HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
|
||||
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
|
||||
HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE = 0x00000200u,
|
||||
} hb_subset_flags_t;
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright © 2023 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_WASM_API_BLOB_HH
|
||||
#define HB_WASM_API_BLOB_HH
|
||||
|
||||
#include "hb-wasm-api.hh"
|
||||
|
||||
namespace hb {
|
||||
namespace wasm {
|
||||
|
||||
|
||||
HB_WASM_API (void, blob_free) (HB_WASM_EXEC_ENV
|
||||
ptr_d(blob_t, blob))
|
||||
{
|
||||
HB_PTR_PARAM (blob_t, blob);
|
||||
if (unlikely (!blob))
|
||||
return;
|
||||
|
||||
module_free (blob->data);
|
||||
|
||||
blob->data = nullref;
|
||||
blob->length = 0;
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* HB_WASM_API_BLOB_HH */
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* Copyright © 2023 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_WASM_API_BUFFER_HH
|
||||
#define HB_WASM_API_BUFFER_HH
|
||||
|
||||
#include "hb-wasm-api.hh"
|
||||
|
||||
#include "hb-buffer.hh"
|
||||
|
||||
namespace hb {
|
||||
namespace wasm {
|
||||
|
||||
static_assert (sizeof (glyph_info_t) == sizeof (hb_glyph_info_t), "");
|
||||
static_assert (sizeof (glyph_position_t) == sizeof (hb_glyph_position_t), "");
|
||||
|
||||
HB_WASM_API (bool_t, buffer_contents_realloc) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_contents_t, contents),
|
||||
uint32_t size)
|
||||
{
|
||||
HB_PTR_PARAM (buffer_contents_t, contents);
|
||||
if (unlikely (!contents))
|
||||
return false;
|
||||
|
||||
if (size <= contents->length)
|
||||
return true;
|
||||
|
||||
unsigned bytes;
|
||||
if (hb_unsigned_mul_overflows (size, sizeof (glyph_info_t), &bytes))
|
||||
return false;
|
||||
|
||||
glyph_info_t *info = HB_ARRAY_APP2NATIVE (glyph_info_t, contents->info, contents->length);
|
||||
glyph_position_t *pos = HB_ARRAY_APP2NATIVE (glyph_position_t, contents->pos, contents->length);
|
||||
|
||||
if (unlikely (!info || !pos))
|
||||
return false;
|
||||
|
||||
glyph_info_t *new_info = nullptr;
|
||||
uint32_t new_inforef = module_malloc (bytes, (void **) &new_info);
|
||||
glyph_position_t *new_pos = nullptr;
|
||||
uint32_t new_posref = module_malloc (bytes, (void **) &new_pos);
|
||||
|
||||
unsigned old_bytes = contents->length * sizeof (glyph_info_t);
|
||||
if (likely (new_inforef))
|
||||
{
|
||||
memcpy (new_info, info, old_bytes);
|
||||
module_free (contents->info);
|
||||
contents->info = new_inforef;
|
||||
}
|
||||
if (likely (new_posref))
|
||||
{
|
||||
memcpy (new_pos, pos, old_bytes);
|
||||
module_free (contents->pos);
|
||||
contents->pos = new_posref;
|
||||
}
|
||||
|
||||
if (likely (new_info && new_pos))
|
||||
{
|
||||
contents->length = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
HB_WASM_API (void, buffer_contents_free) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_contents_t, contents))
|
||||
{
|
||||
HB_PTR_PARAM (buffer_contents_t, contents);
|
||||
if (unlikely (!contents))
|
||||
return;
|
||||
|
||||
module_free (contents->info);
|
||||
module_free (contents->pos);
|
||||
|
||||
contents->info = nullref;
|
||||
contents->pos = nullref;
|
||||
contents->length = 0;
|
||||
}
|
||||
|
||||
HB_WASM_API (bool_t, buffer_copy_contents) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_t, buffer),
|
||||
ptr_d(buffer_contents_t, contents))
|
||||
{
|
||||
HB_REF2OBJ (buffer);
|
||||
HB_PTR_PARAM (buffer_contents_t, contents);
|
||||
if (unlikely (!contents))
|
||||
return false;
|
||||
|
||||
if (buffer->have_output)
|
||||
buffer->sync ();
|
||||
if (!buffer->have_positions)
|
||||
buffer->clear_positions ();
|
||||
|
||||
unsigned length = buffer->len;
|
||||
|
||||
if (length <= contents->length)
|
||||
{
|
||||
glyph_info_t *info = HB_ARRAY_APP2NATIVE (glyph_info_t, contents->info, length);
|
||||
glyph_position_t *pos = HB_ARRAY_APP2NATIVE (glyph_position_t, contents->pos, length);
|
||||
|
||||
if (unlikely (!info || !pos))
|
||||
{
|
||||
contents->length = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned bytes = length * sizeof (hb_glyph_info_t);
|
||||
memcpy (info, buffer->info, bytes);
|
||||
memcpy (pos, buffer->pos, bytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
module_free (contents->info);
|
||||
module_free (contents->pos);
|
||||
|
||||
contents->length = length;
|
||||
unsigned bytes = length * sizeof (hb_glyph_info_t);
|
||||
contents->info = wasm_runtime_module_dup_data (module_inst, (const char *) buffer->info, bytes);
|
||||
contents->pos = wasm_runtime_module_dup_data (module_inst, (const char *) buffer->pos, bytes);
|
||||
|
||||
if (length && (!contents->info || !contents->pos))
|
||||
{
|
||||
contents->length = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HB_WASM_API (bool_t, buffer_set_contents) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_t, buffer),
|
||||
ptr_d(const buffer_contents_t, contents))
|
||||
{
|
||||
HB_REF2OBJ (buffer);
|
||||
HB_PTR_PARAM (buffer_contents_t, contents);
|
||||
if (unlikely (!contents))
|
||||
return false;
|
||||
|
||||
unsigned length = contents->length;
|
||||
unsigned bytes;
|
||||
if (unlikely (hb_unsigned_mul_overflows (length, sizeof (buffer->info[0]), &bytes)))
|
||||
return false;
|
||||
|
||||
if (unlikely (!buffer->resize (length)))
|
||||
return false;
|
||||
|
||||
glyph_info_t *info = (glyph_info_t *) (validate_app_addr (contents->info, bytes) ? addr_app_to_native (contents->info) : nullptr);
|
||||
glyph_position_t *pos = (glyph_position_t *) (validate_app_addr (contents->pos, bytes) ? addr_app_to_native (contents->pos) : nullptr);
|
||||
|
||||
if (!buffer->have_positions)
|
||||
buffer->clear_positions (); /* This is wasteful. */
|
||||
|
||||
memcpy (buffer->info, info, bytes);
|
||||
memcpy (buffer->pos, pos, bytes);
|
||||
buffer->len = length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HB_WASM_API (direction_t, buffer_get_direction) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_t, buffer))
|
||||
{
|
||||
HB_REF2OBJ (buffer);
|
||||
|
||||
return (direction_t) hb_buffer_get_direction (buffer);
|
||||
}
|
||||
|
||||
HB_WASM_API (script_t, buffer_get_script) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_t, buffer))
|
||||
{
|
||||
HB_REF2OBJ (buffer);
|
||||
|
||||
return hb_script_to_iso15924_tag (hb_buffer_get_script (buffer));
|
||||
}
|
||||
|
||||
HB_WASM_API (void, buffer_reverse) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_t, buffer))
|
||||
{
|
||||
HB_REF2OBJ (buffer);
|
||||
|
||||
hb_buffer_reverse (buffer);
|
||||
}
|
||||
|
||||
HB_WASM_API (void, buffer_reverse_clusters) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_t, buffer))
|
||||
{
|
||||
HB_REF2OBJ (buffer);
|
||||
|
||||
hb_buffer_reverse_clusters (buffer);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif /* HB_WASM_API_BUFFER_HH */
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright © 2023 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_WASM_API_COMMON_HH
|
||||
#define HB_WASM_API_COMMON_HH
|
||||
|
||||
#include "hb-wasm-api.hh"
|
||||
|
||||
namespace hb {
|
||||
namespace wasm {
|
||||
|
||||
|
||||
HB_WASM_API (direction_t, script_get_horizontal_direction) (HB_WASM_EXEC_ENV
|
||||
script_t script)
|
||||
{
|
||||
return (direction_t)
|
||||
hb_script_get_horizontal_direction (hb_script_from_iso15924_tag (script));
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* HB_WASM_API_COMMON_HH */
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright © 2023 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_WASM_API_FACE_HH
|
||||
#define HB_WASM_API_FACE_HH
|
||||
|
||||
#include "hb-wasm-api.hh"
|
||||
|
||||
namespace hb {
|
||||
namespace wasm {
|
||||
|
||||
|
||||
HB_WASM_API (ptr_t(face_t), face_create) (HB_WASM_EXEC_ENV
|
||||
ptr_d(blob_t, blob),
|
||||
unsigned int index)
|
||||
{
|
||||
HB_PTR_PARAM (blob_t, blob);
|
||||
hb_blob_t *hb_blob = hb_blob_create(
|
||||
HB_ARRAY_APP2NATIVE (char, blob->data, blob->length),
|
||||
blob->length,
|
||||
HB_MEMORY_MODE_DUPLICATE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
hb_face_t *face = hb_face_create(hb_blob, index);
|
||||
|
||||
HB_OBJ2REF (face);
|
||||
return faceref;
|
||||
}
|
||||
|
||||
HB_WASM_API (bool_t, face_copy_table) (HB_WASM_EXEC_ENV
|
||||
ptr_d(face_t, face),
|
||||
tag_t table_tag,
|
||||
ptr_d(blob_t, blob))
|
||||
{
|
||||
HB_REF2OBJ (face);
|
||||
HB_PTR_PARAM (blob_t, blob);
|
||||
if (unlikely (!blob))
|
||||
return false;
|
||||
|
||||
hb_blob_t *hb_blob = hb_face_reference_table (face, table_tag);
|
||||
|
||||
unsigned length;
|
||||
const char *hb_data = hb_blob_get_data (hb_blob, &length);
|
||||
|
||||
if (length <= blob->length)
|
||||
{
|
||||
char *data = HB_ARRAY_APP2NATIVE (char, blob->data, length);
|
||||
|
||||
if (unlikely (!data))
|
||||
{
|
||||
blob->length = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy (data, hb_data, length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
module_free (blob->data);
|
||||
|
||||
blob->length = length;
|
||||
blob->data = wasm_runtime_module_dup_data (module_inst, hb_data, length);
|
||||
|
||||
hb_blob_destroy (hb_blob);
|
||||
|
||||
if (blob->length && !blob->data)
|
||||
{
|
||||
blob->length = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HB_WASM_API (unsigned, face_get_upem) (HB_WASM_EXEC_ENV
|
||||
ptr_d(face_t, face))
|
||||
{
|
||||
HB_REF2OBJ (face);
|
||||
|
||||
return hb_face_get_upem (face);
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* HB_WASM_API_FACE_HH */
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* Copyright © 2023 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_WASM_API_FONT_HH
|
||||
#define HB_WASM_API_FONT_HH
|
||||
|
||||
#include "hb-wasm-api.hh"
|
||||
|
||||
#include "hb-outline.hh"
|
||||
|
||||
namespace hb {
|
||||
namespace wasm {
|
||||
|
||||
|
||||
HB_WASM_API (ptr_t(font_t), font_create) (HB_WASM_EXEC_ENV
|
||||
ptr_d(face_t, face))
|
||||
{
|
||||
HB_REF2OBJ (face);
|
||||
|
||||
hb_font_t *font = hb_font_create (face);
|
||||
|
||||
HB_OBJ2REF (font);
|
||||
return fontref;
|
||||
}
|
||||
|
||||
HB_WASM_API (ptr_t(face_t), font_get_face) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font))
|
||||
{
|
||||
HB_REF2OBJ (font);
|
||||
|
||||
hb_face_t *face = hb_font_get_face (font);
|
||||
|
||||
HB_OBJ2REF (face);
|
||||
return faceref;
|
||||
}
|
||||
|
||||
HB_WASM_API (void, font_get_scale) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
ptr_d(int32_t, x_scale),
|
||||
ptr_d(int32_t, y_scale))
|
||||
{
|
||||
HB_REF2OBJ (font);
|
||||
|
||||
HB_PTR_PARAM(int32_t, x_scale);
|
||||
HB_PTR_PARAM(int32_t, y_scale);
|
||||
|
||||
hb_font_get_scale (font, x_scale, y_scale);
|
||||
}
|
||||
|
||||
HB_WASM_API (codepoint_t, font_get_glyph) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
codepoint_t unicode,
|
||||
codepoint_t variation_selector)
|
||||
{
|
||||
HB_REF2OBJ (font);
|
||||
codepoint_t glyph;
|
||||
|
||||
hb_font_get_glyph (font, unicode, variation_selector, &glyph);
|
||||
return glyph;
|
||||
}
|
||||
|
||||
HB_WASM_API (position_t, font_get_glyph_h_advance) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
codepoint_t glyph)
|
||||
{
|
||||
HB_REF2OBJ (font);
|
||||
return hb_font_get_glyph_h_advance (font, glyph);
|
||||
}
|
||||
|
||||
HB_WASM_API (position_t, font_get_glyph_v_advance) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
codepoint_t glyph)
|
||||
{
|
||||
HB_REF2OBJ (font);
|
||||
return hb_font_get_glyph_v_advance (font, glyph);
|
||||
}
|
||||
|
||||
static_assert (sizeof (glyph_extents_t) == sizeof (hb_glyph_extents_t), "");
|
||||
|
||||
HB_WASM_API (bool_t, font_get_glyph_extents) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
codepoint_t glyph,
|
||||
ptr_d(glyph_extents_t, extents))
|
||||
{
|
||||
HB_REF2OBJ (font);
|
||||
HB_PTR_PARAM (glyph_extents_t, extents);
|
||||
if (unlikely (!extents))
|
||||
return false;
|
||||
|
||||
return hb_font_get_glyph_extents (font, glyph,
|
||||
(hb_glyph_extents_t *) extents);
|
||||
}
|
||||
|
||||
HB_WASM_API (void, font_glyph_to_string) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
codepoint_t glyph,
|
||||
char *s, uint32_t size)
|
||||
{
|
||||
HB_REF2OBJ (font);
|
||||
|
||||
hb_font_glyph_to_string (font, glyph, s, size);
|
||||
}
|
||||
|
||||
static_assert (sizeof (glyph_outline_point_t) == sizeof (hb_outline_point_t), "");
|
||||
static_assert (sizeof (uint32_t) == sizeof (hb_outline_t::contours[0]), "");
|
||||
|
||||
HB_WASM_API (bool_t, font_copy_glyph_outline) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
codepoint_t glyph,
|
||||
ptr_d(glyph_outline_t, outline))
|
||||
{
|
||||
HB_REF2OBJ (font);
|
||||
HB_PTR_PARAM (glyph_outline_t, outline);
|
||||
if (unlikely (!outline))
|
||||
return false;
|
||||
|
||||
hb_outline_t hb_outline;
|
||||
auto *funcs = hb_outline_recording_pen_get_funcs ();
|
||||
|
||||
hb_font_draw_glyph (font, glyph, funcs, &hb_outline);
|
||||
|
||||
if (unlikely (hb_outline.points.in_error () ||
|
||||
hb_outline.contours.in_error ()))
|
||||
{
|
||||
outline->n_points = outline->n_contours = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO Check two buffers separately
|
||||
if (hb_outline.points.length <= outline->n_points &&
|
||||
hb_outline.contours.length <= outline->n_contours)
|
||||
{
|
||||
glyph_outline_point_t *points = HB_ARRAY_APP2NATIVE (glyph_outline_point_t, outline->points, hb_outline.points.length);
|
||||
uint32_t *contours = HB_ARRAY_APP2NATIVE (uint32_t, outline->contours, hb_outline.contours.length);
|
||||
|
||||
if (unlikely (!points || !contours))
|
||||
{
|
||||
outline->n_points = outline->n_contours = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy (points, hb_outline.points.arrayZ, hb_outline.points.get_size ());
|
||||
memcpy (contours, hb_outline.contours.arrayZ, hb_outline.contours.get_size ());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
outline->n_points = hb_outline.points.length;
|
||||
outline->points = wasm_runtime_module_dup_data (module_inst,
|
||||
(const char *) hb_outline.points.arrayZ,
|
||||
hb_outline.points.get_size ());
|
||||
outline->n_contours = hb_outline.contours.length;
|
||||
outline->contours = wasm_runtime_module_dup_data (module_inst,
|
||||
(const char *) hb_outline.contours.arrayZ,
|
||||
hb_outline.contours.get_size ());
|
||||
|
||||
if ((outline->n_points && !outline->points) ||
|
||||
(!outline->n_contours && !outline->contours))
|
||||
{
|
||||
outline->n_points = outline->n_contours = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HB_WASM_API (void, glyph_outline_free) (HB_WASM_EXEC_ENV
|
||||
ptr_d(glyph_outline_t, outline))
|
||||
{
|
||||
HB_PTR_PARAM (glyph_outline_t, outline);
|
||||
if (unlikely (!outline))
|
||||
return;
|
||||
|
||||
module_free (outline->points);
|
||||
module_free (outline->contours);
|
||||
|
||||
outline->n_points = 0;
|
||||
outline->points = nullref;
|
||||
outline->n_contours = 0;
|
||||
outline->contours = nullref;
|
||||
}
|
||||
|
||||
HB_WASM_API (bool_t, font_copy_coords) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
ptr_d(coords_t, coords))
|
||||
{
|
||||
HB_REF2OBJ (font);
|
||||
HB_PTR_PARAM (coords_t, coords);
|
||||
if (unlikely (!coords))
|
||||
return false;
|
||||
|
||||
unsigned our_length;
|
||||
const int* our_coords = hb_font_get_var_coords_normalized(font, &our_length);
|
||||
|
||||
if (our_length <= coords->length) {
|
||||
int *their_coords = HB_ARRAY_APP2NATIVE (int, coords->coords, our_length);
|
||||
if (unlikely(!their_coords)) {
|
||||
coords->length = 0;
|
||||
return false;
|
||||
}
|
||||
unsigned bytes = our_length * sizeof (int);
|
||||
memcpy (their_coords, our_coords, bytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
module_free (coords->coords);
|
||||
coords->length = our_length;
|
||||
unsigned bytes = our_length * sizeof (int);
|
||||
coords->coords = wasm_runtime_module_dup_data (module_inst, (const char *) our_coords, bytes);
|
||||
if (our_length && !coords->coords)
|
||||
{
|
||||
coords->length = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HB_WASM_API (bool_t, font_set_coords) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
ptr_d(coords_t, coords))
|
||||
{
|
||||
HB_REF2OBJ (font);
|
||||
HB_PTR_PARAM (coords_t, coords);
|
||||
if (unlikely (!coords))
|
||||
return false;
|
||||
|
||||
unsigned length = coords->length;
|
||||
unsigned bytes;
|
||||
if (unlikely (hb_unsigned_mul_overflows (length, sizeof (int), &bytes)))
|
||||
return false;
|
||||
|
||||
const int *our_coords = (const int *) (validate_app_addr (coords->coords, bytes) ? addr_app_to_native (coords->coords) : nullptr);
|
||||
hb_font_set_var_coords_normalized(font, our_coords, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* HB_WASM_API_FONT_HH */
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright © 2023 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_WASM_API_LIST_HH
|
||||
#define HB_WASM_API_LIST_HH
|
||||
|
||||
#include "hb-wasm-api.hh"
|
||||
|
||||
|
||||
#ifdef HB_DEBUG_WASM
|
||||
namespace hb { namespace wasm {
|
||||
|
||||
static void debugprint (HB_WASM_EXEC_ENV char *str)
|
||||
{ DEBUG_MSG (WASM, exec_env, "%s", str); }
|
||||
static void debugprint1 (HB_WASM_EXEC_ENV char *str, int32_t i1)
|
||||
{ DEBUG_MSG (WASM, exec_env, "%s: %d", str, i1); }
|
||||
static void debugprint2 (HB_WASM_EXEC_ENV char *str, int32_t i1, int32_t i2)
|
||||
{ DEBUG_MSG (WASM, exec_env, "%s: %d, %d", str, i1, i2); }
|
||||
static void debugprint3 (HB_WASM_EXEC_ENV char *str, int32_t i1, int32_t i2, int32_t i3)
|
||||
{ DEBUG_MSG (WASM, exec_env, "%s: %d, %d, %d", str, i1, i2, i3); }
|
||||
static void debugprint4 (HB_WASM_EXEC_ENV char *str, int32_t i1, int32_t i2, int32_t i3, int32_t i4)
|
||||
{ DEBUG_MSG (WASM, exec_env, "%s: %d, %d, %d, %d", str, i1, i2, i3, i4); }
|
||||
|
||||
}}
|
||||
#endif
|
||||
|
||||
#define NATIVE_SYMBOL(signature, name) {#name, (void *) hb::wasm::name, signature, NULL}
|
||||
/* Note: the array must be static defined since runtime will keep it after registration.
|
||||
* Also not const, because it modifies it (sorts it).
|
||||
* https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/export_native_api.md
|
||||
*
|
||||
* TODO Allocate this lazily in _hb_wasm_init(). */
|
||||
static NativeSymbol _hb_wasm_native_symbols[] =
|
||||
{
|
||||
/* common */
|
||||
NATIVE_SYMBOL ("(i)i", script_get_horizontal_direction),
|
||||
|
||||
/* blob */
|
||||
NATIVE_SYMBOL ("(i)", blob_free),
|
||||
|
||||
/* buffer */
|
||||
NATIVE_SYMBOL ("(i)", buffer_contents_free),
|
||||
NATIVE_SYMBOL ("(ii)i", buffer_contents_realloc),
|
||||
NATIVE_SYMBOL ("(ii)i", buffer_copy_contents),
|
||||
NATIVE_SYMBOL ("(ii)i", buffer_set_contents),
|
||||
NATIVE_SYMBOL ("(i)i", buffer_get_direction),
|
||||
NATIVE_SYMBOL ("(i)i", buffer_get_script),
|
||||
NATIVE_SYMBOL ("(i)", buffer_reverse),
|
||||
NATIVE_SYMBOL ("(i)", buffer_reverse_clusters),
|
||||
|
||||
/* face */
|
||||
NATIVE_SYMBOL ("(ii)i", face_create),
|
||||
NATIVE_SYMBOL ("(iii)i", face_copy_table),
|
||||
NATIVE_SYMBOL ("(i)i", face_get_upem),
|
||||
|
||||
/* font */
|
||||
NATIVE_SYMBOL ("(i)i", font_create),
|
||||
NATIVE_SYMBOL ("(i)i", font_get_face),
|
||||
NATIVE_SYMBOL ("(iii)", font_get_scale),
|
||||
NATIVE_SYMBOL ("(iii)i", font_get_glyph),
|
||||
NATIVE_SYMBOL ("(ii)i", font_get_glyph_h_advance),
|
||||
NATIVE_SYMBOL ("(ii)i", font_get_glyph_v_advance),
|
||||
NATIVE_SYMBOL ("(iii)i", font_get_glyph_extents),
|
||||
NATIVE_SYMBOL ("(ii$*)", font_glyph_to_string),
|
||||
NATIVE_SYMBOL ("(iii)i", font_copy_glyph_outline),
|
||||
NATIVE_SYMBOL ("(ii)i", font_copy_coords),
|
||||
NATIVE_SYMBOL ("(ii)i", font_set_coords),
|
||||
|
||||
/* outline */
|
||||
NATIVE_SYMBOL ("(i)", glyph_outline_free),
|
||||
|
||||
/* shape */
|
||||
NATIVE_SYMBOL ("(iiii$)i", shape_with),
|
||||
|
||||
/* debug */
|
||||
#ifdef HB_DEBUG_WASM
|
||||
NATIVE_SYMBOL ("($)", debugprint),
|
||||
NATIVE_SYMBOL ("($i)", debugprint1),
|
||||
NATIVE_SYMBOL ("($ii)", debugprint2),
|
||||
NATIVE_SYMBOL ("($iii)", debugprint3),
|
||||
NATIVE_SYMBOL ("($iiii)", debugprint4),
|
||||
#endif
|
||||
|
||||
};
|
||||
#undef NATIVE_SYMBOL
|
||||
|
||||
|
||||
#endif /* HB_WASM_API_LIST_HH */
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright © 2023 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_WASM_API_SHAPE_HH
|
||||
#define HB_WASM_API_SHAPE_HH
|
||||
|
||||
#include "hb-wasm-api.hh"
|
||||
|
||||
namespace hb {
|
||||
namespace wasm {
|
||||
|
||||
|
||||
static_assert (sizeof (feature_t) == sizeof (hb_feature_t), "");
|
||||
|
||||
HB_WASM_INTERFACE (bool_t, shape_with) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
ptr_d(buffer_t, buffer),
|
||||
ptr_d(const feature_t, features),
|
||||
uint32_t num_features,
|
||||
const char *shaper)
|
||||
{
|
||||
if (unlikely (0 == strcmp (shaper, "wasm")))
|
||||
return false;
|
||||
|
||||
HB_REF2OBJ (font);
|
||||
HB_REF2OBJ (buffer);
|
||||
|
||||
/* Pre-conditions that make hb_shape_full() crash should be checked here. */
|
||||
|
||||
if (unlikely (!buffer->ensure_unicode ()))
|
||||
return false;
|
||||
|
||||
if (unlikely (!HB_DIRECTION_IS_VALID (buffer->props.direction)))
|
||||
return false;
|
||||
|
||||
HB_ARRAY_PARAM (const feature_t, features, num_features);
|
||||
if (unlikely (!features && num_features))
|
||||
return false;
|
||||
|
||||
const char * shaper_list[] = {shaper, nullptr};
|
||||
return hb_shape_full (font, buffer,
|
||||
(hb_feature_t *) features, num_features,
|
||||
shaper_list);
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* HB_WASM_API_SHAPE_HH */
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright © 2023 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_WASM
|
||||
|
||||
#include "hb-wasm-api.hh"
|
||||
|
||||
#define module_inst wasm_runtime_get_module_inst (exec_env)
|
||||
|
||||
|
||||
#include "hb-wasm-api-blob.hh"
|
||||
#include "hb-wasm-api-buffer.hh"
|
||||
#include "hb-wasm-api-common.hh"
|
||||
#include "hb-wasm-api-face.hh"
|
||||
#include "hb-wasm-api-font.hh"
|
||||
#include "hb-wasm-api-shape.hh"
|
||||
|
||||
|
||||
#undef module_inst
|
||||
|
||||
hb_user_data_key_t _hb_wasm_ref_type_key = {};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Copyright © 2023 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_WASM_API_H
|
||||
#define HB_WASM_API_H
|
||||
|
||||
/*
|
||||
#include "hb.h"
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#ifndef HB_WASM_BEGIN_DECLS
|
||||
# ifdef __cplusplus
|
||||
# define HB_WASM_BEGIN_DECLS extern "C" {
|
||||
# define HB_WASM_END_DECLS }
|
||||
# else /* !__cplusplus */
|
||||
# define HB_WASM_BEGIN_DECLS
|
||||
# define HB_WASM_END_DECLS
|
||||
# endif /* !__cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
HB_WASM_BEGIN_DECLS
|
||||
|
||||
#ifndef HB_WASM_API
|
||||
#define HB_WASM_API(ret_t, name) ret_t name
|
||||
#endif
|
||||
#ifndef HB_WASM_API_COMPOUND /* compound return type */
|
||||
#define HB_WASM_API_COMPOUND(ret_t, name) HB_WASM_API(ret_t, name)
|
||||
#endif
|
||||
#ifndef HB_WASM_INTERFACE
|
||||
#define HB_WASM_INTERFACE(ret_t, name) ret_t name
|
||||
#endif
|
||||
#ifndef HB_WASM_EXEC_ENV
|
||||
#define HB_WASM_EXEC_ENV
|
||||
#endif
|
||||
#ifndef HB_WASM_EXEC_ENV_COMPOUND
|
||||
#define HB_WASM_EXEC_ENV_COMPOUND HB_WASM_EXEC_ENV
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef bool_t
|
||||
#define bool_t uint32_t
|
||||
#endif
|
||||
#ifndef ptr_t
|
||||
#define ptr_t(type_t) type_t *
|
||||
#endif
|
||||
#ifndef ptr_d
|
||||
#define ptr_d(type_t, name) type_t *name
|
||||
#endif
|
||||
|
||||
typedef uint32_t codepoint_t;
|
||||
typedef int32_t position_t;
|
||||
typedef uint32_t mask_t;
|
||||
typedef uint32_t tag_t;
|
||||
#define TAG(c1,c2,c3,c4) ((tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
|
||||
|
||||
typedef enum {
|
||||
DIRECTION_INVALID = 0,
|
||||
DIRECTION_LTR = 4,
|
||||
DIRECTION_RTL,
|
||||
DIRECTION_TTB,
|
||||
DIRECTION_BTT
|
||||
} direction_t;
|
||||
#define DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4)
|
||||
#define DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) & ~1U) == 4)
|
||||
#define DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) & ~1U) == 6)
|
||||
#define DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) & ~2U) == 4)
|
||||
#define DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) & ~2U) == 5)
|
||||
#define DIRECTION_REVERSE(dir) ((direction_t) (((unsigned int) (dir)) ^ 1))
|
||||
|
||||
typedef tag_t script_t; /* ISO 15924 representation of Unicode scripts. */
|
||||
|
||||
|
||||
/* common */
|
||||
|
||||
HB_WASM_API (direction_t, script_get_horizontal_direction) (HB_WASM_EXEC_ENV
|
||||
script_t script);
|
||||
|
||||
|
||||
/* blob */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t length;
|
||||
ptr_t(char) data;
|
||||
} blob_t;
|
||||
#define BLOB_INIT {0, 0}
|
||||
|
||||
HB_WASM_API (void, blob_free) (HB_WASM_EXEC_ENV
|
||||
ptr_d(blob_t, blob));
|
||||
|
||||
/* buffer */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t codepoint;
|
||||
uint32_t mask;
|
||||
uint32_t cluster;
|
||||
uint32_t var1;
|
||||
uint32_t var2;
|
||||
} glyph_info_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
position_t x_advance;
|
||||
position_t y_advance;
|
||||
position_t x_offset;
|
||||
position_t y_offset;
|
||||
uint32_t var;
|
||||
} glyph_position_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t length;
|
||||
ptr_t(glyph_info_t) info;
|
||||
ptr_t(glyph_position_t) pos;
|
||||
} buffer_contents_t;
|
||||
#define BUFFER_CONTENTS_INIT {0, 0, 0}
|
||||
|
||||
HB_WASM_API (bool_t, buffer_contents_realloc) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_contents_t, contents),
|
||||
uint32_t size);
|
||||
|
||||
HB_WASM_API (void, buffer_contents_free) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_contents_t, contents));
|
||||
|
||||
typedef struct buffer_t buffer_t;
|
||||
|
||||
HB_WASM_API (bool_t, buffer_copy_contents) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_t, buffer),
|
||||
ptr_d(buffer_contents_t, contents));
|
||||
|
||||
HB_WASM_API (bool_t, buffer_set_contents) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_t, buffer),
|
||||
ptr_d(const buffer_contents_t, contents));
|
||||
|
||||
HB_WASM_API (direction_t, buffer_get_direction) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_t, buffer));
|
||||
|
||||
HB_WASM_API (script_t, buffer_get_script) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_t, buffer));
|
||||
|
||||
HB_WASM_API (void, buffer_reverse) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_t, buffer));
|
||||
|
||||
HB_WASM_API (void, buffer_reverse_clusters) (HB_WASM_EXEC_ENV
|
||||
ptr_d(buffer_t, buffer));
|
||||
|
||||
/* face */
|
||||
|
||||
typedef struct face_t face_t;
|
||||
|
||||
HB_WASM_API (ptr_t(face_t), face_create) (HB_WASM_EXEC_ENV
|
||||
ptr_d(blob_t, blob),
|
||||
unsigned int);
|
||||
|
||||
HB_WASM_API (bool_t, face_copy_table) (HB_WASM_EXEC_ENV
|
||||
ptr_d(face_t, face),
|
||||
tag_t table_tag,
|
||||
ptr_d(blob_t, blob));
|
||||
|
||||
HB_WASM_API (unsigned, face_get_upem) (HB_WASM_EXEC_ENV
|
||||
ptr_d(face_t, face));
|
||||
|
||||
/* font */
|
||||
|
||||
typedef struct font_t font_t;
|
||||
|
||||
HB_WASM_API (ptr_t(font_t), font_create) (HB_WASM_EXEC_ENV
|
||||
ptr_d(face_t, face));
|
||||
|
||||
HB_WASM_API (ptr_t(face_t), font_get_face) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font));
|
||||
|
||||
HB_WASM_API (void, font_get_scale) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
ptr_d(int32_t, x_scale),
|
||||
ptr_d(int32_t, y_scale));
|
||||
|
||||
HB_WASM_API (codepoint_t, font_get_glyph) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
codepoint_t unicode,
|
||||
codepoint_t variation_selector);
|
||||
|
||||
HB_WASM_API (position_t, font_get_glyph_h_advance) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
codepoint_t glyph);
|
||||
|
||||
HB_WASM_API (position_t, font_get_glyph_v_advance) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
codepoint_t glyph);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
position_t x_bearing;
|
||||
position_t y_bearing;
|
||||
position_t width;
|
||||
position_t height;
|
||||
} glyph_extents_t;
|
||||
|
||||
HB_WASM_API (bool_t, font_get_glyph_extents) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
codepoint_t glyph,
|
||||
ptr_d(glyph_extents_t, extents));
|
||||
|
||||
HB_WASM_API (void, font_glyph_to_string) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
codepoint_t glyph,
|
||||
char *s, uint32_t size);
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int length;
|
||||
ptr_t(int) coords;
|
||||
} coords_t;
|
||||
|
||||
HB_WASM_API (bool_t, font_copy_coords) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
ptr_d(coords_t, coords));
|
||||
|
||||
HB_WASM_API (bool_t, font_set_coords) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
ptr_d(coords_t, coords));
|
||||
|
||||
/* outline */
|
||||
|
||||
enum glyph_outline_point_type_t
|
||||
{
|
||||
MOVE_TO,
|
||||
LINE_TO,
|
||||
QUADRATIC_TO,
|
||||
CUBIC_TO,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
uint32_t type;
|
||||
} glyph_outline_point_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t n_points;
|
||||
ptr_t(glyph_outline_point_t) points;
|
||||
uint32_t n_contours;
|
||||
ptr_t(uint32_t) contours;
|
||||
} glyph_outline_t;
|
||||
#define GLYPH_OUTLINE_INIT {0, 0, 0, 0}
|
||||
|
||||
HB_WASM_API (void, glyph_outline_free) (HB_WASM_EXEC_ENV
|
||||
ptr_d(glyph_outline_t, outline));
|
||||
|
||||
HB_WASM_API (bool_t, font_copy_glyph_outline) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
codepoint_t glyph,
|
||||
ptr_d(glyph_outline_t, outline));
|
||||
|
||||
|
||||
/* shape */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
tag_t tag;
|
||||
uint32_t value;
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
} feature_t;
|
||||
#define FEATURE_GLOBAL_START 0
|
||||
#define FEATURE_GLOBAL_END ((uint32_t) -1)
|
||||
|
||||
HB_WASM_API (bool_t, shape_with) (HB_WASM_EXEC_ENV
|
||||
ptr_d(font_t, font),
|
||||
ptr_d(buffer_t, buffer),
|
||||
ptr_d(const feature_t, features),
|
||||
uint32_t num_features,
|
||||
const char *shaper);
|
||||
|
||||
/* Implement these in your shaper. */
|
||||
|
||||
HB_WASM_INTERFACE (ptr_t(void), shape_plan_create) (ptr_d(face_t, face));
|
||||
|
||||
HB_WASM_INTERFACE (bool_t, shape) (ptr_d(void, shape_plan),
|
||||
ptr_d(font_t, font),
|
||||
ptr_d(buffer_t, buffer),
|
||||
ptr_d(const feature_t, features),
|
||||
uint32_t num_features);
|
||||
|
||||
HB_WASM_INTERFACE (void, shape_plan_destroy) (ptr_d(void, shape_plan));
|
||||
|
||||
|
||||
HB_WASM_END_DECLS
|
||||
|
||||
#endif /* HB_WASM_API_H */
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright © 2023 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_WASM_API_HH
|
||||
#define HB_WASM_API_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#include <wasm_export.h>
|
||||
|
||||
#define HB_WASM_BEGIN_DECLS namespace hb { namespace wasm {
|
||||
#define HB_WASM_END_DECLS }}
|
||||
|
||||
#define HB_WASM_API(ret_t, name) HB_INTERNAL ret_t name
|
||||
#define HB_WASM_API_COMPOUND(ret_t, name) HB_INTERNAL void name
|
||||
|
||||
#define HB_WASM_EXEC_ENV wasm_exec_env_t exec_env,
|
||||
#define HB_WASM_EXEC_ENV_COMPOUND wasm_exec_env_t exec_env, ptr_t() retptr,
|
||||
|
||||
#define ptr_t(type_t) uint32_t
|
||||
#define ptr_d(type_t, name) uint32_t name##ptr
|
||||
|
||||
#include "hb-wasm-api.h"
|
||||
|
||||
#undef HB_WASM_BEGIN_DECLS
|
||||
#undef HB_WASM_END_DECLS
|
||||
|
||||
|
||||
enum {
|
||||
hb_wasm_ref_type_none,
|
||||
hb_wasm_ref_type_face,
|
||||
hb_wasm_ref_type_font,
|
||||
hb_wasm_ref_type_buffer,
|
||||
};
|
||||
|
||||
HB_INTERNAL extern hb_user_data_key_t _hb_wasm_ref_type_key;
|
||||
|
||||
#define nullref 0
|
||||
|
||||
#define HB_REF2OBJ(obj) \
|
||||
hb_##obj##_t *obj = nullptr; \
|
||||
HB_STMT_START { \
|
||||
(void) wasm_externref_ref2obj (obj##ptr, (void **) &obj); \
|
||||
/* Check object type. */ \
|
||||
/* This works because all our objects have the same hb_object_t layout. */ \
|
||||
if (unlikely (hb_##obj##_get_user_data (obj, &_hb_wasm_ref_type_key) != \
|
||||
(void *) hb_wasm_ref_type_##obj)) \
|
||||
obj = hb_##obj##_get_empty (); \
|
||||
} HB_STMT_END
|
||||
|
||||
#define HB_OBJ2REF(obj) \
|
||||
uint32_t obj##ref = nullref; \
|
||||
HB_STMT_START { \
|
||||
hb_##obj##_set_user_data (obj, &_hb_wasm_ref_type_key, \
|
||||
(void *) hb_wasm_ref_type_##obj, \
|
||||
nullptr, false); \
|
||||
(void) wasm_externref_obj2ref (module_inst, obj, &obj##ref); \
|
||||
} HB_STMT_END
|
||||
|
||||
#define HB_RETURN_STRUCT(type, name) \
|
||||
type *_name_ptr = nullptr; \
|
||||
{ \
|
||||
if (likely (wasm_runtime_validate_app_addr (module_inst, \
|
||||
retptr, sizeof (type)))) \
|
||||
{ \
|
||||
_name_ptr = (type *) wasm_runtime_addr_app_to_native (module_inst, retptr); \
|
||||
if (unlikely (!_name_ptr)) \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
type &name = *_name_ptr
|
||||
|
||||
#define HB_PTR_PARAM(type, name) \
|
||||
type *name = nullptr; \
|
||||
HB_STMT_START { \
|
||||
if (likely (wasm_runtime_validate_app_addr (module_inst, \
|
||||
name##ptr, sizeof (type)))) \
|
||||
name = (type *) wasm_runtime_addr_app_to_native (module_inst, name##ptr); \
|
||||
} HB_STMT_END
|
||||
|
||||
#define HB_ARRAY_PARAM(type, name, length) \
|
||||
type *name = nullptr; \
|
||||
HB_STMT_START { \
|
||||
if (likely (!hb_unsigned_mul_overflows (length, sizeof (type)) && \
|
||||
wasm_runtime_validate_app_addr (module_inst, \
|
||||
name##ptr, length * sizeof (type)))) \
|
||||
name = (type *) wasm_runtime_addr_app_to_native (module_inst, name##ptr); \
|
||||
} HB_STMT_END
|
||||
|
||||
#define HB_ARRAY_APP2NATIVE(type, name, length) \
|
||||
((type *) (!hb_unsigned_mul_overflows (length, sizeof (type)) && \
|
||||
validate_app_addr (name, (length) * sizeof (type)) ? \
|
||||
addr_app_to_native (name) : nullptr))
|
||||
|
||||
|
||||
#endif /* HB_WASM_API_HH */
|
|
@ -0,0 +1,469 @@
|
|||
/*
|
||||
* Copyright © 2011 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#define HB_DEBUG_WASM 1
|
||||
|
||||
#include "hb-shaper-impl.hh"
|
||||
|
||||
#ifdef HAVE_WASM
|
||||
|
||||
/* Compile wasm-micro-runtime with:
|
||||
*
|
||||
* $ cmake -DWAMR_BUILD_MULTI_MODULE=1 -DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_FAST_JIT=1
|
||||
* $ make
|
||||
*
|
||||
* If you manage to build a wasm shared module successfully and want to use it,
|
||||
* do the following:
|
||||
*
|
||||
* - Add -DWAMR_BUILD_MULTI_MODULE=1 to your cmake build for wasm-micro-runtime,
|
||||
*
|
||||
* - Remove the #define HB_WASM_NO_MODULES line below,
|
||||
*
|
||||
* - Install your shared module with name ending in .wasm in
|
||||
* $(prefix)/$(libdir)/harfbuzz/wasm/
|
||||
*
|
||||
* - Build your font's wasm code importing the shared modules with the desired
|
||||
* name. This can be done eg.: __attribute__((import_module("graphite2")))
|
||||
* before each symbol in the the shared-module's headers.
|
||||
*
|
||||
* - Try shaping your font and hope for the best...
|
||||
*
|
||||
* I haven't been able to get this to work since emcc's support for shared libraries
|
||||
* requires support from the host that seems to be missing from wasm-micro-runtime?
|
||||
*/
|
||||
|
||||
#include "hb-wasm-api.hh"
|
||||
#include "hb-wasm-api-list.hh"
|
||||
|
||||
#ifndef HB_WASM_NO_MODULES
|
||||
#define HB_WASM_NO_MODULES
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HB_WASM_NO_MODULES
|
||||
static bool HB_UNUSED
|
||||
_hb_wasm_module_reader (const char *module_name,
|
||||
uint8_t **p_buffer, uint32_t *p_size)
|
||||
{
|
||||
char path[sizeof (HB_WASM_MODULE_DIR) + 64] = HB_WASM_MODULE_DIR "/";
|
||||
strncat (path, module_name, sizeof (path) - sizeof (HB_WASM_MODULE_DIR) - 16);
|
||||
strncat (path, ".wasm", 6);
|
||||
|
||||
auto *blob = hb_blob_create_from_file (path);
|
||||
|
||||
unsigned length;
|
||||
auto *data = hb_blob_get_data (blob, &length);
|
||||
|
||||
*p_buffer = (uint8_t *) hb_malloc (length);
|
||||
|
||||
if (length && !p_buffer)
|
||||
return false;
|
||||
|
||||
memcpy (*p_buffer, data, length);
|
||||
*p_size = length;
|
||||
|
||||
hb_blob_destroy (blob);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void HB_UNUSED
|
||||
_hb_wasm_module_destroyer (uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
hb_free (buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* shaper face data
|
||||
*/
|
||||
|
||||
#define HB_WASM_TAG_WASM HB_TAG('W','a','s','m')
|
||||
|
||||
struct hb_wasm_shape_plan_t {
|
||||
wasm_module_inst_t module_inst;
|
||||
wasm_exec_env_t exec_env;
|
||||
ptr_d(void, wasm_shape_plan);
|
||||
};
|
||||
|
||||
struct hb_wasm_face_data_t {
|
||||
hb_blob_t *wasm_blob;
|
||||
wasm_module_t wasm_module;
|
||||
mutable hb_atomic_ptr_t<hb_wasm_shape_plan_t> plan;
|
||||
};
|
||||
|
||||
static bool
|
||||
_hb_wasm_init ()
|
||||
{
|
||||
/* XXX
|
||||
*
|
||||
* Umm. Make this threadsafe. How?!
|
||||
* It's clunky that we can't allocate a static mutex.
|
||||
* So we have to first allocate one on the heap atomically...
|
||||
*
|
||||
* Do we also need to lock around module creation?
|
||||
*
|
||||
* Also, wasm-micro-runtime uses a singleton instance. So if
|
||||
* another library or client uses it, all bets are off. :-(
|
||||
* If nothing else, around HB_REF2OBJ().
|
||||
*/
|
||||
|
||||
static bool initialized;
|
||||
if (initialized)
|
||||
return true;
|
||||
|
||||
RuntimeInitArgs init_args;
|
||||
memset (&init_args, 0, sizeof (RuntimeInitArgs));
|
||||
|
||||
init_args.mem_alloc_type = Alloc_With_Allocator;
|
||||
init_args.mem_alloc_option.allocator.malloc_func = (void *) hb_malloc;
|
||||
init_args.mem_alloc_option.allocator.realloc_func = (void *) hb_realloc;
|
||||
init_args.mem_alloc_option.allocator.free_func = (void *) hb_free;
|
||||
|
||||
// Native symbols need below registration phase
|
||||
init_args.n_native_symbols = ARRAY_LENGTH (_hb_wasm_native_symbols);
|
||||
init_args.native_module_name = "env";
|
||||
init_args.native_symbols = _hb_wasm_native_symbols;
|
||||
|
||||
if (unlikely (!wasm_runtime_full_init (&init_args)))
|
||||
{
|
||||
DEBUG_MSG (WASM, nullptr, "Init runtime environment failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef HB_WASM_NO_MODULES
|
||||
wasm_runtime_set_module_reader (_hb_wasm_module_reader,
|
||||
_hb_wasm_module_destroyer);
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
hb_wasm_face_data_t *
|
||||
_hb_wasm_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
char error[128];
|
||||
hb_wasm_face_data_t *data = nullptr;
|
||||
hb_blob_t *wasm_blob = nullptr;
|
||||
wasm_module_t wasm_module = nullptr;
|
||||
|
||||
wasm_blob = hb_face_reference_table (face, HB_WASM_TAG_WASM);
|
||||
unsigned length = hb_blob_get_length (wasm_blob);
|
||||
if (!length)
|
||||
goto fail;
|
||||
|
||||
if (!_hb_wasm_init ())
|
||||
goto fail;
|
||||
|
||||
wasm_module = wasm_runtime_load ((uint8_t *) hb_blob_get_data_writable (wasm_blob, nullptr),
|
||||
length, error, sizeof (error));
|
||||
if (unlikely (!wasm_module))
|
||||
{
|
||||
DEBUG_MSG (WASM, nullptr, "Load wasm module failed: %s", error);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
data = (hb_wasm_face_data_t *) hb_calloc (1, sizeof (hb_wasm_face_data_t));
|
||||
if (unlikely (!data))
|
||||
goto fail;
|
||||
|
||||
data->wasm_blob = wasm_blob;
|
||||
data->wasm_module = wasm_module;
|
||||
|
||||
return data;
|
||||
|
||||
fail:
|
||||
if (wasm_module)
|
||||
wasm_runtime_unload (wasm_module);
|
||||
hb_blob_destroy (wasm_blob);
|
||||
hb_free (data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static hb_wasm_shape_plan_t *
|
||||
acquire_shape_plan (hb_face_t *face,
|
||||
const hb_wasm_face_data_t *face_data)
|
||||
{
|
||||
char error[128];
|
||||
|
||||
/* Fetch cached one if available. */
|
||||
hb_wasm_shape_plan_t *plan = face_data->plan.get_acquire ();
|
||||
if (likely (plan && face_data->plan.cmpexch (plan, nullptr)))
|
||||
return plan;
|
||||
|
||||
plan = (hb_wasm_shape_plan_t *) hb_calloc (1, sizeof (hb_wasm_shape_plan_t));
|
||||
|
||||
wasm_module_inst_t module_inst = nullptr;
|
||||
wasm_exec_env_t exec_env = nullptr;
|
||||
wasm_function_inst_t func = nullptr;
|
||||
|
||||
constexpr uint32_t stack_size = 32 * 1024, heap_size = 2 * 1024 * 1024;
|
||||
|
||||
module_inst = plan->module_inst = wasm_runtime_instantiate (face_data->wasm_module,
|
||||
stack_size, heap_size,
|
||||
error, sizeof (error));
|
||||
if (unlikely (!module_inst))
|
||||
{
|
||||
DEBUG_MSG (WASM, face_data, "Create wasm module instance failed: %s", error);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
exec_env = plan->exec_env = wasm_runtime_create_exec_env (module_inst,
|
||||
stack_size);
|
||||
if (unlikely (!exec_env)) {
|
||||
DEBUG_MSG (WASM, face_data, "Create wasm execution environment failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
func = wasm_runtime_lookup_function (module_inst, "shape_plan_create", nullptr);
|
||||
if (func)
|
||||
{
|
||||
wasm_val_t results[1];
|
||||
wasm_val_t arguments[1];
|
||||
|
||||
HB_OBJ2REF (face);
|
||||
if (unlikely (!faceref))
|
||||
{
|
||||
DEBUG_MSG (WASM, face_data, "Failed to register face object.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
results[0].kind = WASM_I32;
|
||||
arguments[0].kind = WASM_I32;
|
||||
arguments[0].of.i32 = faceref;
|
||||
bool ret = wasm_runtime_call_wasm_a (exec_env, func,
|
||||
ARRAY_LENGTH (results), results,
|
||||
ARRAY_LENGTH (arguments), arguments);
|
||||
|
||||
if (unlikely (!ret))
|
||||
{
|
||||
DEBUG_MSG (WASM, module_inst, "Calling shape_plan_create() failed: %s",
|
||||
wasm_runtime_get_exception (module_inst));
|
||||
goto fail;
|
||||
}
|
||||
plan->wasm_shape_planptr = results[0].of.i32;
|
||||
}
|
||||
|
||||
return plan;
|
||||
|
||||
fail:
|
||||
|
||||
if (exec_env)
|
||||
wasm_runtime_destroy_exec_env (exec_env);
|
||||
if (module_inst)
|
||||
wasm_runtime_deinstantiate (module_inst);
|
||||
hb_free (plan);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void
|
||||
release_shape_plan (const hb_wasm_face_data_t *face_data,
|
||||
hb_wasm_shape_plan_t *plan,
|
||||
bool cache = false)
|
||||
{
|
||||
if (cache && face_data->plan.cmpexch (nullptr, plan))
|
||||
return;
|
||||
|
||||
auto *module_inst = plan->module_inst;
|
||||
auto *exec_env = plan->exec_env;
|
||||
|
||||
/* Is there even any point to having a shape_plan_destroy function
|
||||
* and calling it? */
|
||||
if (plan->wasm_shape_planptr)
|
||||
{
|
||||
|
||||
auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy", nullptr);
|
||||
if (func)
|
||||
{
|
||||
wasm_val_t arguments[1];
|
||||
|
||||
arguments[0].kind = WASM_I32;
|
||||
arguments[0].of.i32 = plan->wasm_shape_planptr;
|
||||
bool ret = wasm_runtime_call_wasm_a (exec_env, func,
|
||||
0, nullptr,
|
||||
ARRAY_LENGTH (arguments), arguments);
|
||||
|
||||
if (unlikely (!ret))
|
||||
{
|
||||
DEBUG_MSG (WASM, module_inst, "Calling shape_plan_destroy() failed: %s",
|
||||
wasm_runtime_get_exception (module_inst));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wasm_runtime_destroy_exec_env (exec_env);
|
||||
wasm_runtime_deinstantiate (module_inst);
|
||||
hb_free (plan);
|
||||
}
|
||||
|
||||
void
|
||||
_hb_wasm_shaper_face_data_destroy (hb_wasm_face_data_t *data)
|
||||
{
|
||||
if (data->plan.get_relaxed ())
|
||||
release_shape_plan (data, data->plan);
|
||||
wasm_runtime_unload (data->wasm_module);
|
||||
hb_blob_destroy (data->wasm_blob);
|
||||
hb_free (data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shaper font data
|
||||
*/
|
||||
|
||||
struct hb_wasm_font_data_t {};
|
||||
|
||||
hb_wasm_font_data_t *
|
||||
_hb_wasm_shaper_font_data_create (hb_font_t *font HB_UNUSED)
|
||||
{
|
||||
return (hb_wasm_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_wasm_shaper_font_data_destroy (hb_wasm_font_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shaper
|
||||
*/
|
||||
|
||||
hb_bool_t
|
||||
_hb_wasm_shape (hb_shape_plan_t *shape_plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer,
|
||||
const hb_feature_t *features,
|
||||
unsigned int num_features)
|
||||
{
|
||||
if (unlikely (buffer->in_error ()))
|
||||
return false;
|
||||
|
||||
bool ret = true;
|
||||
hb_face_t *face = font->face;
|
||||
const hb_wasm_face_data_t *face_data = face->data.wasm;
|
||||
|
||||
bool retried = false;
|
||||
if (0)
|
||||
{
|
||||
retry:
|
||||
DEBUG_MSG (WASM, font, "Retrying...");
|
||||
}
|
||||
|
||||
wasm_function_inst_t func = nullptr;
|
||||
|
||||
hb_wasm_shape_plan_t *plan = acquire_shape_plan (face, face_data);
|
||||
if (unlikely (!plan))
|
||||
{
|
||||
DEBUG_MSG (WASM, face_data, "Acquiring shape-plan failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *module_inst = plan->module_inst;
|
||||
auto *exec_env = plan->exec_env;
|
||||
|
||||
HB_OBJ2REF (font);
|
||||
HB_OBJ2REF (buffer);
|
||||
if (unlikely (!fontref || !bufferref))
|
||||
{
|
||||
DEBUG_MSG (WASM, module_inst, "Failed to register objects.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
func = wasm_runtime_lookup_function (module_inst, "shape", nullptr);
|
||||
if (unlikely (!func))
|
||||
{
|
||||
DEBUG_MSG (WASM, module_inst, "Shape function not found.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wasm_val_t results[1];
|
||||
wasm_val_t arguments[5];
|
||||
|
||||
results[0].kind = WASM_I32;
|
||||
arguments[0].kind = WASM_I32;
|
||||
arguments[0].of.i32 = plan->wasm_shape_planptr;
|
||||
arguments[1].kind = WASM_I32;
|
||||
arguments[1].of.i32 = fontref;
|
||||
arguments[2].kind = WASM_I32;
|
||||
arguments[2].of.i32 = bufferref;
|
||||
arguments[3].kind = WASM_I32;
|
||||
arguments[3].of.i32 = num_features ? wasm_runtime_module_dup_data (module_inst,
|
||||
(const char *) features,
|
||||
num_features * sizeof (features[0])) : 0;
|
||||
arguments[4].kind = WASM_I32;
|
||||
arguments[4].of.i32 = num_features;
|
||||
|
||||
ret = wasm_runtime_call_wasm_a (exec_env, func,
|
||||
ARRAY_LENGTH (results), results,
|
||||
ARRAY_LENGTH (arguments), arguments);
|
||||
|
||||
if (num_features)
|
||||
wasm_runtime_module_free (module_inst, arguments[2].of.i32);
|
||||
|
||||
if (unlikely (!ret || !results[0].of.i32))
|
||||
{
|
||||
DEBUG_MSG (WASM, module_inst, "Calling shape() failed: %s",
|
||||
wasm_runtime_get_exception (module_inst));
|
||||
if (!buffer->ensure_unicode ())
|
||||
{
|
||||
DEBUG_MSG (WASM, font, "Shape failed but buffer is not in Unicode; failing...");
|
||||
goto fail;
|
||||
}
|
||||
if (retried)
|
||||
{
|
||||
DEBUG_MSG (WASM, font, "Giving up...");
|
||||
goto fail;
|
||||
}
|
||||
buffer->successful = true;
|
||||
retried = true;
|
||||
release_shape_plan (face_data, plan);
|
||||
plan = nullptr;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* TODO Regularize clusters according to direction & cluster level,
|
||||
* such that client doesn't crash with unmet expectations. */
|
||||
|
||||
if (!results[0].of.i32)
|
||||
{
|
||||
fail:
|
||||
ret = false;
|
||||
}
|
||||
|
||||
release_shape_plan (face_data, plan, ret);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
buffer->clear_glyph_flags ();
|
||||
buffer->unsafe_to_break ();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -324,6 +324,19 @@ hb_glib_headers = files('hb-glib.h')
|
|||
hb_graphite2_sources = files('hb-graphite2.cc')
|
||||
hb_graphite2_headers = files('hb-graphite2.h')
|
||||
|
||||
hb_wasm_sources = files(
|
||||
'hb-wasm-api.cc',
|
||||
'hb-wasm-api.hh',
|
||||
'hb-wasm-api-blob.hh',
|
||||
'hb-wasm-api-buffer.hh',
|
||||
'hb-wasm-api-common.hh',
|
||||
'hb-wasm-api-face.hh',
|
||||
'hb-wasm-api-font.hh',
|
||||
'hb-wasm-api-shape.hh',
|
||||
'hb-wasm-shape.cc',
|
||||
)
|
||||
hb_wasm_headers = files()
|
||||
|
||||
# System-dependent sources and headers
|
||||
|
||||
hb_coretext_sources = files('hb-coretext.cc')
|
||||
|
@ -416,7 +429,7 @@ custom_target('harfbuzz.cc',
|
|||
output: 'harfbuzz.cc',
|
||||
input: hb_base_sources + hb_glib_sources + hb_ft_sources +
|
||||
hb_graphite2_sources + hb_uniscribe_sources + hb_gdi_sources +
|
||||
hb_directwrite_sources + hb_coretext_sources,
|
||||
hb_directwrite_sources + hb_coretext_sources + hb_wasm_sources,
|
||||
command: [find_program('gen-harfbuzzcc.py'),
|
||||
'@OUTPUT@', meson.current_source_dir(), '@INPUT@'],
|
||||
)
|
||||
|
@ -459,6 +472,13 @@ if conf.get('HAVE_GRAPHITE2', 0) == 1
|
|||
harfbuzz_deps += [graphite2_dep, graphite_dep]
|
||||
endif
|
||||
|
||||
if conf.get('HAVE_WASM', 0) == 1
|
||||
hb_sources += hb_wasm_sources
|
||||
hb_headers += hb_wasm_headers
|
||||
harfbuzz_deps += wasm_dep
|
||||
#harfbuzz_deps += llvm_dep
|
||||
endif
|
||||
|
||||
if conf.get('HAVE_UNISCRIBE', 0) == 1
|
||||
hb_sources += hb_uniscribe_sources
|
||||
hb_headers += hb_uniscribe_headers
|
||||
|
@ -496,6 +516,7 @@ features = [
|
|||
'GRAPHITE',
|
||||
'ICU',
|
||||
'UNISCRIBE',
|
||||
'WASM',
|
||||
]
|
||||
|
||||
hb_enabled_features = configuration_data()
|
||||
|
@ -909,7 +930,10 @@ if get_option('tests').enabled()
|
|||
env.set('HBHEADERS', ' '.join(HBHEADERS))
|
||||
|
||||
if cpp.get_argument_syntax() != 'msvc' and not meson.is_cross_build() # ensure the local tools are usable
|
||||
dist_check_script += ['check-libstdc++', 'check-static-inits', 'check-symbols']
|
||||
dist_check_script += ['check-static-inits', 'check-symbols']
|
||||
if get_option('wasm').disabled()
|
||||
dist_check_script += ['check-libstdc++']
|
||||
endif
|
||||
endif
|
||||
|
||||
foreach name : dist_check_script
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
FONTS = CharisSIL-R.wasm.ttf Scheherazade-R.wasm.ttf AwamiNastaliq-Regular.wasm.ttf
|
||||
ADD_TABLE = ../../addTable.py
|
||||
|
||||
all: $(FONTS)
|
||||
|
||||
%.wasm: %.cc ../../hb-wasm-api.h
|
||||
emcc \
|
||||
-I ../.. \
|
||||
-I ~/graphite/include/ \
|
||||
-fvisibility=hidden \
|
||||
-Wl,--allow-undefined \
|
||||
-Wl,--no-entry \
|
||||
-Wl,--strip-all \
|
||||
-sERROR_ON_UNDEFINED_SYMBOLS=0 \
|
||||
-Wl,--export=malloc -Wl,--export=free \
|
||||
~/graphite/src/libgraphite2.a \
|
||||
~/wasm/wasi-sdk-19.0/share/wasi-sysroot/lib/wasm32-wasi/libc.a \
|
||||
$< \
|
||||
-o $@
|
||||
|
||||
|
||||
%.wasm.ttf: %.ttf shape.wasm $(ADD_TABLE)
|
||||
python $(ADD_TABLE) $< $@ shape.wasm
|
||||
|
||||
clean:
|
||||
$(RM) shape.wasm $(FONTS)
|
||||
|
||||
.PRECIOUS: shape.wasm
|
|
@ -0,0 +1,249 @@
|
|||
#define HB_WASM_INTERFACE(ret_t, name) __attribute__((export_name(#name))) ret_t name
|
||||
|
||||
#include <hb-wasm-api.h>
|
||||
|
||||
#include <graphite2/Segment.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void debugprint1 (char *s, int32_t);
|
||||
void debugprint2 (char *s, int32_t, int32_t);
|
||||
|
||||
static const void *copy_table (const void *data, unsigned int tag, size_t *len)
|
||||
{
|
||||
face_t *face = (face_t *) data;
|
||||
blob_t blob = BLOB_INIT;
|
||||
if (!face_copy_table (face, tag, &blob))
|
||||
abort ();
|
||||
|
||||
*len = blob.length;
|
||||
return blob.data;
|
||||
}
|
||||
|
||||
static void free_table (const void *data, const void *table_data)
|
||||
{
|
||||
blob_t blob;
|
||||
blob.length = 0; // Doesn't matter
|
||||
blob.data = (char *) table_data;
|
||||
blob_free (&blob);
|
||||
}
|
||||
|
||||
void *
|
||||
shape_plan_create (face_t *face)
|
||||
{
|
||||
const gr_face_ops ops = {sizeof (gr_face_ops), ©_table, &free_table};
|
||||
gr_face *grface = gr_make_face_with_ops (face, &ops, gr_face_preloadAll);
|
||||
return grface;
|
||||
}
|
||||
|
||||
void
|
||||
shape_plan_destroy (void *data)
|
||||
{
|
||||
gr_face_destroy ((gr_face *) data);
|
||||
}
|
||||
|
||||
bool_t
|
||||
shape (void *shape_plan,
|
||||
font_t *font,
|
||||
buffer_t *buffer,
|
||||
const feature_t *features,
|
||||
uint32_t num_features)
|
||||
{
|
||||
face_t *face = font_get_face (font);
|
||||
gr_face *grface = (gr_face *) shape_plan;
|
||||
|
||||
direction_t direction = buffer_get_direction (buffer);
|
||||
direction_t horiz_dir = script_get_horizontal_direction (buffer_get_script (buffer));
|
||||
/* TODO vertical:
|
||||
* The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
|
||||
* Ogham fonts are supposed to be implemented BTT or not. Need to research that
|
||||
* first. */
|
||||
if ((DIRECTION_IS_HORIZONTAL (direction) &&
|
||||
direction != horiz_dir && horiz_dir != DIRECTION_INVALID) ||
|
||||
(DIRECTION_IS_VERTICAL (direction) &&
|
||||
direction != DIRECTION_TTB))
|
||||
{
|
||||
buffer_reverse_clusters (buffer);
|
||||
direction = DIRECTION_REVERSE (direction);
|
||||
}
|
||||
|
||||
buffer_contents_t contents = BUFFER_CONTENTS_INIT;
|
||||
if (!buffer_copy_contents (buffer, &contents))
|
||||
return false;
|
||||
|
||||
gr_segment *seg = nullptr;
|
||||
const gr_slot *is;
|
||||
unsigned int ci = 0, ic = 0;
|
||||
unsigned int curradvx = 0, curradvy = 0;
|
||||
unsigned length = contents.length;
|
||||
|
||||
uint32_t *chars = (uint32_t *) malloc (length * sizeof (uint32_t));
|
||||
if (!chars)
|
||||
return false;
|
||||
for (unsigned int i = 0; i < contents.length; ++i)
|
||||
chars[i] = contents.info[i].codepoint;
|
||||
|
||||
seg = gr_make_seg (nullptr, grface,
|
||||
0, // https://github.com/harfbuzz/harfbuzz/issues/3439#issuecomment-1442650148
|
||||
nullptr,
|
||||
gr_utf32, chars, contents.length,
|
||||
2 | (direction == DIRECTION_RTL ? 1 : 0));
|
||||
|
||||
free (chars);
|
||||
|
||||
if (!seg)
|
||||
return false;
|
||||
|
||||
unsigned int glyph_count = gr_seg_n_slots (seg);
|
||||
|
||||
struct cluster_t {
|
||||
unsigned int base_char;
|
||||
unsigned int num_chars;
|
||||
unsigned int base_glyph;
|
||||
unsigned int num_glyphs;
|
||||
unsigned int cluster;
|
||||
int advance;
|
||||
};
|
||||
|
||||
length = glyph_count;
|
||||
if (!buffer_contents_realloc (&contents, length))
|
||||
return false;
|
||||
cluster_t *clusters = (cluster_t *) malloc (length * sizeof (cluster_t));
|
||||
uint32_t *gids = (uint32_t *) malloc (length * sizeof (uint32_t));
|
||||
if (!clusters || !gids)
|
||||
{
|
||||
free (clusters);
|
||||
free (gids);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset (clusters, 0, sizeof (clusters[0]) * length);
|
||||
codepoint_t *pg = gids;
|
||||
clusters[0].cluster = contents.info[0].cluster;
|
||||
unsigned int upem = face_get_upem (face);
|
||||
int32_t font_x_scale, font_y_scale;
|
||||
font_get_scale (font, &font_x_scale, &font_y_scale);
|
||||
float xscale = (float) font_x_scale / upem;
|
||||
float yscale = (float) font_y_scale / upem;
|
||||
yscale *= yscale / xscale;
|
||||
unsigned int curradv = 0;
|
||||
if (DIRECTION_IS_BACKWARD (direction))
|
||||
{
|
||||
curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale;
|
||||
clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv;
|
||||
}
|
||||
else
|
||||
clusters[0].advance = 0;
|
||||
for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
|
||||
{
|
||||
unsigned int before = gr_slot_before (is);
|
||||
unsigned int after = gr_slot_after (is);
|
||||
*pg = gr_slot_gid (is);
|
||||
pg++;
|
||||
while (clusters[ci].base_char > before && ci)
|
||||
{
|
||||
clusters[ci-1].num_chars += clusters[ci].num_chars;
|
||||
clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
|
||||
clusters[ci-1].advance += clusters[ci].advance;
|
||||
ci--;
|
||||
}
|
||||
|
||||
if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
|
||||
{
|
||||
cluster_t *c = clusters + ci + 1;
|
||||
c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
|
||||
c->cluster = contents.info[c->base_char].cluster;
|
||||
c->num_chars = before - c->base_char;
|
||||
c->base_glyph = ic;
|
||||
c->num_glyphs = 0;
|
||||
if (DIRECTION_IS_BACKWARD (direction))
|
||||
{
|
||||
c->advance = curradv - gr_slot_origin_X(is) * xscale;
|
||||
curradv -= c->advance;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->advance = 0;
|
||||
clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv;
|
||||
curradv += clusters[ci].advance;
|
||||
}
|
||||
ci++;
|
||||
}
|
||||
clusters[ci].num_glyphs++;
|
||||
|
||||
if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
|
||||
clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
|
||||
}
|
||||
|
||||
if (DIRECTION_IS_BACKWARD (direction))
|
||||
clusters[ci].advance += curradv;
|
||||
else
|
||||
clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv;
|
||||
ci++;
|
||||
|
||||
for (unsigned int i = 0; i < ci; ++i)
|
||||
{
|
||||
for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
|
||||
{
|
||||
glyph_info_t *info = &contents.info[clusters[i].base_glyph + j];
|
||||
info->codepoint = gids[clusters[i].base_glyph + j];
|
||||
info->cluster = clusters[i].cluster;
|
||||
info->var1 = (unsigned) clusters[i].advance; // all glyphs in the cluster get the same advance
|
||||
}
|
||||
}
|
||||
contents.length = glyph_count;
|
||||
|
||||
/* Positioning. */
|
||||
unsigned int currclus = 0xFFFFFFFF;
|
||||
const glyph_info_t *info = contents.info;
|
||||
glyph_position_t *pPos = contents.pos;
|
||||
if (!DIRECTION_IS_BACKWARD (direction))
|
||||
{
|
||||
curradvx = 0;
|
||||
for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
|
||||
{
|
||||
pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx;
|
||||
pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
|
||||
if (info->cluster != currclus) {
|
||||
pPos->x_advance = (int) info->var1;
|
||||
curradvx += pPos->x_advance;
|
||||
currclus = info->cluster;
|
||||
} else
|
||||
pPos->x_advance = 0.;
|
||||
|
||||
pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
|
||||
curradvy += pPos->y_advance;
|
||||
}
|
||||
buffer_set_contents (buffer, &contents);
|
||||
}
|
||||
else
|
||||
{
|
||||
curradvx = gr_seg_advance_X(seg) * xscale;
|
||||
for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
|
||||
{
|
||||
if (info->cluster != currclus)
|
||||
{
|
||||
pPos->x_advance = (int) info->var1;
|
||||
curradvx -= pPos->x_advance;
|
||||
currclus = info->cluster;
|
||||
} else
|
||||
pPos->x_advance = 0.;
|
||||
|
||||
pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
|
||||
curradvy -= pPos->y_advance;
|
||||
pPos->x_offset = gr_slot_origin_X (is) * xscale - (int) info->var1 - curradvx + pPos->x_advance;
|
||||
pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
|
||||
}
|
||||
buffer_set_contents (buffer, &contents);
|
||||
buffer_reverse_clusters (buffer);
|
||||
}
|
||||
|
||||
gr_seg_destroy (seg);
|
||||
free (clusters);
|
||||
free (gids);
|
||||
|
||||
bool ret = glyph_count;
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "harfbuzz-wasm"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
kurbo = { version = "0.9.0", optional = true }
|
|
@ -0,0 +1,464 @@
|
|||
#![warn(missing_docs)]
|
||||
#![allow(dead_code)]
|
||||
//! Interface to Harfbuzz's WASM exports
|
||||
//!
|
||||
//! This crate is designed to make it easier to write a
|
||||
//! WASM shaper for your font using Rust. It binds the
|
||||
//! functions exported by Harfbuzz into the WASM runtime,
|
||||
//! and wraps them in an ergonomic interface using Rust
|
||||
//! structures. For example, here is a basic shaping engine:
|
||||
//!
|
||||
//!
|
||||
//! ```rust
|
||||
//! #[wasm_bindgen]
|
||||
//! pub fn shape(font_ref: u32, buf_ref: u32) -> i32 {
|
||||
//! let font = Font::from_ref(font_ref);
|
||||
//! let mut buffer = GlyphBuffer::from_ref(buf_ref);
|
||||
//! for mut item in buffer.glyphs.iter_mut() {
|
||||
//! // Map character to glyph
|
||||
//! item.codepoint = font.get_glyph(codepoint, 0);
|
||||
//! // Set advance width
|
||||
//! item.h_advance = font.get_glyph_h_advance(item.codepoint);
|
||||
//! }
|
||||
//! 1
|
||||
//! }
|
||||
//! ```
|
||||
use std::ffi::{c_int, CStr, CString};
|
||||
|
||||
#[cfg(feature = "kurbo")]
|
||||
use kurbo::BezPath;
|
||||
|
||||
// We don't use #[wasm_bindgen] here because that makes
|
||||
// assumptions about Javascript calling conventions. We
|
||||
// really do just want to import some C symbols and run
|
||||
// them in unsafe-land!
|
||||
extern "C" {
|
||||
fn face_get_upem(face: u32) -> u32;
|
||||
fn font_get_face(font: u32) -> u32;
|
||||
fn font_get_glyph(font: u32, unicode: u32, uvs: u32) -> u32;
|
||||
fn font_get_scale(font: u32, x_scale: *mut i32, y_scale: *mut i32);
|
||||
fn font_get_glyph_extents(font: u32, glyph: u32, extents: *mut CGlyphExtents) -> bool;
|
||||
fn font_glyph_to_string(font: u32, glyph: u32, str: *const u8, len: u32);
|
||||
fn font_get_glyph_h_advance(font: u32, glyph: u32) -> i32;
|
||||
fn font_get_glyph_v_advance(font: u32, glyph: u32) -> i32;
|
||||
fn font_copy_glyph_outline(font: u32, glyph: u32, outline: *mut CGlyphOutline) -> bool;
|
||||
fn face_copy_table(font: u32, tag: u32, blob: *mut Blob) -> bool;
|
||||
fn buffer_copy_contents(buffer: u32, cbuffer: *mut CBufferContents) -> bool;
|
||||
fn buffer_set_contents(buffer: u32, cbuffer: &CBufferContents) -> bool;
|
||||
fn debugprint(s: *const u8);
|
||||
fn shape_with(
|
||||
font: u32,
|
||||
buffer: u32,
|
||||
features: u32,
|
||||
num_features: u32,
|
||||
shaper: *const u8,
|
||||
) -> i32;
|
||||
}
|
||||
|
||||
/// An opaque reference to a font at a given size and
|
||||
/// variation. It is equivalent to the `hb_font_t` pointer
|
||||
/// in Harfbuzz.
|
||||
#[derive(Debug)]
|
||||
pub struct Font(u32);
|
||||
|
||||
impl Font {
|
||||
/// Initialize a `Font` struct from the reference provided
|
||||
/// by Harfbuzz to the `shape` function.
|
||||
pub fn from_ref(ptr: u32) -> Self {
|
||||
Self(ptr)
|
||||
}
|
||||
/// Call the given Harfbuzz shaper on a buffer reference.
|
||||
///
|
||||
/// For example, `font.shape_with(buffer_ref, "ot")` will
|
||||
/// run standard OpenType shaping, allowing you to modify
|
||||
/// the buffer contents after glyph mapping, substitution
|
||||
/// and positioning has taken place.
|
||||
pub fn shape_with(&self, buffer_ref: u32, shaper: &str) {
|
||||
let c_shaper = CString::new(shaper).unwrap();
|
||||
unsafe {
|
||||
shape_with(self.0, buffer_ref, 0, 0, c_shaper.as_ptr() as *const u8);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the font face object that this font belongs to.
|
||||
pub fn get_face(&self) -> Face {
|
||||
Face(unsafe { font_get_face(self.0) })
|
||||
}
|
||||
|
||||
/// Map a Unicode codepoint to a glyph ID.
|
||||
///
|
||||
/// The `uvs` parameter specifies a Unicode Variation
|
||||
/// Selector codepoint which is used in conjunction with
|
||||
/// [format 14 cmap tables](https://learn.microsoft.com/en-us/typography/opentype/spec/cmap#format-14-unicode-variation-sequences)
|
||||
/// to provide alternate glyph mappings for characters with
|
||||
/// Unicode Variation Sequences. Generally you will pass
|
||||
/// `0`.
|
||||
pub fn get_glyph(&self, unicode: u32, uvs: u32) -> u32 {
|
||||
unsafe { font_get_glyph(self.0, unicode, uvs) }
|
||||
}
|
||||
|
||||
/// Get the extents for a given glyph ID, in its design position.
|
||||
pub fn get_glyph_extents(&self, glyph: u32) -> CGlyphExtents {
|
||||
let mut extents = CGlyphExtents::default();
|
||||
unsafe {
|
||||
font_get_glyph_extents(self.0, glyph, &mut extents);
|
||||
}
|
||||
extents
|
||||
}
|
||||
|
||||
/// Get the default advance width for a given glyph ID.
|
||||
pub fn get_glyph_h_advance(&self, glyph: u32) -> i32 {
|
||||
unsafe { font_get_glyph_h_advance(self.0, glyph) }
|
||||
}
|
||||
|
||||
/// Get the default vertical advance for a given glyph ID.
|
||||
fn get_glyph_v_advance(&self, glyph: u32) -> i32 {
|
||||
unsafe { font_get_glyph_v_advance(self.0, glyph) }
|
||||
}
|
||||
|
||||
/// Get the name of a glyph.
|
||||
///
|
||||
/// If no names are provided by the font, names of the form
|
||||
/// `gidXXX` are constructed.
|
||||
pub fn get_glyph_name(&self, glyph: u32) -> String {
|
||||
let mut s = [1u8; 32];
|
||||
unsafe {
|
||||
font_glyph_to_string(self.0, glyph, s.as_mut_ptr(), 32);
|
||||
}
|
||||
unsafe { CStr::from_ptr(s.as_ptr() as *const _) }
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// Get the X and Y scale factor applied to this font.
|
||||
///
|
||||
/// This should be divided by the units per em value to
|
||||
/// provide a scale factor mapping from design units to
|
||||
/// user units. (See [`Face::get_upem`].)
|
||||
pub fn get_scale(&self) -> (i32, i32) {
|
||||
let mut x_scale: i32 = 0;
|
||||
let mut y_scale: i32 = 0;
|
||||
unsafe {
|
||||
font_get_scale(
|
||||
self.0,
|
||||
&mut x_scale as *mut c_int,
|
||||
&mut y_scale as *mut c_int,
|
||||
)
|
||||
};
|
||||
(x_scale, y_scale)
|
||||
}
|
||||
|
||||
#[cfg(feature = "kurbo")]
|
||||
/// Get the outline of a glyph as a vector of bezier paths
|
||||
pub fn get_outline(&self, glyph: u32) -> Vec<BezPath> {
|
||||
let mut outline = CGlyphOutline {
|
||||
n_points: 0,
|
||||
points: std::ptr::null_mut(),
|
||||
n_contours: 0,
|
||||
contours: std::ptr::null_mut(),
|
||||
};
|
||||
let end_pts_of_contours: &[usize] = unsafe {
|
||||
font_copy_glyph_outline(self.0, glyph, &mut outline);
|
||||
std::slice::from_raw_parts(outline.contours, outline.n_contours as usize)
|
||||
};
|
||||
let points: &[CGlyphOutlinePoint] =
|
||||
unsafe { std::slice::from_raw_parts(outline.points, outline.n_points as usize) };
|
||||
let mut results: Vec<BezPath> = vec![];
|
||||
let mut start_pt: usize = 0;
|
||||
for end_pt in end_pts_of_contours {
|
||||
let this_contour = &points[start_pt..*end_pt];
|
||||
start_pt = *end_pt;
|
||||
let mut path = BezPath::new();
|
||||
let mut ix = 0;
|
||||
while ix < this_contour.len() {
|
||||
let point = &this_contour[ix];
|
||||
match point.pointtype {
|
||||
PointType::MoveTo => path.move_to((point.x as f64, point.y as f64)),
|
||||
PointType::LineTo => path.line_to((point.x as f64, point.y as f64)),
|
||||
PointType::QuadraticTo => {
|
||||
ix += 1;
|
||||
let end_pt = &this_contour[ix];
|
||||
path.quad_to(
|
||||
(point.x as f64, point.y as f64),
|
||||
(end_pt.x as f64, end_pt.y as f64),
|
||||
);
|
||||
}
|
||||
PointType::CubicTo => {
|
||||
ix += 1;
|
||||
let mid_pt = &this_contour[ix];
|
||||
ix += 1;
|
||||
let end_pt = &this_contour[ix];
|
||||
path.curve_to(
|
||||
(point.x as f64, point.y as f64),
|
||||
(mid_pt.x as f64, mid_pt.y as f64),
|
||||
(end_pt.x as f64, end_pt.y as f64),
|
||||
);
|
||||
}
|
||||
}
|
||||
ix += 1;
|
||||
}
|
||||
path.close_path();
|
||||
results.push(path);
|
||||
}
|
||||
results
|
||||
}
|
||||
}
|
||||
|
||||
/// An opaque reference to a font face, equivalent to the `hb_face_t` pointer
|
||||
/// in Harfbuzz.
|
||||
///
|
||||
/// This is generally returned from [`Font::get_face`].
|
||||
#[derive(Debug)]
|
||||
pub struct Face(u32);
|
||||
|
||||
impl Face {
|
||||
/// Get a blob containing the contents of the given binary font table.
|
||||
pub fn reference_table(&self, tag: &str) -> Blob {
|
||||
let mut tag_u: u32 = 0;
|
||||
let mut chars = tag.chars();
|
||||
tag_u |= (chars.next().unwrap() as u32) << 24;
|
||||
tag_u |= (chars.next().unwrap() as u32) << 16;
|
||||
tag_u |= (chars.next().unwrap() as u32) << 8;
|
||||
tag_u |= chars.next().unwrap() as u32;
|
||||
let mut blob = Blob {
|
||||
data: std::ptr::null_mut(),
|
||||
length: 0,
|
||||
};
|
||||
unsafe {
|
||||
face_copy_table(self.0, tag_u, &mut blob);
|
||||
}
|
||||
blob
|
||||
}
|
||||
|
||||
/// Get the face's design units per em.
|
||||
pub fn get_upem(&self) -> u32 {
|
||||
unsafe { face_get_upem(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait implemented by custom structs representing buffer items
|
||||
pub trait BufferItem {
|
||||
/// Construct an item in your preferred representation out of the info and position data provided by Harfbuzz.
|
||||
fn from_c(info: CGlyphInfo, position: CGlyphPosition) -> Self;
|
||||
/// Return info and position data to Harfbuzz.
|
||||
fn to_c(self) -> (CGlyphInfo, CGlyphPosition);
|
||||
}
|
||||
|
||||
/// Generic representation of a Harfbuzz buffer item.
|
||||
///
|
||||
/// By making this generic, we allow you to implement your own
|
||||
/// representations of buffer items; for example, in your shaper,
|
||||
/// you may want certain fields to keep track of the glyph's name,
|
||||
/// extents, or shape, so you would want a custom struct to represent
|
||||
/// buffer items. If you don't care about any of them, use the
|
||||
/// supplied `GlyphBuffer` struct.
|
||||
#[derive(Debug)]
|
||||
pub struct Buffer<T: BufferItem> {
|
||||
_ptr: u32,
|
||||
/// Glyphs in the buffer
|
||||
pub glyphs: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: BufferItem> Buffer<T> {
|
||||
/// Construct a buffer from the pointer Harfbuzz provides to the WASM.
|
||||
///
|
||||
/// The `Buffer` struct implements Drop, meaning that when the shaping
|
||||
/// function is finished, the buffer contents are sent back to Harfbuzz.
|
||||
pub fn from_ref(ptr: u32) -> Self {
|
||||
let mut c_contents = CBufferContents {
|
||||
info: std::ptr::null_mut(),
|
||||
position: std::ptr::null_mut(),
|
||||
length: 0,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
buffer_copy_contents(ptr, &mut c_contents) || panic!("Couldn't copy buffer contents")
|
||||
};
|
||||
let positions: Vec<CGlyphPosition> = unsafe {
|
||||
std::slice::from_raw_parts(c_contents.position, c_contents.length as usize).to_vec()
|
||||
};
|
||||
let infos: Vec<CGlyphInfo> = unsafe {
|
||||
std::slice::from_raw_parts(c_contents.info, c_contents.length as usize).to_vec()
|
||||
};
|
||||
Buffer {
|
||||
glyphs: infos
|
||||
.into_iter()
|
||||
.zip(positions.into_iter())
|
||||
.map(|(i, p)| T::from_c(i, p))
|
||||
.collect(),
|
||||
_ptr: ptr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: BufferItem> Drop for Buffer<T> {
|
||||
fn drop(&mut self) {
|
||||
let mut positions: Vec<CGlyphPosition>;
|
||||
let mut infos: Vec<CGlyphInfo>;
|
||||
let glyphs = std::mem::take(&mut self.glyphs);
|
||||
(infos, positions) = glyphs.into_iter().map(|g| g.to_c()).unzip();
|
||||
let c_contents = CBufferContents {
|
||||
length: positions.len() as u32,
|
||||
info: infos[..].as_mut_ptr(),
|
||||
position: positions[..].as_mut_ptr(),
|
||||
};
|
||||
unsafe {
|
||||
if !buffer_set_contents(self._ptr, &c_contents) {
|
||||
panic!("Couldn't set buffer contents");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Some data provided by Harfbuzz.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Blob {
|
||||
/// Length of the blob in bytes
|
||||
pub length: u32,
|
||||
/// A raw pointer to the contents
|
||||
pub data: *mut u8,
|
||||
}
|
||||
|
||||
/// Glyph information in a buffer item provided by Harfbuzz
|
||||
///
|
||||
/// You'll only need to interact with this if you're writing
|
||||
/// your own buffer item structure.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CGlyphInfo {
|
||||
pub codepoint: u32,
|
||||
pub mask: u32,
|
||||
pub cluster: u32,
|
||||
pub var1: u32,
|
||||
pub var2: u32,
|
||||
}
|
||||
|
||||
/// Glyph positioning information in a buffer item provided by Harfbuzz
|
||||
///
|
||||
/// You'll only need to interact with this if you're writing
|
||||
/// your own buffer item structure.
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct CGlyphPosition {
|
||||
pub x_advance: i32,
|
||||
pub y_advance: i32,
|
||||
pub x_offset: i32,
|
||||
pub y_offset: i32,
|
||||
pub var: u32,
|
||||
}
|
||||
|
||||
/// Glyph extents
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[repr(C)]
|
||||
pub struct CGlyphExtents {
|
||||
/// The scaled left side bearing of the glyph
|
||||
pub x_bearing: i32,
|
||||
/// The scaled coordinate of the top of the glyph
|
||||
pub y_bearing: i32,
|
||||
/// The width of the glyph
|
||||
pub width: i32,
|
||||
/// The height of the glyph
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct CBufferContents {
|
||||
length: u32,
|
||||
info: *mut CGlyphInfo,
|
||||
position: *mut CGlyphPosition,
|
||||
}
|
||||
|
||||
/// Ergonomic representation of a Harfbuzz buffer item
|
||||
///
|
||||
/// Harfbuzz buffers are normally split into two arrays,
|
||||
/// one representing glyph information and the other
|
||||
/// representing glyph positioning. In Rust, this would
|
||||
/// require lots of zipping and unzipping, so we zip them
|
||||
/// together into a single structure for you.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Glyph {
|
||||
/// The Unicode codepoint or glyph ID of the item
|
||||
pub codepoint: u32,
|
||||
/// The index of the cluster in the input text where this came from
|
||||
pub cluster: u32,
|
||||
/// The horizontal advance of the glyph
|
||||
pub x_advance: i32,
|
||||
/// The vertical advance of the glyph
|
||||
pub y_advance: i32,
|
||||
/// The horizontal offset of the glyph
|
||||
pub x_offset: i32,
|
||||
/// The vertical offset of the glyph
|
||||
pub y_offset: i32,
|
||||
/// You can use this for whatever you like
|
||||
pub flags: u32,
|
||||
}
|
||||
impl BufferItem for Glyph {
|
||||
fn from_c(info: CGlyphInfo, pos: CGlyphPosition) -> Self {
|
||||
Self {
|
||||
codepoint: info.codepoint,
|
||||
cluster: info.cluster,
|
||||
x_advance: pos.x_advance,
|
||||
y_advance: pos.y_advance,
|
||||
x_offset: pos.x_offset,
|
||||
y_offset: pos.y_offset,
|
||||
flags: 0,
|
||||
}
|
||||
}
|
||||
fn to_c(self) -> (CGlyphInfo, CGlyphPosition) {
|
||||
let info = CGlyphInfo {
|
||||
codepoint: self.codepoint,
|
||||
cluster: self.cluster,
|
||||
mask: 0,
|
||||
var1: 0,
|
||||
var2: 0,
|
||||
};
|
||||
let pos = CGlyphPosition {
|
||||
x_advance: self.x_advance,
|
||||
y_advance: self.y_advance,
|
||||
x_offset: self.x_offset,
|
||||
y_offset: self.y_offset,
|
||||
var: 0,
|
||||
};
|
||||
(info, pos)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
#[derive(Clone, Debug)]
|
||||
enum PointType {
|
||||
MoveTo,
|
||||
LineTo,
|
||||
QuadraticTo,
|
||||
CubicTo,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug)]
|
||||
struct CGlyphOutlinePoint {
|
||||
x: f32,
|
||||
y: f32,
|
||||
pointtype: PointType,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct CGlyphOutline {
|
||||
n_points: usize,
|
||||
points: *mut CGlyphOutlinePoint,
|
||||
n_contours: usize,
|
||||
contours: *mut usize,
|
||||
}
|
||||
|
||||
/// Our default buffer item struct. See also [`Glyph`].
|
||||
pub type GlyphBuffer = Buffer<Glyph>;
|
||||
|
||||
/// Write a string to the Harfbuzz debug log.
|
||||
pub fn debug(s: &str) {
|
||||
let c_s = CString::new(s).unwrap();
|
||||
unsafe {
|
||||
debugprint(c_s.as_ptr() as *const u8);
|
||||
};
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
ADD_TABLE = ../../../addTable.py
|
||||
|
||||
all: test-fallback.wasm.ttf test-ot.wasm.ttf
|
||||
|
||||
%.wasm: %.cc ../../../hb-wasm-api.h
|
||||
clang \
|
||||
--target=wasm32-unknown-wasi \
|
||||
-Wl,--no-entry \
|
||||
-fvisibility=hidden \
|
||||
-Wl,--allow-undefined \
|
||||
-nostdlib \
|
||||
-I ../../.. \
|
||||
$< \
|
||||
-o $@
|
||||
|
||||
test-fallback.wasm.ttf: test.ttf shape-fallback.wasm $(ADD_TABLE)
|
||||
python $(ADD_TABLE) $< $@ shape-fallback.wasm
|
||||
|
||||
test-ot.wasm.ttf: test.ttf shape-ot.wasm $(ADD_TABLE)
|
||||
python $(ADD_TABLE) $< $@ shape-ot.wasm
|
||||
|
||||
clean:
|
||||
$(RM) test-fallback.wasm.ttf test-ot.wasm.ttf shape-fallback.wasm shape-ot.wasm
|
||||
|
||||
.PRECIOUS: *.wasm
|
|
@ -0,0 +1,60 @@
|
|||
#define HB_WASM_INTERFACE(ret_t, name) __attribute__((export_name(#name))) ret_t name
|
||||
|
||||
#include <hb-wasm-api.h>
|
||||
|
||||
extern "C" {
|
||||
void debugprint (const char *s);
|
||||
void debugprint1 (const char *s, int32_t);
|
||||
void debugprint2 (const char *s, int32_t, int32_t);
|
||||
}
|
||||
|
||||
bool_t
|
||||
shape (void *shape_plan,
|
||||
font_t *font,
|
||||
buffer_t *buffer,
|
||||
const feature_t *features,
|
||||
uint32_t num_features)
|
||||
{
|
||||
face_t *face = font_get_face (font);
|
||||
|
||||
blob_t blob = BLOB_INIT;
|
||||
face_copy_table (face, TAG ('c','m','a','p'), &blob);
|
||||
|
||||
debugprint1 ("cmap length", blob.length);
|
||||
|
||||
blob_free (&blob);
|
||||
|
||||
buffer_contents_t contents = BUFFER_CONTENTS_INIT;
|
||||
if (!buffer_copy_contents (buffer, &contents))
|
||||
return false;
|
||||
|
||||
debugprint1 ("buffer length", contents.length);
|
||||
|
||||
glyph_outline_t outline = GLYPH_OUTLINE_INIT;
|
||||
|
||||
for (unsigned i = 0; i < contents.length; i++)
|
||||
{
|
||||
char name[64];
|
||||
|
||||
debugprint1 ("glyph at", i);
|
||||
|
||||
font_glyph_to_string (font, contents.info[i].codepoint, name, sizeof (name));
|
||||
|
||||
debugprint (name);
|
||||
|
||||
contents.info[i].codepoint = font_get_glyph (font, contents.info[i].codepoint, 0);
|
||||
contents.pos[i].x_advance = font_get_glyph_h_advance (font, contents.info[i].codepoint);
|
||||
|
||||
font_copy_glyph_outline (font, contents.info[i].codepoint, &outline);
|
||||
debugprint1 ("num outline points", outline.n_points);
|
||||
debugprint1 ("num outline contours", outline.n_contours);
|
||||
}
|
||||
|
||||
glyph_outline_free (&outline);
|
||||
|
||||
bool_t ret = buffer_set_contents (buffer, &contents);
|
||||
|
||||
buffer_contents_free (&contents);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#define HB_WASM_INTERFACE(ret_t, name) __attribute__((export_name(#name))) ret_t name
|
||||
|
||||
#include <hb-wasm-api.h>
|
||||
|
||||
extern "C" {
|
||||
void debugprint1 (const char *s, int32_t);
|
||||
void debugprint2 (const char *s, int32_t, int32_t);
|
||||
}
|
||||
|
||||
bool_t
|
||||
shape (void *shape_plan,
|
||||
font_t *font,
|
||||
buffer_t *buffer,
|
||||
const feature_t *features,
|
||||
uint32_t num_features)
|
||||
{
|
||||
return shape_with (font, buffer, features, num_features, "ot");
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "hello-wasm"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
#externref = "0.1.0"
|
||||
wasm-bindgen = "0.2.0"
|
||||
tiny-rng = "0.2.0"
|
||||
harfbuzz-wasm = { path="../../../rust/harfbuzz-wasm"}
|
|
@ -0,0 +1,24 @@
|
|||
use harfbuzz_wasm::{Font, GlyphBuffer};
|
||||
use tiny_rng::{Rand, Rng};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn shape(
|
||||
_shape_plan: u32,
|
||||
font_ref: u32,
|
||||
buf_ref: u32,
|
||||
_features: u32,
|
||||
_num_features: u32,
|
||||
) -> i32 {
|
||||
let mut rng = Rng::from_seed(123456);
|
||||
let font = Font::from_ref(font_ref);
|
||||
font.shape_with(buf_ref, "ot");
|
||||
let mut buffer = GlyphBuffer::from_ref(buf_ref);
|
||||
for mut item in buffer.glyphs.iter_mut() {
|
||||
// Randomize it!
|
||||
item.x_offset = ((rng.rand_u32() as i32) >> 24) - 120;
|
||||
item.y_offset = ((rng.rand_u32() as i32) >> 24) - 120;
|
||||
}
|
||||
// Buffer is written back to HB on drop
|
||||
1
|
||||
}
|
Binary file not shown.
|
@ -44,7 +44,6 @@ EXTRA_DIST += \
|
|||
expected/layout.duplicate_features \
|
||||
expected/layout.unsorted_featurelist \
|
||||
expected/layout.drop_feature \
|
||||
expected/no_layout_closure \
|
||||
expected/cmap \
|
||||
expected/cmap14 \
|
||||
expected/sbix \
|
||||
|
@ -71,7 +70,6 @@ EXTRA_DIST += \
|
|||
expected/apply_cvar_delta \
|
||||
expected/collect_name_ids \
|
||||
expected/instantiate_colrv1 \
|
||||
expected/instantiate_cff2_update_metrics \
|
||||
fonts \
|
||||
profiles \
|
||||
$(NULL)
|
||||
|
|
|
@ -43,7 +43,6 @@ TESTS = \
|
|||
tests/layout.duplicate_features.tests \
|
||||
tests/layout.unsorted_featurelist.tests \
|
||||
tests/layout.drop_feature.tests \
|
||||
tests/no_layout_closure.tests \
|
||||
tests/sbix.tests \
|
||||
tests/variable.tests \
|
||||
tests/glyph_names.tests \
|
||||
|
@ -62,7 +61,6 @@ TESTS = \
|
|||
tests/apply_cvar_delta.tests \
|
||||
tests/collect_name_ids.tests \
|
||||
tests/instantiate_colrv1.tests \
|
||||
tests/instantiate_cff2_update_metrics.tests \
|
||||
$(NULL)
|
||||
|
||||
# TODO: re-enable once colrv1 subsetting is stabilized.
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,2 +0,0 @@
|
|||
--no-layout-closure
|
||||
--gids=74,77,446
|
|
@ -1,3 +0,0 @@
|
|||
--no-layout-closure
|
||||
--gids=74,87,88,443,448
|
||||
--layout-features+=dlig
|
|
@ -1,15 +0,0 @@
|
|||
FONTS:
|
||||
Cantarell-VF-ABC.otf
|
||||
|
||||
PROFILES:
|
||||
default.txt
|
||||
retain-gids.txt
|
||||
|
||||
SUBSETS:
|
||||
*
|
||||
|
||||
INSTANCES:
|
||||
wght=800
|
||||
|
||||
OPTIONS:
|
||||
no_fonttools
|
|
@ -1,9 +0,0 @@
|
|||
FONTS:
|
||||
Roboto-Regular.ttf
|
||||
|
||||
PROFILES:
|
||||
no-layout-closure-gids.txt
|
||||
no-layout-closure-gids2.txt
|
||||
|
||||
SUBSETS:
|
||||
no-unicodes
|
|
@ -47,10 +47,8 @@ def generate_expected_output(input_file, unicodes, profile_flags, instance_flags
|
|||
args.extend(["--drop-tables+=DSIG",
|
||||
"--drop-tables-=sbix",
|
||||
"--no-harfbuzz-repacker", # disable harfbuzz repacker so we aren't comparing to ourself.
|
||||
"--unicodes=%s" % unicodes,
|
||||
"--output-file=%s" % fonttools_path])
|
||||
if unicodes != "":
|
||||
args.extend(["--unicodes=%s" % unicodes,])
|
||||
|
||||
args.extend(profile_flags)
|
||||
if not no_fonttools:
|
||||
check_call(args)
|
||||
|
@ -65,10 +63,9 @@ def generate_expected_output(input_file, unicodes, profile_flags, instance_flags
|
|||
hb_subset,
|
||||
"--font-file=" + input_file,
|
||||
"--output-file=" + harfbuzz_path,
|
||||
"--unicodes=%s" % unicodes,
|
||||
"--drop-tables+=DSIG",
|
||||
"--drop-tables-=sbix"]
|
||||
if unicodes != "":
|
||||
args.extend(["--unicodes=%s" % unicodes,])
|
||||
args.extend(profile_flags)
|
||||
if instance_flags:
|
||||
args.extend(["--instance=%s" % ','.join(instance_flags)])
|
||||
|
|
|
@ -34,7 +34,6 @@ tests = [
|
|||
'layout.duplicate_features',
|
||||
'layout.unsorted_featurelist',
|
||||
'layout.drop_feature',
|
||||
'no_layout_closure',
|
||||
'cmap',
|
||||
'cmap14',
|
||||
'sbix',
|
||||
|
@ -64,7 +63,6 @@ tests = [
|
|||
'apply_cvar_delta',
|
||||
'collect_name_ids',
|
||||
'instantiate_colrv1',
|
||||
'instantiate_cff2_update_metrics',
|
||||
]
|
||||
|
||||
repack_tests = [
|
||||
|
|
|
@ -16,8 +16,6 @@ class Test:
|
|||
import re
|
||||
if self.subset == '*':
|
||||
return self.subset[0]
|
||||
elif self.subset == "no-unicodes":
|
||||
return ""
|
||||
elif re.match("^U\+", self.subset):
|
||||
s = re.sub (r"U\+", "", self.subset)
|
||||
return s
|
||||
|
@ -51,11 +49,6 @@ class Test:
|
|||
profile_name,
|
||||
self.instance_name(),
|
||||
font_base_name_parts[1])
|
||||
elif self.unicodes() == "":
|
||||
return "%s.%s.no-unicodes%s%s" % (font_base_name_parts[0],
|
||||
profile_name,
|
||||
self.instance_name(),
|
||||
font_base_name_parts[1])
|
||||
else:
|
||||
return "%s.%s.%s%s%s" % (font_base_name_parts[0],
|
||||
profile_name,
|
||||
|
|
|
@ -941,7 +941,6 @@ subset_main_t::add_options ()
|
|||
{"set-overlaps-flag", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG>, "Set the overlaps flag on each glyph.", nullptr},
|
||||
{"notdef-outline", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NOTDEF_OUTLINE>, "Keep the outline of \'.notdef\' glyph", nullptr},
|
||||
{"no-prune-unicode-ranges", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES>, "Don't change the 'OS/2 ulUnicodeRange*' bits.", nullptr},
|
||||
{"no-layout-closure", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE>, "Don't perform glyph closure for layout substitution (GSUB).", nullptr},
|
||||
{"glyph-names", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_GLYPH_NAMES>, "Keep PS glyph names in TT-flavored fonts. ", nullptr},
|
||||
{"passthrough-tables", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED>, "Do not drop tables that the tool does not know how to subset.", nullptr},
|
||||
{"preprocess-face", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &this->preprocess,
|
||||
|
|
Loading…
Reference in New Issue