xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-wasm-shape.cc (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2011  Google, Inc.
3*2d1272b8SAndroid Build Coastguard Worker  *
4*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
5*2d1272b8SAndroid Build Coastguard Worker  *
6*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
7*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
8*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
9*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
10*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
11*2d1272b8SAndroid Build Coastguard Worker  *
12*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
17*2d1272b8SAndroid Build Coastguard Worker  *
18*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23*2d1272b8SAndroid Build Coastguard Worker  *
24*2d1272b8SAndroid Build Coastguard Worker  * Google Author(s): Behdad Esfahbod
25*2d1272b8SAndroid Build Coastguard Worker  */
26*2d1272b8SAndroid Build Coastguard Worker 
27*2d1272b8SAndroid Build Coastguard Worker #undef HB_DEBUG_WASM
28*2d1272b8SAndroid Build Coastguard Worker #define HB_DEBUG_WASM 1
29*2d1272b8SAndroid Build Coastguard Worker 
30*2d1272b8SAndroid Build Coastguard Worker #include "hb-shaper-impl.hh"
31*2d1272b8SAndroid Build Coastguard Worker 
32*2d1272b8SAndroid Build Coastguard Worker #ifdef HAVE_WASM
33*2d1272b8SAndroid Build Coastguard Worker 
34*2d1272b8SAndroid Build Coastguard Worker /* Compile wasm-micro-runtime with:
35*2d1272b8SAndroid Build Coastguard Worker  *
36*2d1272b8SAndroid Build Coastguard Worker  * $ cmake -DWAMR_BUILD_MULTI_MODULE=1 -DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_FAST_JIT=1
37*2d1272b8SAndroid Build Coastguard Worker  * $ make
38*2d1272b8SAndroid Build Coastguard Worker  *
39*2d1272b8SAndroid Build Coastguard Worker  * If you manage to build a wasm shared module successfully and want to use it,
40*2d1272b8SAndroid Build Coastguard Worker  * do the following:
41*2d1272b8SAndroid Build Coastguard Worker  *
42*2d1272b8SAndroid Build Coastguard Worker  *   - Add -DWAMR_BUILD_MULTI_MODULE=1 to your cmake build for wasm-micro-runtime,
43*2d1272b8SAndroid Build Coastguard Worker  *
44*2d1272b8SAndroid Build Coastguard Worker  *   - Remove the #define HB_WASM_NO_MODULES line below,
45*2d1272b8SAndroid Build Coastguard Worker  *
46*2d1272b8SAndroid Build Coastguard Worker  *   - Install your shared module with name ending in .wasm in
47*2d1272b8SAndroid Build Coastguard Worker  *     $(prefix)/$(libdir)/harfbuzz/wasm/
48*2d1272b8SAndroid Build Coastguard Worker  *
49*2d1272b8SAndroid Build Coastguard Worker  *   - Build your font's wasm code importing the shared modules with the desired
50*2d1272b8SAndroid Build Coastguard Worker  *     name. This can be done eg.: __attribute__((import_module("graphite2")))
51*2d1272b8SAndroid Build Coastguard Worker  *     before each symbol in the shared-module's headers.
52*2d1272b8SAndroid Build Coastguard Worker  *
53*2d1272b8SAndroid Build Coastguard Worker  *   - Try shaping your font and hope for the best...
54*2d1272b8SAndroid Build Coastguard Worker  *
55*2d1272b8SAndroid Build Coastguard Worker  * I haven't been able to get this to work since emcc's support for shared libraries
56*2d1272b8SAndroid Build Coastguard Worker  * requires support from the host that seems to be missing from wasm-micro-runtime?
57*2d1272b8SAndroid Build Coastguard Worker  */
58*2d1272b8SAndroid Build Coastguard Worker 
59*2d1272b8SAndroid Build Coastguard Worker #include "hb-wasm-api.hh"
60*2d1272b8SAndroid Build Coastguard Worker #include "hb-wasm-api-list.hh"
61*2d1272b8SAndroid Build Coastguard Worker 
62*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_WASM_NO_MODULES
63*2d1272b8SAndroid Build Coastguard Worker #define HB_WASM_NO_MODULES
64*2d1272b8SAndroid Build Coastguard Worker #endif
65*2d1272b8SAndroid Build Coastguard Worker 
66*2d1272b8SAndroid Build Coastguard Worker 
67*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_WASM_NO_MODULES
68*2d1272b8SAndroid Build Coastguard Worker static bool HB_UNUSED
_hb_wasm_module_reader(const char * module_name,uint8_t ** p_buffer,uint32_t * p_size)69*2d1272b8SAndroid Build Coastguard Worker _hb_wasm_module_reader (const char *module_name,
70*2d1272b8SAndroid Build Coastguard Worker 		       uint8_t **p_buffer, uint32_t *p_size)
71*2d1272b8SAndroid Build Coastguard Worker {
72*2d1272b8SAndroid Build Coastguard Worker   char path[sizeof (HB_WASM_MODULE_DIR) + 64] = HB_WASM_MODULE_DIR "/";
73*2d1272b8SAndroid Build Coastguard Worker   strncat (path, module_name, sizeof (path) - sizeof (HB_WASM_MODULE_DIR) - 16);
74*2d1272b8SAndroid Build Coastguard Worker   strncat (path, ".wasm", 6);
75*2d1272b8SAndroid Build Coastguard Worker 
76*2d1272b8SAndroid Build Coastguard Worker   auto *blob = hb_blob_create_from_file (path);
77*2d1272b8SAndroid Build Coastguard Worker 
78*2d1272b8SAndroid Build Coastguard Worker   unsigned length;
79*2d1272b8SAndroid Build Coastguard Worker   auto *data = hb_blob_get_data (blob, &length);
80*2d1272b8SAndroid Build Coastguard Worker 
81*2d1272b8SAndroid Build Coastguard Worker   *p_buffer = (uint8_t *) hb_malloc (length);
82*2d1272b8SAndroid Build Coastguard Worker 
83*2d1272b8SAndroid Build Coastguard Worker   if (length && !p_buffer)
84*2d1272b8SAndroid Build Coastguard Worker     return false;
85*2d1272b8SAndroid Build Coastguard Worker 
86*2d1272b8SAndroid Build Coastguard Worker   memcpy (*p_buffer, data, length);
87*2d1272b8SAndroid Build Coastguard Worker   *p_size = length;
88*2d1272b8SAndroid Build Coastguard Worker 
89*2d1272b8SAndroid Build Coastguard Worker   hb_blob_destroy (blob);
90*2d1272b8SAndroid Build Coastguard Worker 
91*2d1272b8SAndroid Build Coastguard Worker   return true;
92*2d1272b8SAndroid Build Coastguard Worker }
93*2d1272b8SAndroid Build Coastguard Worker 
94*2d1272b8SAndroid Build Coastguard Worker static void HB_UNUSED
_hb_wasm_module_destroyer(uint8_t * buffer,uint32_t size)95*2d1272b8SAndroid Build Coastguard Worker _hb_wasm_module_destroyer (uint8_t *buffer, uint32_t size)
96*2d1272b8SAndroid Build Coastguard Worker {
97*2d1272b8SAndroid Build Coastguard Worker   hb_free (buffer);
98*2d1272b8SAndroid Build Coastguard Worker }
99*2d1272b8SAndroid Build Coastguard Worker #endif
100*2d1272b8SAndroid Build Coastguard Worker 
101*2d1272b8SAndroid Build Coastguard Worker /*
102*2d1272b8SAndroid Build Coastguard Worker  * shaper face data
103*2d1272b8SAndroid Build Coastguard Worker  */
104*2d1272b8SAndroid Build Coastguard Worker 
105*2d1272b8SAndroid Build Coastguard Worker #define HB_WASM_TAG_WASM HB_TAG('W','a','s','m')
106*2d1272b8SAndroid Build Coastguard Worker 
107*2d1272b8SAndroid Build Coastguard Worker struct hb_wasm_shape_plan_t {
108*2d1272b8SAndroid Build Coastguard Worker   wasm_module_inst_t module_inst;
109*2d1272b8SAndroid Build Coastguard Worker   wasm_exec_env_t exec_env;
110*2d1272b8SAndroid Build Coastguard Worker   ptr_d(void, wasm_shape_plan);
111*2d1272b8SAndroid Build Coastguard Worker };
112*2d1272b8SAndroid Build Coastguard Worker 
113*2d1272b8SAndroid Build Coastguard Worker struct hb_wasm_face_data_t {
114*2d1272b8SAndroid Build Coastguard Worker   hb_blob_t *wasm_blob;
115*2d1272b8SAndroid Build Coastguard Worker   wasm_module_t wasm_module;
116*2d1272b8SAndroid Build Coastguard Worker   mutable hb_atomic_ptr_t<hb_wasm_shape_plan_t> plan;
117*2d1272b8SAndroid Build Coastguard Worker };
118*2d1272b8SAndroid Build Coastguard Worker 
119*2d1272b8SAndroid Build Coastguard Worker static bool
_hb_wasm_init()120*2d1272b8SAndroid Build Coastguard Worker _hb_wasm_init ()
121*2d1272b8SAndroid Build Coastguard Worker {
122*2d1272b8SAndroid Build Coastguard Worker   /* XXX
123*2d1272b8SAndroid Build Coastguard Worker    *
124*2d1272b8SAndroid Build Coastguard Worker    * Umm. Make this threadsafe. How?!
125*2d1272b8SAndroid Build Coastguard Worker    * It's clunky that we can't allocate a static mutex.
126*2d1272b8SAndroid Build Coastguard Worker    * So we have to first allocate one on the heap atomically...
127*2d1272b8SAndroid Build Coastguard Worker    *
128*2d1272b8SAndroid Build Coastguard Worker    * Do we also need to lock around module creation?
129*2d1272b8SAndroid Build Coastguard Worker    *
130*2d1272b8SAndroid Build Coastguard Worker    * Also, wasm-micro-runtime uses a singleton instance. So if
131*2d1272b8SAndroid Build Coastguard Worker    * another library or client uses it, all bets are off. :-(
132*2d1272b8SAndroid Build Coastguard Worker    * If nothing else, around HB_REF2OBJ().
133*2d1272b8SAndroid Build Coastguard Worker    */
134*2d1272b8SAndroid Build Coastguard Worker 
135*2d1272b8SAndroid Build Coastguard Worker   static bool initialized;
136*2d1272b8SAndroid Build Coastguard Worker   if (initialized)
137*2d1272b8SAndroid Build Coastguard Worker     return true;
138*2d1272b8SAndroid Build Coastguard Worker 
139*2d1272b8SAndroid Build Coastguard Worker   RuntimeInitArgs init_args;
140*2d1272b8SAndroid Build Coastguard Worker   hb_memset (&init_args, 0, sizeof (RuntimeInitArgs));
141*2d1272b8SAndroid Build Coastguard Worker 
142*2d1272b8SAndroid Build Coastguard Worker   init_args.mem_alloc_type = Alloc_With_Allocator;
143*2d1272b8SAndroid Build Coastguard Worker   init_args.mem_alloc_option.allocator.malloc_func = (void *) hb_malloc;
144*2d1272b8SAndroid Build Coastguard Worker   init_args.mem_alloc_option.allocator.realloc_func = (void *) hb_realloc;
145*2d1272b8SAndroid Build Coastguard Worker   init_args.mem_alloc_option.allocator.free_func = (void *) hb_free;
146*2d1272b8SAndroid Build Coastguard Worker 
147*2d1272b8SAndroid Build Coastguard Worker   // Native symbols need below registration phase
148*2d1272b8SAndroid Build Coastguard Worker   init_args.n_native_symbols = ARRAY_LENGTH (_hb_wasm_native_symbols);
149*2d1272b8SAndroid Build Coastguard Worker   init_args.native_module_name = "env";
150*2d1272b8SAndroid Build Coastguard Worker   init_args.native_symbols = _hb_wasm_native_symbols;
151*2d1272b8SAndroid Build Coastguard Worker 
152*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!wasm_runtime_full_init (&init_args)))
153*2d1272b8SAndroid Build Coastguard Worker   {
154*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (WASM, nullptr, "Init runtime environment failed.");
155*2d1272b8SAndroid Build Coastguard Worker     return false;
156*2d1272b8SAndroid Build Coastguard Worker   }
157*2d1272b8SAndroid Build Coastguard Worker 
158*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_WASM_NO_MODULES
159*2d1272b8SAndroid Build Coastguard Worker   wasm_runtime_set_module_reader (_hb_wasm_module_reader,
160*2d1272b8SAndroid Build Coastguard Worker 				  _hb_wasm_module_destroyer);
161*2d1272b8SAndroid Build Coastguard Worker #endif
162*2d1272b8SAndroid Build Coastguard Worker 
163*2d1272b8SAndroid Build Coastguard Worker   initialized = true;
164*2d1272b8SAndroid Build Coastguard Worker   return true;
165*2d1272b8SAndroid Build Coastguard Worker }
166*2d1272b8SAndroid Build Coastguard Worker 
167*2d1272b8SAndroid Build Coastguard Worker hb_wasm_face_data_t *
_hb_wasm_shaper_face_data_create(hb_face_t * face)168*2d1272b8SAndroid Build Coastguard Worker _hb_wasm_shaper_face_data_create (hb_face_t *face)
169*2d1272b8SAndroid Build Coastguard Worker {
170*2d1272b8SAndroid Build Coastguard Worker   char error[128];
171*2d1272b8SAndroid Build Coastguard Worker   hb_wasm_face_data_t *data = nullptr;
172*2d1272b8SAndroid Build Coastguard Worker   hb_blob_t *wasm_blob = nullptr;
173*2d1272b8SAndroid Build Coastguard Worker   wasm_module_t wasm_module = nullptr;
174*2d1272b8SAndroid Build Coastguard Worker 
175*2d1272b8SAndroid Build Coastguard Worker   wasm_blob = hb_face_reference_table (face, HB_WASM_TAG_WASM);
176*2d1272b8SAndroid Build Coastguard Worker   unsigned length = hb_blob_get_length (wasm_blob);
177*2d1272b8SAndroid Build Coastguard Worker   if (!length)
178*2d1272b8SAndroid Build Coastguard Worker     goto fail;
179*2d1272b8SAndroid Build Coastguard Worker 
180*2d1272b8SAndroid Build Coastguard Worker   if (!_hb_wasm_init ())
181*2d1272b8SAndroid Build Coastguard Worker     goto fail;
182*2d1272b8SAndroid Build Coastguard Worker 
183*2d1272b8SAndroid Build Coastguard Worker   wasm_module = wasm_runtime_load ((uint8_t *) hb_blob_get_data_writable (wasm_blob, nullptr),
184*2d1272b8SAndroid Build Coastguard Worker 				   length, error, sizeof (error));
185*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!wasm_module))
186*2d1272b8SAndroid Build Coastguard Worker   {
187*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (WASM, nullptr, "Load wasm module failed: %s", error);
188*2d1272b8SAndroid Build Coastguard Worker     goto fail;
189*2d1272b8SAndroid Build Coastguard Worker   }
190*2d1272b8SAndroid Build Coastguard Worker 
191*2d1272b8SAndroid Build Coastguard Worker   data = (hb_wasm_face_data_t *) hb_calloc (1, sizeof (hb_wasm_face_data_t));
192*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!data))
193*2d1272b8SAndroid Build Coastguard Worker     goto fail;
194*2d1272b8SAndroid Build Coastguard Worker 
195*2d1272b8SAndroid Build Coastguard Worker   data->wasm_blob = wasm_blob;
196*2d1272b8SAndroid Build Coastguard Worker   data->wasm_module = wasm_module;
197*2d1272b8SAndroid Build Coastguard Worker 
198*2d1272b8SAndroid Build Coastguard Worker   return data;
199*2d1272b8SAndroid Build Coastguard Worker 
200*2d1272b8SAndroid Build Coastguard Worker fail:
201*2d1272b8SAndroid Build Coastguard Worker   if (wasm_module)
202*2d1272b8SAndroid Build Coastguard Worker       wasm_runtime_unload (wasm_module);
203*2d1272b8SAndroid Build Coastguard Worker   hb_blob_destroy (wasm_blob);
204*2d1272b8SAndroid Build Coastguard Worker   hb_free (data);
205*2d1272b8SAndroid Build Coastguard Worker   return nullptr;
206*2d1272b8SAndroid Build Coastguard Worker }
207*2d1272b8SAndroid Build Coastguard Worker 
208*2d1272b8SAndroid Build Coastguard Worker static hb_wasm_shape_plan_t *
acquire_shape_plan(hb_face_t * face,const hb_wasm_face_data_t * face_data)209*2d1272b8SAndroid Build Coastguard Worker acquire_shape_plan (hb_face_t *face,
210*2d1272b8SAndroid Build Coastguard Worker 		    const hb_wasm_face_data_t *face_data)
211*2d1272b8SAndroid Build Coastguard Worker {
212*2d1272b8SAndroid Build Coastguard Worker   char error[128];
213*2d1272b8SAndroid Build Coastguard Worker 
214*2d1272b8SAndroid Build Coastguard Worker   /* Fetch cached one if available. */
215*2d1272b8SAndroid Build Coastguard Worker   hb_wasm_shape_plan_t *plan = face_data->plan.get_acquire ();
216*2d1272b8SAndroid Build Coastguard Worker   if (likely (plan && face_data->plan.cmpexch (plan, nullptr)))
217*2d1272b8SAndroid Build Coastguard Worker     return plan;
218*2d1272b8SAndroid Build Coastguard Worker 
219*2d1272b8SAndroid Build Coastguard Worker   plan = (hb_wasm_shape_plan_t *) hb_calloc (1, sizeof (hb_wasm_shape_plan_t));
220*2d1272b8SAndroid Build Coastguard Worker 
221*2d1272b8SAndroid Build Coastguard Worker   wasm_module_inst_t module_inst = nullptr;
222*2d1272b8SAndroid Build Coastguard Worker   wasm_exec_env_t exec_env = nullptr;
223*2d1272b8SAndroid Build Coastguard Worker   wasm_function_inst_t func = nullptr;
224*2d1272b8SAndroid Build Coastguard Worker 
225*2d1272b8SAndroid Build Coastguard Worker   constexpr uint32_t stack_size = 32 * 1024, heap_size = 2 * 1024 * 1024;
226*2d1272b8SAndroid Build Coastguard Worker 
227*2d1272b8SAndroid Build Coastguard Worker   module_inst = plan->module_inst = wasm_runtime_instantiate (face_data->wasm_module,
228*2d1272b8SAndroid Build Coastguard Worker 							      stack_size, heap_size,
229*2d1272b8SAndroid Build Coastguard Worker 							      error, sizeof (error));
230*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!module_inst))
231*2d1272b8SAndroid Build Coastguard Worker   {
232*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (WASM, face_data, "Create wasm module instance failed: %s", error);
233*2d1272b8SAndroid Build Coastguard Worker     goto fail;
234*2d1272b8SAndroid Build Coastguard Worker   }
235*2d1272b8SAndroid Build Coastguard Worker 
236*2d1272b8SAndroid Build Coastguard Worker   exec_env = plan->exec_env = wasm_runtime_create_exec_env (module_inst,
237*2d1272b8SAndroid Build Coastguard Worker 							    stack_size);
238*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!exec_env)) {
239*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (WASM, face_data, "Create wasm execution environment failed.");
240*2d1272b8SAndroid Build Coastguard Worker     goto fail;
241*2d1272b8SAndroid Build Coastguard Worker   }
242*2d1272b8SAndroid Build Coastguard Worker 
243*2d1272b8SAndroid Build Coastguard Worker   func = wasm_runtime_lookup_function (module_inst, "shape_plan_create");
244*2d1272b8SAndroid Build Coastguard Worker   if (func)
245*2d1272b8SAndroid Build Coastguard Worker   {
246*2d1272b8SAndroid Build Coastguard Worker     wasm_val_t results[1];
247*2d1272b8SAndroid Build Coastguard Worker     wasm_val_t arguments[1];
248*2d1272b8SAndroid Build Coastguard Worker 
249*2d1272b8SAndroid Build Coastguard Worker     HB_OBJ2REF (face);
250*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!faceref))
251*2d1272b8SAndroid Build Coastguard Worker     {
252*2d1272b8SAndroid Build Coastguard Worker       DEBUG_MSG (WASM, face_data, "Failed to register face object.");
253*2d1272b8SAndroid Build Coastguard Worker       goto fail;
254*2d1272b8SAndroid Build Coastguard Worker     }
255*2d1272b8SAndroid Build Coastguard Worker 
256*2d1272b8SAndroid Build Coastguard Worker     results[0].kind = WASM_I32;
257*2d1272b8SAndroid Build Coastguard Worker     arguments[0].kind = WASM_I32;
258*2d1272b8SAndroid Build Coastguard Worker     arguments[0].of.i32 = faceref;
259*2d1272b8SAndroid Build Coastguard Worker     bool ret = wasm_runtime_call_wasm_a (exec_env, func,
260*2d1272b8SAndroid Build Coastguard Worker 					 ARRAY_LENGTH (results), results,
261*2d1272b8SAndroid Build Coastguard Worker 					 ARRAY_LENGTH (arguments), arguments);
262*2d1272b8SAndroid Build Coastguard Worker 
263*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!ret))
264*2d1272b8SAndroid Build Coastguard Worker     {
265*2d1272b8SAndroid Build Coastguard Worker       DEBUG_MSG (WASM, module_inst, "Calling shape_plan_create() failed: %s",
266*2d1272b8SAndroid Build Coastguard Worker 		 wasm_runtime_get_exception (module_inst));
267*2d1272b8SAndroid Build Coastguard Worker       goto fail;
268*2d1272b8SAndroid Build Coastguard Worker     }
269*2d1272b8SAndroid Build Coastguard Worker     plan->wasm_shape_planptr = results[0].of.i32;
270*2d1272b8SAndroid Build Coastguard Worker   }
271*2d1272b8SAndroid Build Coastguard Worker 
272*2d1272b8SAndroid Build Coastguard Worker   return plan;
273*2d1272b8SAndroid Build Coastguard Worker 
274*2d1272b8SAndroid Build Coastguard Worker fail:
275*2d1272b8SAndroid Build Coastguard Worker 
276*2d1272b8SAndroid Build Coastguard Worker   if (exec_env)
277*2d1272b8SAndroid Build Coastguard Worker     wasm_runtime_destroy_exec_env (exec_env);
278*2d1272b8SAndroid Build Coastguard Worker   if (module_inst)
279*2d1272b8SAndroid Build Coastguard Worker     wasm_runtime_deinstantiate (module_inst);
280*2d1272b8SAndroid Build Coastguard Worker   hb_free (plan);
281*2d1272b8SAndroid Build Coastguard Worker   return nullptr;
282*2d1272b8SAndroid Build Coastguard Worker }
283*2d1272b8SAndroid Build Coastguard Worker 
284*2d1272b8SAndroid Build Coastguard Worker static void
release_shape_plan(const hb_wasm_face_data_t * face_data,hb_wasm_shape_plan_t * plan,bool cache=false)285*2d1272b8SAndroid Build Coastguard Worker release_shape_plan (const hb_wasm_face_data_t *face_data,
286*2d1272b8SAndroid Build Coastguard Worker 		    hb_wasm_shape_plan_t *plan,
287*2d1272b8SAndroid Build Coastguard Worker 		    bool cache = false)
288*2d1272b8SAndroid Build Coastguard Worker {
289*2d1272b8SAndroid Build Coastguard Worker   if (cache && face_data->plan.cmpexch (nullptr, plan))
290*2d1272b8SAndroid Build Coastguard Worker     return;
291*2d1272b8SAndroid Build Coastguard Worker 
292*2d1272b8SAndroid Build Coastguard Worker   auto *module_inst = plan->module_inst;
293*2d1272b8SAndroid Build Coastguard Worker   auto *exec_env = plan->exec_env;
294*2d1272b8SAndroid Build Coastguard Worker 
295*2d1272b8SAndroid Build Coastguard Worker   /* Is there even any point to having a shape_plan_destroy function
296*2d1272b8SAndroid Build Coastguard Worker    * and calling it? */
297*2d1272b8SAndroid Build Coastguard Worker   if (plan->wasm_shape_planptr)
298*2d1272b8SAndroid Build Coastguard Worker   {
299*2d1272b8SAndroid Build Coastguard Worker 
300*2d1272b8SAndroid Build Coastguard Worker     auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy");
301*2d1272b8SAndroid Build Coastguard Worker     if (func)
302*2d1272b8SAndroid Build Coastguard Worker     {
303*2d1272b8SAndroid Build Coastguard Worker       wasm_val_t arguments[1];
304*2d1272b8SAndroid Build Coastguard Worker 
305*2d1272b8SAndroid Build Coastguard Worker       arguments[0].kind = WASM_I32;
306*2d1272b8SAndroid Build Coastguard Worker       arguments[0].of.i32 = plan->wasm_shape_planptr;
307*2d1272b8SAndroid Build Coastguard Worker       bool ret = wasm_runtime_call_wasm_a (exec_env, func,
308*2d1272b8SAndroid Build Coastguard Worker 					   0, nullptr,
309*2d1272b8SAndroid Build Coastguard Worker 					   ARRAY_LENGTH (arguments), arguments);
310*2d1272b8SAndroid Build Coastguard Worker 
311*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!ret))
312*2d1272b8SAndroid Build Coastguard Worker       {
313*2d1272b8SAndroid Build Coastguard Worker 	DEBUG_MSG (WASM, module_inst, "Calling shape_plan_destroy() failed: %s",
314*2d1272b8SAndroid Build Coastguard Worker 		   wasm_runtime_get_exception (module_inst));
315*2d1272b8SAndroid Build Coastguard Worker       }
316*2d1272b8SAndroid Build Coastguard Worker     }
317*2d1272b8SAndroid Build Coastguard Worker   }
318*2d1272b8SAndroid Build Coastguard Worker 
319*2d1272b8SAndroid Build Coastguard Worker   wasm_runtime_destroy_exec_env (exec_env);
320*2d1272b8SAndroid Build Coastguard Worker   wasm_runtime_deinstantiate (module_inst);
321*2d1272b8SAndroid Build Coastguard Worker   hb_free (plan);
322*2d1272b8SAndroid Build Coastguard Worker }
323*2d1272b8SAndroid Build Coastguard Worker 
324*2d1272b8SAndroid Build Coastguard Worker void
_hb_wasm_shaper_face_data_destroy(hb_wasm_face_data_t * data)325*2d1272b8SAndroid Build Coastguard Worker _hb_wasm_shaper_face_data_destroy (hb_wasm_face_data_t *data)
326*2d1272b8SAndroid Build Coastguard Worker {
327*2d1272b8SAndroid Build Coastguard Worker   if (data->plan.get_relaxed ())
328*2d1272b8SAndroid Build Coastguard Worker     release_shape_plan (data, data->plan);
329*2d1272b8SAndroid Build Coastguard Worker   wasm_runtime_unload (data->wasm_module);
330*2d1272b8SAndroid Build Coastguard Worker   hb_blob_destroy (data->wasm_blob);
331*2d1272b8SAndroid Build Coastguard Worker   hb_free (data);
332*2d1272b8SAndroid Build Coastguard Worker }
333*2d1272b8SAndroid Build Coastguard Worker 
334*2d1272b8SAndroid Build Coastguard Worker 
335*2d1272b8SAndroid Build Coastguard Worker /*
336*2d1272b8SAndroid Build Coastguard Worker  * shaper font data
337*2d1272b8SAndroid Build Coastguard Worker  */
338*2d1272b8SAndroid Build Coastguard Worker 
339*2d1272b8SAndroid Build Coastguard Worker struct hb_wasm_font_data_t {};
340*2d1272b8SAndroid Build Coastguard Worker 
341*2d1272b8SAndroid Build Coastguard Worker hb_wasm_font_data_t *
_hb_wasm_shaper_font_data_create(hb_font_t * font HB_UNUSED)342*2d1272b8SAndroid Build Coastguard Worker _hb_wasm_shaper_font_data_create (hb_font_t *font HB_UNUSED)
343*2d1272b8SAndroid Build Coastguard Worker {
344*2d1272b8SAndroid Build Coastguard Worker   return (hb_wasm_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
345*2d1272b8SAndroid Build Coastguard Worker }
346*2d1272b8SAndroid Build Coastguard Worker 
347*2d1272b8SAndroid Build Coastguard Worker void
_hb_wasm_shaper_font_data_destroy(hb_wasm_font_data_t * data HB_UNUSED)348*2d1272b8SAndroid Build Coastguard Worker _hb_wasm_shaper_font_data_destroy (hb_wasm_font_data_t *data HB_UNUSED)
349*2d1272b8SAndroid Build Coastguard Worker {
350*2d1272b8SAndroid Build Coastguard Worker }
351*2d1272b8SAndroid Build Coastguard Worker 
352*2d1272b8SAndroid Build Coastguard Worker 
353*2d1272b8SAndroid Build Coastguard Worker /*
354*2d1272b8SAndroid Build Coastguard Worker  * shaper
355*2d1272b8SAndroid Build Coastguard Worker  */
356*2d1272b8SAndroid Build Coastguard Worker 
357*2d1272b8SAndroid Build Coastguard Worker 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)358*2d1272b8SAndroid Build Coastguard Worker _hb_wasm_shape (hb_shape_plan_t    *shape_plan,
359*2d1272b8SAndroid Build Coastguard Worker 		hb_font_t          *font,
360*2d1272b8SAndroid Build Coastguard Worker 		hb_buffer_t        *buffer,
361*2d1272b8SAndroid Build Coastguard Worker 		const hb_feature_t *features,
362*2d1272b8SAndroid Build Coastguard Worker 		unsigned int        num_features)
363*2d1272b8SAndroid Build Coastguard Worker {
364*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (buffer->in_error ()))
365*2d1272b8SAndroid Build Coastguard Worker     return false;
366*2d1272b8SAndroid Build Coastguard Worker 
367*2d1272b8SAndroid Build Coastguard Worker   bool ret = true;
368*2d1272b8SAndroid Build Coastguard Worker   hb_face_t *face = font->face;
369*2d1272b8SAndroid Build Coastguard Worker   const hb_wasm_face_data_t *face_data = face->data.wasm;
370*2d1272b8SAndroid Build Coastguard Worker 
371*2d1272b8SAndroid Build Coastguard Worker   bool retried = false;
372*2d1272b8SAndroid Build Coastguard Worker   if (0)
373*2d1272b8SAndroid Build Coastguard Worker   {
374*2d1272b8SAndroid Build Coastguard Worker retry:
375*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (WASM, font, "Retrying...");
376*2d1272b8SAndroid Build Coastguard Worker   }
377*2d1272b8SAndroid Build Coastguard Worker 
378*2d1272b8SAndroid Build Coastguard Worker   wasm_function_inst_t func = nullptr;
379*2d1272b8SAndroid Build Coastguard Worker 
380*2d1272b8SAndroid Build Coastguard Worker   hb_wasm_shape_plan_t *plan = acquire_shape_plan (face, face_data);
381*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!plan))
382*2d1272b8SAndroid Build Coastguard Worker   {
383*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (WASM, face_data, "Acquiring shape-plan failed.");
384*2d1272b8SAndroid Build Coastguard Worker     return false;
385*2d1272b8SAndroid Build Coastguard Worker   }
386*2d1272b8SAndroid Build Coastguard Worker 
387*2d1272b8SAndroid Build Coastguard Worker   auto *module_inst = plan->module_inst;
388*2d1272b8SAndroid Build Coastguard Worker   auto *exec_env = plan->exec_env;
389*2d1272b8SAndroid Build Coastguard Worker 
390*2d1272b8SAndroid Build Coastguard Worker   HB_OBJ2REF (font);
391*2d1272b8SAndroid Build Coastguard Worker   HB_OBJ2REF (buffer);
392*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!fontref || !bufferref))
393*2d1272b8SAndroid Build Coastguard Worker   {
394*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (WASM, module_inst, "Failed to register objects.");
395*2d1272b8SAndroid Build Coastguard Worker     goto fail;
396*2d1272b8SAndroid Build Coastguard Worker   }
397*2d1272b8SAndroid Build Coastguard Worker 
398*2d1272b8SAndroid Build Coastguard Worker   func = wasm_runtime_lookup_function (module_inst, "shape");
399*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!func))
400*2d1272b8SAndroid Build Coastguard Worker   {
401*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (WASM, module_inst, "Shape function not found.");
402*2d1272b8SAndroid Build Coastguard Worker     goto fail;
403*2d1272b8SAndroid Build Coastguard Worker   }
404*2d1272b8SAndroid Build Coastguard Worker 
405*2d1272b8SAndroid Build Coastguard Worker   wasm_val_t results[1];
406*2d1272b8SAndroid Build Coastguard Worker   wasm_val_t arguments[5];
407*2d1272b8SAndroid Build Coastguard Worker 
408*2d1272b8SAndroid Build Coastguard Worker   results[0].kind = WASM_I32;
409*2d1272b8SAndroid Build Coastguard Worker   arguments[0].kind = WASM_I32;
410*2d1272b8SAndroid Build Coastguard Worker   arguments[0].of.i32 = plan->wasm_shape_planptr;
411*2d1272b8SAndroid Build Coastguard Worker   arguments[1].kind = WASM_I32;
412*2d1272b8SAndroid Build Coastguard Worker   arguments[1].of.i32 = fontref;
413*2d1272b8SAndroid Build Coastguard Worker   arguments[2].kind = WASM_I32;
414*2d1272b8SAndroid Build Coastguard Worker   arguments[2].of.i32 = bufferref;
415*2d1272b8SAndroid Build Coastguard Worker   arguments[3].kind = WASM_I32;
416*2d1272b8SAndroid Build Coastguard Worker   arguments[3].of.i32 = num_features ? wasm_runtime_module_dup_data (module_inst,
417*2d1272b8SAndroid Build Coastguard Worker 								     (const char *) features,
418*2d1272b8SAndroid Build Coastguard Worker 								     num_features * sizeof (features[0])) : 0;
419*2d1272b8SAndroid Build Coastguard Worker   arguments[4].kind = WASM_I32;
420*2d1272b8SAndroid Build Coastguard Worker   arguments[4].of.i32 = num_features;
421*2d1272b8SAndroid Build Coastguard Worker 
422*2d1272b8SAndroid Build Coastguard Worker   ret = wasm_runtime_call_wasm_a (exec_env, func,
423*2d1272b8SAndroid Build Coastguard Worker 				  ARRAY_LENGTH (results), results,
424*2d1272b8SAndroid Build Coastguard Worker 				  ARRAY_LENGTH (arguments), arguments);
425*2d1272b8SAndroid Build Coastguard Worker 
426*2d1272b8SAndroid Build Coastguard Worker   if (num_features)
427*2d1272b8SAndroid Build Coastguard Worker     wasm_runtime_module_free (module_inst, arguments[2].of.i32);
428*2d1272b8SAndroid Build Coastguard Worker 
429*2d1272b8SAndroid Build Coastguard Worker   if (unlikely (!ret || !results[0].of.i32))
430*2d1272b8SAndroid Build Coastguard Worker   {
431*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (WASM, module_inst, "Calling shape() failed: %s",
432*2d1272b8SAndroid Build Coastguard Worker 	       wasm_runtime_get_exception (module_inst));
433*2d1272b8SAndroid Build Coastguard Worker     if (!buffer->ensure_unicode ())
434*2d1272b8SAndroid Build Coastguard Worker     {
435*2d1272b8SAndroid Build Coastguard Worker       DEBUG_MSG (WASM, font, "Shape failed but buffer is not in Unicode; failing...");
436*2d1272b8SAndroid Build Coastguard Worker       goto fail;
437*2d1272b8SAndroid Build Coastguard Worker     }
438*2d1272b8SAndroid Build Coastguard Worker     if (retried)
439*2d1272b8SAndroid Build Coastguard Worker     {
440*2d1272b8SAndroid Build Coastguard Worker       DEBUG_MSG (WASM, font, "Giving up...");
441*2d1272b8SAndroid Build Coastguard Worker       goto fail;
442*2d1272b8SAndroid Build Coastguard Worker     }
443*2d1272b8SAndroid Build Coastguard Worker     buffer->successful = true;
444*2d1272b8SAndroid Build Coastguard Worker     retried = true;
445*2d1272b8SAndroid Build Coastguard Worker     release_shape_plan (face_data, plan);
446*2d1272b8SAndroid Build Coastguard Worker     plan = nullptr;
447*2d1272b8SAndroid Build Coastguard Worker     goto retry;
448*2d1272b8SAndroid Build Coastguard Worker   }
449*2d1272b8SAndroid Build Coastguard Worker 
450*2d1272b8SAndroid Build Coastguard Worker   /* TODO Regularize clusters according to direction & cluster level,
451*2d1272b8SAndroid Build Coastguard Worker    * such that client doesn't crash with unmet expectations. */
452*2d1272b8SAndroid Build Coastguard Worker 
453*2d1272b8SAndroid Build Coastguard Worker   if (!results[0].of.i32)
454*2d1272b8SAndroid Build Coastguard Worker   {
455*2d1272b8SAndroid Build Coastguard Worker fail:
456*2d1272b8SAndroid Build Coastguard Worker     ret = false;
457*2d1272b8SAndroid Build Coastguard Worker   }
458*2d1272b8SAndroid Build Coastguard Worker 
459*2d1272b8SAndroid Build Coastguard Worker   release_shape_plan (face_data, plan, ret);
460*2d1272b8SAndroid Build Coastguard Worker 
461*2d1272b8SAndroid Build Coastguard Worker   if (ret)
462*2d1272b8SAndroid Build Coastguard Worker   {
463*2d1272b8SAndroid Build Coastguard Worker     buffer->clear_glyph_flags ();
464*2d1272b8SAndroid Build Coastguard Worker     buffer->unsafe_to_break ();
465*2d1272b8SAndroid Build Coastguard Worker   }
466*2d1272b8SAndroid Build Coastguard Worker 
467*2d1272b8SAndroid Build Coastguard Worker   return ret;
468*2d1272b8SAndroid Build Coastguard Worker }
469*2d1272b8SAndroid Build Coastguard Worker 
470*2d1272b8SAndroid Build Coastguard Worker #endif
471