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