xref: /aosp_15_r20/external/harfbuzz_ng/docs/wasm-shaper.md (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker# The web assembly shaper
2*2d1272b8SAndroid Build Coastguard Worker
3*2d1272b8SAndroid Build Coastguard WorkerIf 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.
4*2d1272b8SAndroid Build Coastguard Worker
5*2d1272b8SAndroid Build Coastguard Worker## What you can and can't do: the WASM shaper's role in shaping
6*2d1272b8SAndroid Build Coastguard Worker
7*2d1272b8SAndroid Build Coastguard WorkerThe Harfbuzz shaping engine, unlike its counterparts CoreText and DirectWrite, is only responsible for a small part of the text rendering process. Specifically, Harfbuzz is purely responsible for *shaping*; although Harfbuzz does have APIs for accessing glyph outlines, typically other libraries in the free software text rendering stack are responsible for text segmentation into runs, outline scaling and rasterizing, setting text on lines, and so on.
8*2d1272b8SAndroid Build Coastguard Worker
9*2d1272b8SAndroid Build Coastguard WorkerHarfbuzz is therefore restricted to turning a buffer of codepoints for a segmented run of the same script, language, font, and variation settings, into glyphs and positioning them. This is also all that you can do with the WASM shaper; you can influence the process of mapping a string of characters into an array of glyphs, you can determine how those glyphs are positioned and their advance widths, but you cannot manipulate outlines, variations, line breaks, or affect text layout between texts of different font, variation, language, script or OpenType feature selection.
10*2d1272b8SAndroid Build Coastguard Worker
11*2d1272b8SAndroid Build Coastguard Worker## The WASM shaper interface
12*2d1272b8SAndroid Build Coastguard Worker
13*2d1272b8SAndroid Build Coastguard WorkerThe WASM code inside a font is expected to export a function called `shape` which takes five int32 arguments and returns an int32 status value. (Zero for failure, any other value for success.) Three of the five arguments are tokens which can be passed to the API functions exported to your WASM code by the host shaping engine:
14*2d1272b8SAndroid Build Coastguard Worker
15*2d1272b8SAndroid Build Coastguard Worker* A *shape plan* token, which can largely be ignored.
16*2d1272b8SAndroid Build Coastguard Worker* A *font* token.
17*2d1272b8SAndroid Build Coastguard Worker* A *buffer* token.
18*2d1272b8SAndroid Build Coastguard Worker* A *feature* array.
19*2d1272b8SAndroid Build Coastguard Worker* The number of features.
20*2d1272b8SAndroid Build Coastguard Worker
21*2d1272b8SAndroid Build Coastguard WorkerThe general goal of WASM shaping involves receiving and manipulating a *buffer contents* structure, which is an array of *infos* and *positions* (as defined below). Initially this buffer will represent an input string in Unicode codepoints. By the end of your `shape` function, it should represent a set of glyph IDs and their positions. (User-supplied WASM code will manipulate the buffer through *buffer tokens*; the `buffer_copy_contents` and `buffer_set_contents` API functions, defined below, use these tokens to exchange buffer information with the host shaping engine.)
22*2d1272b8SAndroid Build Coastguard Worker
23*2d1272b8SAndroid Build Coastguard Worker* The `buffer_contents_t` structure
24*2d1272b8SAndroid Build Coastguard Worker
25*2d1272b8SAndroid Build Coastguard Worker| type | field | description|
26*2d1272b8SAndroid Build Coastguard Worker| - | - | - |
27*2d1272b8SAndroid Build Coastguard Worker| uint32 | length | Number of items (characters or glyphs) in the buffer
28*2d1272b8SAndroid Build Coastguard Worker| glyph_info_t | infos | An array of `length` glyph infos |
29*2d1272b8SAndroid Build Coastguard Worker| glyph_position_t | positions | An array of `length` glyph positions |
30*2d1272b8SAndroid Build Coastguard Worker
31*2d1272b8SAndroid Build Coastguard Worker* The `glyph_info_t` structure
32*2d1272b8SAndroid Build Coastguard Worker
33*2d1272b8SAndroid Build Coastguard Worker| type | field | description|
34*2d1272b8SAndroid Build Coastguard Worker| - | - | - |
35*2d1272b8SAndroid Build Coastguard Worker| uint32 | codepoint | (On input) A Unicode codepoint. (On output) A glyph ID. |
36*2d1272b8SAndroid Build Coastguard Worker| uint32 | mask | Unused in WASM; can be user-defined |
37*2d1272b8SAndroid Build Coastguard Worker| uint32 | cluster | Index of start of this graphical cluster in input string |
38*2d1272b8SAndroid Build Coastguard Worker| uint32 | var1 | Reserved |
39*2d1272b8SAndroid Build Coastguard Worker| uint32 | var2 | Reserved |
40*2d1272b8SAndroid Build Coastguard Worker
41*2d1272b8SAndroid Build Coastguard WorkerThe `cluster` field is used to glyphs in the output glyph stream back to characters in the input Unicode sequence for hit testing, cursor positioning, etc. It must be set to a monotonically increasing value across the buffer.
42*2d1272b8SAndroid Build Coastguard Worker
43*2d1272b8SAndroid Build Coastguard Worker* The `glyph_position_t` structure
44*2d1272b8SAndroid Build Coastguard Worker
45*2d1272b8SAndroid Build Coastguard Worker| type | field | description|
46*2d1272b8SAndroid Build Coastguard Worker| - | - | - |
47*2d1272b8SAndroid Build Coastguard Worker| int32 | x_advance | X advance of the glyph |
48*2d1272b8SAndroid Build Coastguard Worker| int32 | y_advance | Y advance of the glyph |
49*2d1272b8SAndroid Build Coastguard Worker| int32 | x_offset | X offset of the glyph |
50*2d1272b8SAndroid Build Coastguard Worker| int32 | y_offset | Y offset of the glyph |
51*2d1272b8SAndroid Build Coastguard Worker| uint32 | var | Reserved |
52*2d1272b8SAndroid Build Coastguard Worker
53*2d1272b8SAndroid Build Coastguard Worker* The `feature_t` array
54*2d1272b8SAndroid Build Coastguard Worker
55*2d1272b8SAndroid Build Coastguard WorkerTo communicate user-selected OpenType features to the user-defined WASM shaper, the host shaping engine passes an array of feature structures:
56*2d1272b8SAndroid Build Coastguard Worker
57*2d1272b8SAndroid Build Coastguard Worker| type | field | description|
58*2d1272b8SAndroid Build Coastguard Worker| - | - | - |
59*2d1272b8SAndroid Build Coastguard Worker| uint32 | tag | Byte-encoded feature tag |
60*2d1272b8SAndroid Build Coastguard Worker| uint32 | value | Value: 0=off, 1=on, other values used for alternate selection |
61*2d1272b8SAndroid Build Coastguard Worker| uint32 | start | Index into the input string representing start of the active region for this feature selection (0=start of string) |
62*2d1272b8SAndroid Build Coastguard Worker| uint32 | end | Index into the input string representing end of the active region for this feature selection (-1=end of string) |
63*2d1272b8SAndroid Build Coastguard Worker
64*2d1272b8SAndroid Build Coastguard Worker## API functions available
65*2d1272b8SAndroid Build Coastguard Worker
66*2d1272b8SAndroid Build Coastguard WorkerTo assist the shaping code in mapping codepoints to glyphs, the WASM shaper exports the following functions. Note that these are the low level API functions; WASM authors may prefer to use higher-level abstractions around these functions, such as the `harfbuzz-wasm` Rust crate provided by Harfbuzz.
67*2d1272b8SAndroid Build Coastguard Worker
68*2d1272b8SAndroid Build Coastguard Worker### Sub-shaping
69*2d1272b8SAndroid Build Coastguard Worker
70*2d1272b8SAndroid Build Coastguard Worker* `shape_with`
71*2d1272b8SAndroid Build Coastguard Worker
72*2d1272b8SAndroid Build Coastguard Worker```C
73*2d1272b8SAndroid Build Coastguard Workerbool shape_with(
74*2d1272b8SAndroid Build Coastguard Worker    uint32 font_token,
75*2d1272b8SAndroid Build Coastguard Worker    uint32 buffer_token,
76*2d1272b8SAndroid Build Coastguard Worker    feature_t* features,
77*2d1272b8SAndroid Build Coastguard Worker    uint32 num_features,
78*2d1272b8SAndroid Build Coastguard Worker    char* shaper
79*2d1272b8SAndroid Build Coastguard Worker)
80*2d1272b8SAndroid Build Coastguard Worker```
81*2d1272b8SAndroid Build Coastguard Worker
82*2d1272b8SAndroid Build Coastguard WorkerRun another shaping engine's shaping process on the given font and buffer. The only shaping engine guaranteed to be available is `ot`, the OpenType shaper, but others may also be available. This allows the WASM author to process a buffer "normally", before further manipulating it.
83*2d1272b8SAndroid Build Coastguard Worker
84*2d1272b8SAndroid Build Coastguard Worker### Buffer access
85*2d1272b8SAndroid Build Coastguard Worker
86*2d1272b8SAndroid Build Coastguard Worker* `buffer_copy_contents`
87*2d1272b8SAndroid Build Coastguard Worker
88*2d1272b8SAndroid Build Coastguard Worker```C
89*2d1272b8SAndroid Build Coastguard Workerbool buffer_copy_contents(
90*2d1272b8SAndroid Build Coastguard Worker    uint32 buffer_token,
91*2d1272b8SAndroid Build Coastguard Worker    buffer_contents_t* buffer_contents
92*2d1272b8SAndroid Build Coastguard Worker)
93*2d1272b8SAndroid Build Coastguard Worker```
94*2d1272b8SAndroid Build Coastguard Worker
95*2d1272b8SAndroid Build Coastguard WorkerRetrieves the contents of the host shaping engine's buffer into the `buffer_contents` structure. This should typically be called at the beginning of shaping.
96*2d1272b8SAndroid Build Coastguard Worker
97*2d1272b8SAndroid Build Coastguard Worker* `buffer_set_contents`
98*2d1272b8SAndroid Build Coastguard Worker
99*2d1272b8SAndroid Build Coastguard Worker```C
100*2d1272b8SAndroid Build Coastguard Workerbool buffer_set_contents(
101*2d1272b8SAndroid Build Coastguard Worker    uint32 buffer_token,
102*2d1272b8SAndroid Build Coastguard Worker    buffer_contents_t* buffer_contents
103*2d1272b8SAndroid Build Coastguard Worker)
104*2d1272b8SAndroid Build Coastguard Worker```
105*2d1272b8SAndroid Build Coastguard Worker
106*2d1272b8SAndroid Build Coastguard WorkerCopy the `buffer_contents` structure back into the host shaping engine's buffer. This should typically be called at the end of shaping.
107*2d1272b8SAndroid Build Coastguard Worker
108*2d1272b8SAndroid Build Coastguard Worker* `buffer_contents_free`
109*2d1272b8SAndroid Build Coastguard Worker
110*2d1272b8SAndroid Build Coastguard Worker```C
111*2d1272b8SAndroid Build Coastguard Workerbool buffer_contents_free(buffer_contents_t* buffer_contents)
112*2d1272b8SAndroid Build Coastguard Worker```
113*2d1272b8SAndroid Build Coastguard Worker
114*2d1272b8SAndroid Build Coastguard WorkerReleases the memory taken up by the buffer contents structure.
115*2d1272b8SAndroid Build Coastguard Worker
116*2d1272b8SAndroid Build Coastguard Worker* `buffer_contents_realloc`
117*2d1272b8SAndroid Build Coastguard Worker
118*2d1272b8SAndroid Build Coastguard Worker```C
119*2d1272b8SAndroid Build Coastguard Workerbool buffer_contents_realloc(
120*2d1272b8SAndroid Build Coastguard Worker    buffer_contents_t* buffer_contents,
121*2d1272b8SAndroid Build Coastguard Worker    uint32 size
122*2d1272b8SAndroid Build Coastguard Worker)
123*2d1272b8SAndroid Build Coastguard Worker```
124*2d1272b8SAndroid Build Coastguard Worker
125*2d1272b8SAndroid Build Coastguard WorkerRequests that the buffer contents structure be resized to the given size.
126*2d1272b8SAndroid Build Coastguard Worker
127*2d1272b8SAndroid Build Coastguard Worker* `buffer_get_direction`
128*2d1272b8SAndroid Build Coastguard Worker
129*2d1272b8SAndroid Build Coastguard Worker```C
130*2d1272b8SAndroid Build Coastguard Workeruint32 buffer_get_direction(uint32 buffer_token)
131*2d1272b8SAndroid Build Coastguard Worker```
132*2d1272b8SAndroid Build Coastguard Worker
133*2d1272b8SAndroid Build Coastguard WorkerReturns the buffer's direction:
134*2d1272b8SAndroid Build Coastguard Worker
135*2d1272b8SAndroid Build Coastguard Worker* 0 = invalid
136*2d1272b8SAndroid Build Coastguard Worker* 4 = left to right
137*2d1272b8SAndroid Build Coastguard Worker* 5 = right to left
138*2d1272b8SAndroid Build Coastguard Worker* 6 = top to bottom
139*2d1272b8SAndroid Build Coastguard Worker* 7 = bottom to top
140*2d1272b8SAndroid Build Coastguard Worker
141*2d1272b8SAndroid Build Coastguard Worker* `buffer_get_script`
142*2d1272b8SAndroid Build Coastguard Worker
143*2d1272b8SAndroid Build Coastguard Worker```C
144*2d1272b8SAndroid Build Coastguard Workeruint32 buffer_get_script(uint32 buffer_token)
145*2d1272b8SAndroid Build Coastguard Worker```
146*2d1272b8SAndroid Build Coastguard Worker
147*2d1272b8SAndroid Build Coastguard WorkerReturns the byte-encoded OpenType script tag of the buffer.
148*2d1272b8SAndroid Build Coastguard Worker
149*2d1272b8SAndroid Build Coastguard Worker* `buffer_reverse`
150*2d1272b8SAndroid Build Coastguard Worker
151*2d1272b8SAndroid Build Coastguard Worker```C
152*2d1272b8SAndroid Build Coastguard Workervoid buffer_reverse(uint32 buffer_token)
153*2d1272b8SAndroid Build Coastguard Worker```
154*2d1272b8SAndroid Build Coastguard Worker
155*2d1272b8SAndroid Build Coastguard WorkerReverses the order of items in the buffer.
156*2d1272b8SAndroid Build Coastguard Worker
157*2d1272b8SAndroid Build Coastguard Worker* `buffer_reverse_clusters`
158*2d1272b8SAndroid Build Coastguard Worker
159*2d1272b8SAndroid Build Coastguard Worker```C
160*2d1272b8SAndroid Build Coastguard Workervoid buffer_reverse_clusters(uint32 buffer_token)
161*2d1272b8SAndroid Build Coastguard Worker```
162*2d1272b8SAndroid Build Coastguard Worker
163*2d1272b8SAndroid Build Coastguard WorkerReverses the order of items in the buffer while keeping items of the same cluster together.
164*2d1272b8SAndroid Build Coastguard Worker
165*2d1272b8SAndroid Build Coastguard Worker## Font handling functions
166*2d1272b8SAndroid Build Coastguard Worker
167*2d1272b8SAndroid Build Coastguard Worker(In the following functions, a *font* is a specific instantiation of a *face* at a particular scale factor and variation position.)
168*2d1272b8SAndroid Build Coastguard Worker
169*2d1272b8SAndroid Build Coastguard Worker* `font_create`
170*2d1272b8SAndroid Build Coastguard Worker
171*2d1272b8SAndroid Build Coastguard Worker```C
172*2d1272b8SAndroid Build Coastguard Workeruint32 font_create(uint32 face_token)
173*2d1272b8SAndroid Build Coastguard Worker```
174*2d1272b8SAndroid Build Coastguard Worker
175*2d1272b8SAndroid Build Coastguard WorkerReturns a new *font token* from the given *face token*.
176*2d1272b8SAndroid Build Coastguard Worker
177*2d1272b8SAndroid Build Coastguard Worker* `font_get_face`
178*2d1272b8SAndroid Build Coastguard Worker
179*2d1272b8SAndroid Build Coastguard Worker```C
180*2d1272b8SAndroid Build Coastguard Workeruint32 font_get_face(uint32 font_token)
181*2d1272b8SAndroid Build Coastguard Worker```
182*2d1272b8SAndroid Build Coastguard Worker
183*2d1272b8SAndroid Build Coastguard WorkerCreates a new *face token* from the given *font token*.
184*2d1272b8SAndroid Build Coastguard Worker
185*2d1272b8SAndroid Build Coastguard Worker* `font_get_scale`
186*2d1272b8SAndroid Build Coastguard Worker
187*2d1272b8SAndroid Build Coastguard Worker```C
188*2d1272b8SAndroid Build Coastguard Workervoid font_get_scale(
189*2d1272b8SAndroid Build Coastguard Worker    uint32 font_token,
190*2d1272b8SAndroid Build Coastguard Worker    int32* x_scale,
191*2d1272b8SAndroid Build Coastguard Worker    int32* y_scale
192*2d1272b8SAndroid Build Coastguard Worker)
193*2d1272b8SAndroid Build Coastguard Worker```
194*2d1272b8SAndroid Build Coastguard Worker
195*2d1272b8SAndroid Build Coastguard WorkerReturns the scale of the current font.
196*2d1272b8SAndroid Build Coastguard Worker
197*2d1272b8SAndroid Build Coastguard Worker* `font_get_glyph`
198*2d1272b8SAndroid Build Coastguard Worker
199*2d1272b8SAndroid Build Coastguard Worker```C
200*2d1272b8SAndroid Build Coastguard Workeruint32 font_get_glyph(
201*2d1272b8SAndroid Build Coastguard Worker    uint32 font_token,
202*2d1272b8SAndroid Build Coastguard Worker    uint32 codepoint,
203*2d1272b8SAndroid Build Coastguard Worker    uint32 variation_selector
204*2d1272b8SAndroid Build Coastguard Worker)
205*2d1272b8SAndroid Build Coastguard Worker```
206*2d1272b8SAndroid Build Coastguard Worker
207*2d1272b8SAndroid Build Coastguard WorkerReturns the nominal glyph ID for the given codepoint, using the `cmap` table of the font to map Unicode codepoint (and variation selector) to glyph ID.
208*2d1272b8SAndroid Build Coastguard Worker
209*2d1272b8SAndroid Build Coastguard Worker* `font_get_glyph_h_advance`/`font_get_glyph_v_advance`
210*2d1272b8SAndroid Build Coastguard Worker
211*2d1272b8SAndroid Build Coastguard Worker```C
212*2d1272b8SAndroid Build Coastguard Workeruint32 font_get_glyph_h_advance(uint32 font_token, uint32 glyph_id)
213*2d1272b8SAndroid Build Coastguard Workeruint32 font_get_glyph_v_advance(uint32 font_token, uint32 glyph_id)
214*2d1272b8SAndroid Build Coastguard Worker```
215*2d1272b8SAndroid Build Coastguard Worker
216*2d1272b8SAndroid Build Coastguard WorkerReturns the default horizontal and vertical advance respectively for the given glyph ID the current scale and variations settings.
217*2d1272b8SAndroid Build Coastguard Worker
218*2d1272b8SAndroid Build Coastguard Worker* `font_get_glyph_extents`
219*2d1272b8SAndroid Build Coastguard Worker
220*2d1272b8SAndroid Build Coastguard Worker```C
221*2d1272b8SAndroid Build Coastguard Workertypedef struct
222*2d1272b8SAndroid Build Coastguard Worker{
223*2d1272b8SAndroid Build Coastguard Worker  uint32 x_bearing;
224*2d1272b8SAndroid Build Coastguard Worker  uint32 y_bearing;
225*2d1272b8SAndroid Build Coastguard Worker  uint32 width;
226*2d1272b8SAndroid Build Coastguard Worker  uint32 height;
227*2d1272b8SAndroid Build Coastguard Worker} glyph_extents_t;
228*2d1272b8SAndroid Build Coastguard Worker
229*2d1272b8SAndroid Build Coastguard Workerbool font_get_glyph_extents(
230*2d1272b8SAndroid Build Coastguard Worker    uint32 font_token,
231*2d1272b8SAndroid Build Coastguard Worker    uint32 glyph_id,
232*2d1272b8SAndroid Build Coastguard Worker    glyph_extents_t* extents
233*2d1272b8SAndroid Build Coastguard Worker)
234*2d1272b8SAndroid Build Coastguard Worker```
235*2d1272b8SAndroid Build Coastguard Worker
236*2d1272b8SAndroid Build Coastguard WorkerReturns the glyph's extents for the given glyph ID at current scale and variation settings.
237*2d1272b8SAndroid Build Coastguard Worker
238*2d1272b8SAndroid Build Coastguard Worker* `font_glyph_to_string`
239*2d1272b8SAndroid Build Coastguard Worker
240*2d1272b8SAndroid Build Coastguard Worker```C
241*2d1272b8SAndroid Build Coastguard Workervoid font_glyph_to_string(
242*2d1272b8SAndroid Build Coastguard Worker    uint32 font_token,
243*2d1272b8SAndroid Build Coastguard Worker    uint32 glyph_id,
244*2d1272b8SAndroid Build Coastguard Worker    char* string,
245*2d1272b8SAndroid Build Coastguard Worker    uint32 size
246*2d1272b8SAndroid Build Coastguard Worker)
247*2d1272b8SAndroid Build Coastguard Worker```
248*2d1272b8SAndroid Build Coastguard Worker
249*2d1272b8SAndroid Build Coastguard WorkerCopies the name of the given glyph, or, if no name is available, a string of the form `gXXXX` into the given string.
250*2d1272b8SAndroid Build Coastguard Worker
251*2d1272b8SAndroid Build Coastguard Worker* `font_copy_glyph_outline`
252*2d1272b8SAndroid Build Coastguard Worker
253*2d1272b8SAndroid Build Coastguard Worker```C
254*2d1272b8SAndroid Build Coastguard Workertypedef struct
255*2d1272b8SAndroid Build Coastguard Worker{
256*2d1272b8SAndroid Build Coastguard Worker  float x;
257*2d1272b8SAndroid Build Coastguard Worker  float y;
258*2d1272b8SAndroid Build Coastguard Worker  uint32_t type;
259*2d1272b8SAndroid Build Coastguard Worker} glyph_outline_point_t;
260*2d1272b8SAndroid Build Coastguard Worker
261*2d1272b8SAndroid Build Coastguard Workertypedef struct
262*2d1272b8SAndroid Build Coastguard Worker{
263*2d1272b8SAndroid Build Coastguard Worker  uint32_t n_points;
264*2d1272b8SAndroid Build Coastguard Worker  glyph_outline_point_t* points;
265*2d1272b8SAndroid Build Coastguard Worker  uint32_t n_contours;
266*2d1272b8SAndroid Build Coastguard Worker  uint32_t* contours;
267*2d1272b8SAndroid Build Coastguard Worker} glyph_outline_t;
268*2d1272b8SAndroid Build Coastguard Worker
269*2d1272b8SAndroid Build Coastguard Workerbool font_copy_glyph_outline(
270*2d1272b8SAndroid Build Coastguard Worker    uint32 font_token,
271*2d1272b8SAndroid Build Coastguard Worker    uint32 glyph_id,
272*2d1272b8SAndroid Build Coastguard Worker    glyph_outline_t* outline
273*2d1272b8SAndroid Build Coastguard Worker);
274*2d1272b8SAndroid Build Coastguard Worker```
275*2d1272b8SAndroid Build Coastguard Worker
276*2d1272b8SAndroid Build Coastguard WorkerCopies the outline of the given glyph ID, at current scale and variation settings, into the outline structure provided. The outline structure returns an array of points (specifying coordinates and whether the point is oncurve or offcurve) and an array of indexes into the points array representing the end of each contour, similar to the `glyf` table structure.
277*2d1272b8SAndroid Build Coastguard Worker
278*2d1272b8SAndroid Build Coastguard Worker* `font_copy_coords`/`font_set_coords`
279*2d1272b8SAndroid Build Coastguard Worker
280*2d1272b8SAndroid Build Coastguard Worker```C
281*2d1272b8SAndroid Build Coastguard Workertypedef struct
282*2d1272b8SAndroid Build Coastguard Worker{
283*2d1272b8SAndroid Build Coastguard Worker  uint32 length;
284*2d1272b8SAndroid Build Coastguard Worker  int32* coords;
285*2d1272b8SAndroid Build Coastguard Worker} coords_t;
286*2d1272b8SAndroid Build Coastguard Worker
287*2d1272b8SAndroid Build Coastguard Workerbool font_copy_coords(uint32 font_token, &coords_t coords);
288*2d1272b8SAndroid Build Coastguard Workerbool font_set_coords(uint32 font_token, &coords_t coords);
289*2d1272b8SAndroid Build Coastguard Worker```
290*2d1272b8SAndroid Build Coastguard Worker
291*2d1272b8SAndroid Build Coastguard Worker`font_copy_coords` copies the font's variation coordinates into the given structure; the resulting structure has `length` equal to the number of variation axes, with each member of the `coords` array being a F2DOT14 encoding of the normalized variation value.
292*2d1272b8SAndroid Build Coastguard Worker
293*2d1272b8SAndroid Build Coastguard Worker`font_set_coords` sets the font's variation coordinates. Because the WASM shaper is only responsible for shaping and positioning, not outline drawing, the user should *not* expect this to affect the rendered outlines; the function is only useful in very limited circumstances, such as when instantiating a second variable font and sub-shaping a buffer using this new font.
294*2d1272b8SAndroid Build Coastguard Worker
295*2d1272b8SAndroid Build Coastguard Worker## Face handling functions
296*2d1272b8SAndroid Build Coastguard Worker
297*2d1272b8SAndroid Build Coastguard Worker* `face_create`
298*2d1272b8SAndroid Build Coastguard Worker
299*2d1272b8SAndroid Build Coastguard Worker```C
300*2d1272b8SAndroid Build Coastguard Workertypedef struct
301*2d1272b8SAndroid Build Coastguard Worker{
302*2d1272b8SAndroid Build Coastguard Worker  uint32_t length;
303*2d1272b8SAndroid Build Coastguard Worker  char* data;
304*2d1272b8SAndroid Build Coastguard Worker} blob_t;
305*2d1272b8SAndroid Build Coastguard Worker
306*2d1272b8SAndroid Build Coastguard Workeruint32 font_get_face(blob_t* blob)
307*2d1272b8SAndroid Build Coastguard Worker```
308*2d1272b8SAndroid Build Coastguard Worker
309*2d1272b8SAndroid Build Coastguard WorkerCreates a new *face token* from the given binary data.
310*2d1272b8SAndroid Build Coastguard Worker
311*2d1272b8SAndroid Build Coastguard Worker* `face_copy_table`
312*2d1272b8SAndroid Build Coastguard Worker
313*2d1272b8SAndroid Build Coastguard Worker```C
314*2d1272b8SAndroid Build Coastguard Workervoid face_copy_table(uint32 face_token, uint32 tag, blob_t* blob)
315*2d1272b8SAndroid Build Coastguard Worker```
316*2d1272b8SAndroid Build Coastguard Worker
317*2d1272b8SAndroid Build Coastguard WorkerCopies the binary data in the OpenType table referenced by `tag` into the supplied `blob` structure.
318*2d1272b8SAndroid Build Coastguard Worker
319*2d1272b8SAndroid Build Coastguard Worker* `face_get_upem`
320*2d1272b8SAndroid Build Coastguard Worker
321*2d1272b8SAndroid Build Coastguard Worker```C
322*2d1272b8SAndroid Build Coastguard Workeruint32 font_get_upem(uint32 face_token)
323*2d1272b8SAndroid Build Coastguard Worker```
324*2d1272b8SAndroid Build Coastguard Worker
325*2d1272b8SAndroid Build Coastguard WorkerReturns the units-per-em of the font face.
326*2d1272b8SAndroid Build Coastguard Worker
327*2d1272b8SAndroid Build Coastguard Worker### Other functions
328*2d1272b8SAndroid Build Coastguard Worker
329*2d1272b8SAndroid Build Coastguard Worker* `blob_free`
330*2d1272b8SAndroid Build Coastguard Worker
331*2d1272b8SAndroid Build Coastguard Worker```C
332*2d1272b8SAndroid Build Coastguard Workervoid blob_free(blob_t* blob)
333*2d1272b8SAndroid Build Coastguard Worker```
334*2d1272b8SAndroid Build Coastguard Worker
335*2d1272b8SAndroid Build Coastguard WorkerFrees the memory allocated to a blob structure.
336*2d1272b8SAndroid Build Coastguard Worker
337*2d1272b8SAndroid Build Coastguard Worker* `glyph_outline_free`
338*2d1272b8SAndroid Build Coastguard Worker
339*2d1272b8SAndroid Build Coastguard Worker```C
340*2d1272b8SAndroid Build Coastguard Workervoid glyph_outline_free(glyph_outline_t* glyph_outline)
341*2d1272b8SAndroid Build Coastguard Worker```
342*2d1272b8SAndroid Build Coastguard Worker
343*2d1272b8SAndroid Build Coastguard WorkerFrees the memory allocated to a glyph outline structure.
344*2d1272b8SAndroid Build Coastguard Worker
345*2d1272b8SAndroid Build Coastguard Worker* `script_get_horizontal_direction`
346*2d1272b8SAndroid Build Coastguard Worker
347*2d1272b8SAndroid Build Coastguard Worker```C
348*2d1272b8SAndroid Build Coastguard Workeruint32 script_get_horizontal_direction(uint32 tag)
349*2d1272b8SAndroid Build Coastguard Worker```
350*2d1272b8SAndroid Build Coastguard Worker
351*2d1272b8SAndroid Build Coastguard WorkerReturns the horizontal direction for the given ISO 15924 script tag. For return values, see `buffer_get_direction` above.
352*2d1272b8SAndroid Build Coastguard Worker
353*2d1272b8SAndroid Build Coastguard Worker* `debugprint` / `debugprint1` ... `debugprint4`
354*2d1272b8SAndroid Build Coastguard Worker
355*2d1272b8SAndroid Build Coastguard Worker```C
356*2d1272b8SAndroid Build Coastguard Workervoid debugprint(char* str)
357*2d1272b8SAndroid Build Coastguard Workervoid debugprint1(char* str, int32 arg1)
358*2d1272b8SAndroid Build Coastguard Workervoid debugprint2(char* str, int32 arg1, int32 arg2)
359*2d1272b8SAndroid Build Coastguard Workervoid debugprint3(char* str, int32 arg1, int32 arg2, int32 arg3)
360*2d1272b8SAndroid Build Coastguard Workervoid debugprint4(
361*2d1272b8SAndroid Build Coastguard Worker    char* str,
362*2d1272b8SAndroid Build Coastguard Worker    int32 arg1,
363*2d1272b8SAndroid Build Coastguard Worker    int32 arg2,
364*2d1272b8SAndroid Build Coastguard Worker    int32 arg3,
365*2d1272b8SAndroid Build Coastguard Worker    int32 arg4
366*2d1272b8SAndroid Build Coastguard Worker)
367*2d1272b8SAndroid Build Coastguard Worker```
368*2d1272b8SAndroid Build Coastguard Worker
369*2d1272b8SAndroid Build Coastguard WorkerProduces a debugging message in the host shaper's log output; the variants `debugprint1` ... `debugprint4` suffix the message with a comma-separated list of the integer arguments.
370*2d1272b8SAndroid Build Coastguard Worker
371*2d1272b8SAndroid Build Coastguard Worker## Enabling the WASM shaper when building Harfbuzz
372*2d1272b8SAndroid Build Coastguard Worker
373*2d1272b8SAndroid Build Coastguard WorkerFirst, you will need the `wasm-micro-runtime` library installed on your computer. Download `wasm-micro-runtime` from [its GitHub repository](https://github.com/bytecodealliance/wasm-micro-runtime/tree/main); then follow [the instructions for building](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/product-mini/README.md), except run the cmake command from the repository root directory and add the `-DWAMR_BUILD_REF_TYPES=1` flag to the `cmake` line. (You may want to enable "fast JIT".) Then, install it.
374*2d1272b8SAndroid Build Coastguard Worker
375*2d1272b8SAndroid Build Coastguard WorkerSo, for example:
376*2d1272b8SAndroid Build Coastguard Worker
377*2d1272b8SAndroid Build Coastguard Worker```
378*2d1272b8SAndroid Build Coastguard Worker$ cmake -B build -DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_FAST_JIT=1
379*2d1272b8SAndroid Build Coastguard Worker$ cmake --build build --parallel
380*2d1272b8SAndroid Build Coastguard Worker$ sudo cmake --build build --target install
381*2d1272b8SAndroid Build Coastguard Worker```
382*2d1272b8SAndroid Build Coastguard Worker
383*2d1272b8SAndroid Build Coastguard Worker(If you don't want to install `wasm-micro-runtime` globally, you can copy `libiwasm.*` and `libvmlib.a` into a directory that your compiler can see when building Harfbuzz.)
384*2d1272b8SAndroid Build Coastguard Worker
385*2d1272b8SAndroid Build Coastguard WorkerOnce `wasm-micro-runtime` is installed, to enable the WASM shaper, you need to add the string `-Dwasm=enabled` to your meson build line. For example:
386*2d1272b8SAndroid Build Coastguard Worker
387*2d1272b8SAndroid Build Coastguard Worker```
388*2d1272b8SAndroid Build Coastguard Worker$ meson setup build -Dwasm=enabled
389*2d1272b8SAndroid Build Coastguard Worker...
390*2d1272b8SAndroid Build Coastguard Worker  Additional shapers
391*2d1272b8SAndroid Build Coastguard Worker    Graphite2                 : NO
392*2d1272b8SAndroid Build Coastguard Worker    WebAssembly (experimental): YES
393*2d1272b8SAndroid Build Coastguard Worker...
394*2d1272b8SAndroid Build Coastguard Worker$ meson compile -C build
395*2d1272b8SAndroid Build Coastguard Worker```
396*2d1272b8SAndroid Build Coastguard Worker
397*2d1272b8SAndroid Build Coastguard Worker## How to write a shaping engine in Rust
398*2d1272b8SAndroid Build Coastguard Worker
399*2d1272b8SAndroid Build Coastguard WorkerYou may write shaping engines in any language supported by WASM, by conforming to the API described above, but Rust is particularly easy, and we have one of those high-level interface wrappers which makes the process easier. Here are the steps to create an example shaping engine in Rust: (These examples can also be found in [their own reposotry](https://github.com/harfbuzz/harfbuzz-wasm-examples))
400*2d1272b8SAndroid Build Coastguard Worker
401*2d1272b8SAndroid Build Coastguard Worker* 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:
402*2d1272b8SAndroid Build Coastguard Worker
403*2d1272b8SAndroid Build Coastguard Worker```
404*2d1272b8SAndroid Build Coastguard Worker$ cargo install wasm-pack
405*2d1272b8SAndroid Build Coastguard Worker```
406*2d1272b8SAndroid Build Coastguard Worker
407*2d1272b8SAndroid Build Coastguard Worker* Now let's create a new library:
408*2d1272b8SAndroid Build Coastguard Worker
409*2d1272b8SAndroid Build Coastguard Worker```
410*2d1272b8SAndroid Build Coastguard Worker$ cargo new --lib hello-wasm
411*2d1272b8SAndroid Build Coastguard Worker```
412*2d1272b8SAndroid Build Coastguard Worker
413*2d1272b8SAndroid Build Coastguard Worker* 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:
414*2d1272b8SAndroid Build Coastguard Worker
415*2d1272b8SAndroid Build Coastguard Worker```toml
416*2d1272b8SAndroid Build Coastguard Worker[lib]
417*2d1272b8SAndroid Build Coastguard Workercrate-type = ["cdylib"]
418*2d1272b8SAndroid Build Coastguard Worker[dependencies]
419*2d1272b8SAndroid Build Coastguard Workerwasm-bindgen = "0.2"
420*2d1272b8SAndroid Build Coastguard Workerharfbuzz-wasm = { path = "your-harfbuzz-source/src/wasm/rust/harfbuzz-wasm"}
421*2d1272b8SAndroid Build Coastguard Worker```
422*2d1272b8SAndroid Build Coastguard Worker
423*2d1272b8SAndroid Build Coastguard Worker*
424*2d1272b8SAndroid Build Coastguard Worker* And now we'll create our shaper code. In `src/lib.rs`:
425*2d1272b8SAndroid Build Coastguard Worker
426*2d1272b8SAndroid Build Coastguard Worker```rust
427*2d1272b8SAndroid Build Coastguard Workeruse wasm_bindgen::prelude::*;
428*2d1272b8SAndroid Build Coastguard Worker
429*2d1272b8SAndroid Build Coastguard Worker#[wasm_bindgen]
430*2d1272b8SAndroid Build Coastguard Workerpub fn shape(_shape_plan:u32, font_ref: u32, buf_ref: u32, _features: u32, _num_features: u32) -> i32 {
431*2d1272b8SAndroid Build Coastguard Worker    1 // success!
432*2d1272b8SAndroid Build Coastguard Worker}
433*2d1272b8SAndroid Build Coastguard Worker```
434*2d1272b8SAndroid Build Coastguard Worker
435*2d1272b8SAndroid Build Coastguard WorkerThis 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:
436*2d1272b8SAndroid Build Coastguard Worker
437*2d1272b8SAndroid Build Coastguard Worker* To compile the shaper, run `wasm-pack build --target nodejs`:
438*2d1272b8SAndroid Build Coastguard Worker
439*2d1272b8SAndroid Build Coastguard Worker```
440*2d1272b8SAndroid Build Coastguard WorkerINFO]: ��  Checking for the Wasm target...
441*2d1272b8SAndroid Build Coastguard Worker[INFO]: ��  Compiling to Wasm...
442*2d1272b8SAndroid Build Coastguard Worker   Compiling hello-wasm v0.1.0 (...)
443*2d1272b8SAndroid Build Coastguard Worker    Finished release [optimized] target(s) in 0.20s
444*2d1272b8SAndroid Build Coastguard Worker[WARN]: ⚠️   origin crate has no README
445*2d1272b8SAndroid Build Coastguard Worker[INFO]: ⬇️  Installing wasm-bindgen...
446*2d1272b8SAndroid Build Coastguard Worker[INFO]: Optimizing wasm binaries with `wasm-opt`...
447*2d1272b8SAndroid Build Coastguard Worker[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended
448*2d1272b8SAndroid Build Coastguard Worker[INFO]: ✨   Done in 0.40s
449*2d1272b8SAndroid Build Coastguard Worker```
450*2d1272b8SAndroid Build Coastguard Worker
451*2d1272b8SAndroid Build Coastguard WorkerYou'll find the output WASM file in `pkg/hello_wasm_bg.wasm`
452*2d1272b8SAndroid Build Coastguard Worker
453*2d1272b8SAndroid Build Coastguard Worker* Now we need to get it into a font.
454*2d1272b8SAndroid Build Coastguard Worker
455*2d1272b8SAndroid Build Coastguard WorkerWe provide a utility to do this called `addTable.py` in the `src/` directory:
456*2d1272b8SAndroid Build Coastguard Worker
457*2d1272b8SAndroid Build Coastguard Worker```
458*2d1272b8SAndroid Build Coastguard Worker% python3 ~/harfbuzz/src/addTable.py test.ttf test-wasm.ttf pkg/hello_wasm_bg.wasm
459*2d1272b8SAndroid Build Coastguard Worker```
460*2d1272b8SAndroid Build Coastguard Worker
461*2d1272b8SAndroid Build Coastguard WorkerAnd now we can run it!
462*2d1272b8SAndroid Build Coastguard Worker
463*2d1272b8SAndroid Build Coastguard Worker```
464*2d1272b8SAndroid Build Coastguard Worker% hb-shape test-wasm.ttf abc --shapers=wasm
465*2d1272b8SAndroid Build Coastguard Worker[cent=0|sterling=1|fraction=2]
466*2d1272b8SAndroid Build Coastguard Worker```
467*2d1272b8SAndroid Build Coastguard Worker
468*2d1272b8SAndroid Build Coastguard Worker(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.)
469*2d1272b8SAndroid Build Coastguard Worker
470*2d1272b8SAndroid Build Coastguard WorkerCongratulations! Our shaper did nothing, but in Rust! Now let's do something - it's time for the Hello World of WASM shaping.
471*2d1272b8SAndroid Build Coastguard Worker
472*2d1272b8SAndroid Build Coastguard Worker* To say hello world, we're going to have to use a native function.
473*2d1272b8SAndroid Build Coastguard Worker
474*2d1272b8SAndroid Build Coastguard WorkerIn 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:
475*2d1272b8SAndroid Build Coastguard Worker
476*2d1272b8SAndroid Build Coastguard Worker```rust
477*2d1272b8SAndroid Build Coastguard Workeruse harfbuzz_wasm::debug;
478*2d1272b8SAndroid Build Coastguard Worker
479*2d1272b8SAndroid Build Coastguard Worker#[wasm_bindgen]
480*2d1272b8SAndroid Build Coastguard Workerpub fn shape(_shape_plan:u32, _font_ref: u32, _buf_ref: u32, _features: u32, _num_features: u32) -> i32 {
481*2d1272b8SAndroid Build Coastguard Worker    debug("Hello from Rust!\n");
482*2d1272b8SAndroid Build Coastguard Worker    1
483*2d1272b8SAndroid Build Coastguard Worker}
484*2d1272b8SAndroid Build Coastguard Worker```
485*2d1272b8SAndroid Build Coastguard Worker
486*2d1272b8SAndroid Build Coastguard WorkerWith this compiled into a WASM module, and installed into our font again, finally our fonts can talk to us!
487*2d1272b8SAndroid Build Coastguard Worker
488*2d1272b8SAndroid Build Coastguard Worker```
489*2d1272b8SAndroid Build Coastguard Worker$ hb-shape test-wasm.ttf abc
490*2d1272b8SAndroid Build Coastguard WorkerHello from Rust!
491*2d1272b8SAndroid Build Coastguard Worker[cent=0|sterling=1|fraction=2]
492*2d1272b8SAndroid Build Coastguard Worker```
493*2d1272b8SAndroid Build Coastguard Worker
494*2d1272b8SAndroid Build Coastguard WorkerNow 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:
495*2d1272b8SAndroid Build Coastguard Worker
496*2d1272b8SAndroid Build Coastguard Worker```rust
497*2d1272b8SAndroid Build Coastguard Workeruse wasm_bindgen::prelude::*;
498*2d1272b8SAndroid Build Coastguard Workeruse harfbuzz_wasm::{Font, GlyphBuffer};
499*2d1272b8SAndroid Build Coastguard Worker
500*2d1272b8SAndroid Build Coastguard Worker#[wasm_bindgen]
501*2d1272b8SAndroid Build Coastguard Workerpub fn shape(_shape_plan:u32, font_ref: u32, buf_ref: u32, _features: u32, _num_features: u32) -> i32 {
502*2d1272b8SAndroid Build Coastguard Worker    let font = Font::from_ref(font_ref);
503*2d1272b8SAndroid Build Coastguard Worker    let mut buffer = GlyphBuffer::from_ref(buf_ref);
504*2d1272b8SAndroid Build Coastguard Worker    for mut item in buffer.glyphs.iter_mut() {
505*2d1272b8SAndroid Build Coastguard Worker        // Map character to glyph
506*2d1272b8SAndroid Build Coastguard Worker        item.codepoint = font.get_glyph(item.codepoint, 0);
507*2d1272b8SAndroid Build Coastguard Worker        // Set advance width
508*2d1272b8SAndroid Build Coastguard Worker        item.x_advance = font.get_glyph_h_advance(item.codepoint);
509*2d1272b8SAndroid Build Coastguard Worker    }
510*2d1272b8SAndroid Build Coastguard Worker    1
511*2d1272b8SAndroid Build Coastguard Worker}
512*2d1272b8SAndroid Build Coastguard Worker```
513*2d1272b8SAndroid Build Coastguard Worker
514*2d1272b8SAndroid Build Coastguard WorkerThe `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.)
515*2d1272b8SAndroid Build Coastguard Worker
516*2d1272b8SAndroid Build Coastguard WorkerOne 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:
517*2d1272b8SAndroid Build Coastguard Worker
518*2d1272b8SAndroid Build Coastguard Worker```rust
519*2d1272b8SAndroid Build Coastguard Workeruse harfbuzz_wasm::{Font, GlyphBuffer};
520*2d1272b8SAndroid Build Coastguard Workeruse tiny_rng::{Rand, Rng};
521*2d1272b8SAndroid Build Coastguard Workeruse wasm_bindgen::prelude::*;
522*2d1272b8SAndroid Build Coastguard Worker
523*2d1272b8SAndroid Build Coastguard Worker#[wasm_bindgen]
524*2d1272b8SAndroid Build Coastguard Workerpub fn shape(_shape_plan:u32, font_ref: u32, buf_ref: u32, _features: u32, _num_features: u32) -> i32 {
525*2d1272b8SAndroid Build Coastguard Worker    let mut rng = Rng::from_seed(123456);
526*2d1272b8SAndroid Build Coastguard Worker
527*2d1272b8SAndroid Build Coastguard Worker    // Use the default OpenType shaper
528*2d1272b8SAndroid Build Coastguard Worker    let font = Font::from_ref(font_ref);
529*2d1272b8SAndroid Build Coastguard Worker    font.shape_with(buf_ref, "ot");
530*2d1272b8SAndroid Build Coastguard Worker
531*2d1272b8SAndroid Build Coastguard Worker    // Now we have a buffer with glyph ids, advance widths etc.
532*2d1272b8SAndroid Build Coastguard Worker    // already filled in.
533*2d1272b8SAndroid Build Coastguard Worker    let mut buffer = GlyphBuffer::from_ref(buf_ref);
534*2d1272b8SAndroid Build Coastguard Worker    for mut item in buffer.glyphs.iter_mut() {
535*2d1272b8SAndroid Build Coastguard Worker        // Randomize it!
536*2d1272b8SAndroid Build Coastguard Worker        item.x_offset = ((rng.rand_u32() as i32) >> 24) - 120;
537*2d1272b8SAndroid Build Coastguard Worker        item.y_offset = ((rng.rand_u32() as i32) >> 24) - 120;
538*2d1272b8SAndroid Build Coastguard Worker    }
539*2d1272b8SAndroid Build Coastguard Worker
540*2d1272b8SAndroid Build Coastguard Worker    1
541*2d1272b8SAndroid Build Coastguard Worker}
542*2d1272b8SAndroid Build Coastguard Worker```
543*2d1272b8SAndroid Build Coastguard Worker
544*2d1272b8SAndroid Build Coastguard WorkerSee the documentation for the `harfbuzz-wasm` crate for all the other
545