1*2d1272b8SAndroid Build Coastguard Worker #define HB_WASM_INTERFACE(ret_t, name) __attribute__((export_name(#name))) ret_t name
2*2d1272b8SAndroid Build Coastguard Worker
3*2d1272b8SAndroid Build Coastguard Worker #include <hb-wasm-api.h>
4*2d1272b8SAndroid Build Coastguard Worker
5*2d1272b8SAndroid Build Coastguard Worker #include <graphite2/Segment.h>
6*2d1272b8SAndroid Build Coastguard Worker
7*2d1272b8SAndroid Build Coastguard Worker #include <stdlib.h>
8*2d1272b8SAndroid Build Coastguard Worker #include <string.h>
9*2d1272b8SAndroid Build Coastguard Worker
10*2d1272b8SAndroid Build Coastguard Worker void debugprint1 (char *s, int32_t);
11*2d1272b8SAndroid Build Coastguard Worker void debugprint2 (char *s, int32_t, int32_t);
12*2d1272b8SAndroid Build Coastguard Worker
copy_table(const void * data,unsigned int tag,size_t * len)13*2d1272b8SAndroid Build Coastguard Worker static const void *copy_table (const void *data, unsigned int tag, size_t *len)
14*2d1272b8SAndroid Build Coastguard Worker {
15*2d1272b8SAndroid Build Coastguard Worker face_t *face = (face_t *) data;
16*2d1272b8SAndroid Build Coastguard Worker blob_t blob = BLOB_INIT;
17*2d1272b8SAndroid Build Coastguard Worker if (!face_copy_table (face, tag, &blob))
18*2d1272b8SAndroid Build Coastguard Worker abort ();
19*2d1272b8SAndroid Build Coastguard Worker
20*2d1272b8SAndroid Build Coastguard Worker *len = blob.length;
21*2d1272b8SAndroid Build Coastguard Worker return blob.data;
22*2d1272b8SAndroid Build Coastguard Worker }
23*2d1272b8SAndroid Build Coastguard Worker
free_table(const void * data,const void * table_data)24*2d1272b8SAndroid Build Coastguard Worker static void free_table (const void *data, const void *table_data)
25*2d1272b8SAndroid Build Coastguard Worker {
26*2d1272b8SAndroid Build Coastguard Worker blob_t blob;
27*2d1272b8SAndroid Build Coastguard Worker blob.length = 0; // Doesn't matter
28*2d1272b8SAndroid Build Coastguard Worker blob.data = (char *) table_data;
29*2d1272b8SAndroid Build Coastguard Worker blob_free (&blob);
30*2d1272b8SAndroid Build Coastguard Worker }
31*2d1272b8SAndroid Build Coastguard Worker
32*2d1272b8SAndroid Build Coastguard Worker void *
shape_plan_create(face_t * face)33*2d1272b8SAndroid Build Coastguard Worker shape_plan_create (face_t *face)
34*2d1272b8SAndroid Build Coastguard Worker {
35*2d1272b8SAndroid Build Coastguard Worker const gr_face_ops ops = {sizeof (gr_face_ops), ©_table, &free_table};
36*2d1272b8SAndroid Build Coastguard Worker gr_face *grface = gr_make_face_with_ops (face, &ops, gr_face_preloadAll);
37*2d1272b8SAndroid Build Coastguard Worker return grface;
38*2d1272b8SAndroid Build Coastguard Worker }
39*2d1272b8SAndroid Build Coastguard Worker
40*2d1272b8SAndroid Build Coastguard Worker void
shape_plan_destroy(void * data)41*2d1272b8SAndroid Build Coastguard Worker shape_plan_destroy (void *data)
42*2d1272b8SAndroid Build Coastguard Worker {
43*2d1272b8SAndroid Build Coastguard Worker gr_face_destroy ((gr_face *) data);
44*2d1272b8SAndroid Build Coastguard Worker }
45*2d1272b8SAndroid Build Coastguard Worker
46*2d1272b8SAndroid Build Coastguard Worker bool_t
shape(void * shape_plan,font_t * font,buffer_t * buffer,const feature_t * features,uint32_t num_features)47*2d1272b8SAndroid Build Coastguard Worker shape (void *shape_plan,
48*2d1272b8SAndroid Build Coastguard Worker font_t *font,
49*2d1272b8SAndroid Build Coastguard Worker buffer_t *buffer,
50*2d1272b8SAndroid Build Coastguard Worker const feature_t *features,
51*2d1272b8SAndroid Build Coastguard Worker uint32_t num_features)
52*2d1272b8SAndroid Build Coastguard Worker {
53*2d1272b8SAndroid Build Coastguard Worker face_t *face = font_get_face (font);
54*2d1272b8SAndroid Build Coastguard Worker gr_face *grface = (gr_face *) shape_plan;
55*2d1272b8SAndroid Build Coastguard Worker
56*2d1272b8SAndroid Build Coastguard Worker direction_t direction = buffer_get_direction (buffer);
57*2d1272b8SAndroid Build Coastguard Worker direction_t horiz_dir = script_get_horizontal_direction (buffer_get_script (buffer));
58*2d1272b8SAndroid Build Coastguard Worker /* TODO vertical:
59*2d1272b8SAndroid Build Coastguard Worker * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
60*2d1272b8SAndroid Build Coastguard Worker * Ogham fonts are supposed to be implemented BTT or not. Need to research that
61*2d1272b8SAndroid Build Coastguard Worker * first. */
62*2d1272b8SAndroid Build Coastguard Worker if ((DIRECTION_IS_HORIZONTAL (direction) &&
63*2d1272b8SAndroid Build Coastguard Worker direction != horiz_dir && horiz_dir != DIRECTION_INVALID) ||
64*2d1272b8SAndroid Build Coastguard Worker (DIRECTION_IS_VERTICAL (direction) &&
65*2d1272b8SAndroid Build Coastguard Worker direction != DIRECTION_TTB))
66*2d1272b8SAndroid Build Coastguard Worker {
67*2d1272b8SAndroid Build Coastguard Worker buffer_reverse_clusters (buffer);
68*2d1272b8SAndroid Build Coastguard Worker direction = DIRECTION_REVERSE (direction);
69*2d1272b8SAndroid Build Coastguard Worker }
70*2d1272b8SAndroid Build Coastguard Worker
71*2d1272b8SAndroid Build Coastguard Worker buffer_contents_t contents = BUFFER_CONTENTS_INIT;
72*2d1272b8SAndroid Build Coastguard Worker if (!buffer_copy_contents (buffer, &contents))
73*2d1272b8SAndroid Build Coastguard Worker return false;
74*2d1272b8SAndroid Build Coastguard Worker
75*2d1272b8SAndroid Build Coastguard Worker gr_segment *seg = nullptr;
76*2d1272b8SAndroid Build Coastguard Worker const gr_slot *is;
77*2d1272b8SAndroid Build Coastguard Worker unsigned int ci = 0, ic = 0;
78*2d1272b8SAndroid Build Coastguard Worker unsigned int curradvx = 0, curradvy = 0;
79*2d1272b8SAndroid Build Coastguard Worker unsigned length = contents.length;
80*2d1272b8SAndroid Build Coastguard Worker
81*2d1272b8SAndroid Build Coastguard Worker uint32_t *chars = (uint32_t *) malloc (length * sizeof (uint32_t));
82*2d1272b8SAndroid Build Coastguard Worker if (!chars)
83*2d1272b8SAndroid Build Coastguard Worker return false;
84*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < contents.length; ++i)
85*2d1272b8SAndroid Build Coastguard Worker chars[i] = contents.info[i].codepoint;
86*2d1272b8SAndroid Build Coastguard Worker
87*2d1272b8SAndroid Build Coastguard Worker seg = gr_make_seg (nullptr, grface,
88*2d1272b8SAndroid Build Coastguard Worker 0, // https://github.com/harfbuzz/harfbuzz/issues/3439#issuecomment-1442650148
89*2d1272b8SAndroid Build Coastguard Worker nullptr,
90*2d1272b8SAndroid Build Coastguard Worker gr_utf32, chars, contents.length,
91*2d1272b8SAndroid Build Coastguard Worker 2 | (direction == DIRECTION_RTL ? 1 : 0));
92*2d1272b8SAndroid Build Coastguard Worker
93*2d1272b8SAndroid Build Coastguard Worker free (chars);
94*2d1272b8SAndroid Build Coastguard Worker
95*2d1272b8SAndroid Build Coastguard Worker if (!seg)
96*2d1272b8SAndroid Build Coastguard Worker return false;
97*2d1272b8SAndroid Build Coastguard Worker
98*2d1272b8SAndroid Build Coastguard Worker unsigned int glyph_count = gr_seg_n_slots (seg);
99*2d1272b8SAndroid Build Coastguard Worker
100*2d1272b8SAndroid Build Coastguard Worker struct cluster_t {
101*2d1272b8SAndroid Build Coastguard Worker unsigned int base_char;
102*2d1272b8SAndroid Build Coastguard Worker unsigned int num_chars;
103*2d1272b8SAndroid Build Coastguard Worker unsigned int base_glyph;
104*2d1272b8SAndroid Build Coastguard Worker unsigned int num_glyphs;
105*2d1272b8SAndroid Build Coastguard Worker unsigned int cluster;
106*2d1272b8SAndroid Build Coastguard Worker int advance;
107*2d1272b8SAndroid Build Coastguard Worker };
108*2d1272b8SAndroid Build Coastguard Worker
109*2d1272b8SAndroid Build Coastguard Worker length = glyph_count;
110*2d1272b8SAndroid Build Coastguard Worker if (!buffer_contents_realloc (&contents, length))
111*2d1272b8SAndroid Build Coastguard Worker return false;
112*2d1272b8SAndroid Build Coastguard Worker cluster_t *clusters = (cluster_t *) malloc (length * sizeof (cluster_t));
113*2d1272b8SAndroid Build Coastguard Worker uint32_t *gids = (uint32_t *) malloc (length * sizeof (uint32_t));
114*2d1272b8SAndroid Build Coastguard Worker if (!clusters || !gids)
115*2d1272b8SAndroid Build Coastguard Worker {
116*2d1272b8SAndroid Build Coastguard Worker free (clusters);
117*2d1272b8SAndroid Build Coastguard Worker free (gids);
118*2d1272b8SAndroid Build Coastguard Worker return false;
119*2d1272b8SAndroid Build Coastguard Worker }
120*2d1272b8SAndroid Build Coastguard Worker
121*2d1272b8SAndroid Build Coastguard Worker memset (clusters, 0, sizeof (clusters[0]) * length);
122*2d1272b8SAndroid Build Coastguard Worker codepoint_t *pg = gids;
123*2d1272b8SAndroid Build Coastguard Worker clusters[0].cluster = contents.info[0].cluster;
124*2d1272b8SAndroid Build Coastguard Worker unsigned int upem = face_get_upem (face);
125*2d1272b8SAndroid Build Coastguard Worker int32_t font_x_scale, font_y_scale;
126*2d1272b8SAndroid Build Coastguard Worker font_get_scale (font, &font_x_scale, &font_y_scale);
127*2d1272b8SAndroid Build Coastguard Worker float xscale = (float) font_x_scale / upem;
128*2d1272b8SAndroid Build Coastguard Worker float yscale = (float) font_y_scale / upem;
129*2d1272b8SAndroid Build Coastguard Worker yscale *= yscale / xscale;
130*2d1272b8SAndroid Build Coastguard Worker unsigned int curradv = 0;
131*2d1272b8SAndroid Build Coastguard Worker if (DIRECTION_IS_BACKWARD (direction))
132*2d1272b8SAndroid Build Coastguard Worker {
133*2d1272b8SAndroid Build Coastguard Worker curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale;
134*2d1272b8SAndroid Build Coastguard Worker clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv;
135*2d1272b8SAndroid Build Coastguard Worker }
136*2d1272b8SAndroid Build Coastguard Worker else
137*2d1272b8SAndroid Build Coastguard Worker clusters[0].advance = 0;
138*2d1272b8SAndroid Build Coastguard Worker for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
139*2d1272b8SAndroid Build Coastguard Worker {
140*2d1272b8SAndroid Build Coastguard Worker unsigned int before = gr_slot_before (is);
141*2d1272b8SAndroid Build Coastguard Worker unsigned int after = gr_slot_after (is);
142*2d1272b8SAndroid Build Coastguard Worker *pg = gr_slot_gid (is);
143*2d1272b8SAndroid Build Coastguard Worker pg++;
144*2d1272b8SAndroid Build Coastguard Worker while (clusters[ci].base_char > before && ci)
145*2d1272b8SAndroid Build Coastguard Worker {
146*2d1272b8SAndroid Build Coastguard Worker clusters[ci-1].num_chars += clusters[ci].num_chars;
147*2d1272b8SAndroid Build Coastguard Worker clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
148*2d1272b8SAndroid Build Coastguard Worker clusters[ci-1].advance += clusters[ci].advance;
149*2d1272b8SAndroid Build Coastguard Worker ci--;
150*2d1272b8SAndroid Build Coastguard Worker }
151*2d1272b8SAndroid Build Coastguard Worker
152*2d1272b8SAndroid Build Coastguard Worker if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
153*2d1272b8SAndroid Build Coastguard Worker {
154*2d1272b8SAndroid Build Coastguard Worker cluster_t *c = clusters + ci + 1;
155*2d1272b8SAndroid Build Coastguard Worker c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
156*2d1272b8SAndroid Build Coastguard Worker c->cluster = contents.info[c->base_char].cluster;
157*2d1272b8SAndroid Build Coastguard Worker c->num_chars = before - c->base_char;
158*2d1272b8SAndroid Build Coastguard Worker c->base_glyph = ic;
159*2d1272b8SAndroid Build Coastguard Worker c->num_glyphs = 0;
160*2d1272b8SAndroid Build Coastguard Worker if (DIRECTION_IS_BACKWARD (direction))
161*2d1272b8SAndroid Build Coastguard Worker {
162*2d1272b8SAndroid Build Coastguard Worker c->advance = curradv - gr_slot_origin_X(is) * xscale;
163*2d1272b8SAndroid Build Coastguard Worker curradv -= c->advance;
164*2d1272b8SAndroid Build Coastguard Worker }
165*2d1272b8SAndroid Build Coastguard Worker else
166*2d1272b8SAndroid Build Coastguard Worker {
167*2d1272b8SAndroid Build Coastguard Worker auto origin_X = gr_slot_origin_X (is) * xscale;
168*2d1272b8SAndroid Build Coastguard Worker c->advance = 0;
169*2d1272b8SAndroid Build Coastguard Worker clusters[ci].advance += origin_X - curradv;
170*2d1272b8SAndroid Build Coastguard Worker curradv = origin_X;
171*2d1272b8SAndroid Build Coastguard Worker }
172*2d1272b8SAndroid Build Coastguard Worker ci++;
173*2d1272b8SAndroid Build Coastguard Worker }
174*2d1272b8SAndroid Build Coastguard Worker clusters[ci].num_glyphs++;
175*2d1272b8SAndroid Build Coastguard Worker
176*2d1272b8SAndroid Build Coastguard Worker if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
177*2d1272b8SAndroid Build Coastguard Worker clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
178*2d1272b8SAndroid Build Coastguard Worker }
179*2d1272b8SAndroid Build Coastguard Worker
180*2d1272b8SAndroid Build Coastguard Worker if (DIRECTION_IS_BACKWARD (direction))
181*2d1272b8SAndroid Build Coastguard Worker clusters[ci].advance += curradv;
182*2d1272b8SAndroid Build Coastguard Worker else
183*2d1272b8SAndroid Build Coastguard Worker clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv;
184*2d1272b8SAndroid Build Coastguard Worker ci++;
185*2d1272b8SAndroid Build Coastguard Worker
186*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < ci; ++i)
187*2d1272b8SAndroid Build Coastguard Worker {
188*2d1272b8SAndroid Build Coastguard Worker for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
189*2d1272b8SAndroid Build Coastguard Worker {
190*2d1272b8SAndroid Build Coastguard Worker glyph_info_t *info = &contents.info[clusters[i].base_glyph + j];
191*2d1272b8SAndroid Build Coastguard Worker info->codepoint = gids[clusters[i].base_glyph + j];
192*2d1272b8SAndroid Build Coastguard Worker info->cluster = clusters[i].cluster;
193*2d1272b8SAndroid Build Coastguard Worker info->var1 = (unsigned) clusters[i].advance; // all glyphs in the cluster get the same advance
194*2d1272b8SAndroid Build Coastguard Worker }
195*2d1272b8SAndroid Build Coastguard Worker }
196*2d1272b8SAndroid Build Coastguard Worker contents.length = glyph_count;
197*2d1272b8SAndroid Build Coastguard Worker
198*2d1272b8SAndroid Build Coastguard Worker /* Positioning. */
199*2d1272b8SAndroid Build Coastguard Worker unsigned int currclus = 0xFFFFFFFF;
200*2d1272b8SAndroid Build Coastguard Worker const glyph_info_t *info = contents.info;
201*2d1272b8SAndroid Build Coastguard Worker glyph_position_t *pPos = contents.pos;
202*2d1272b8SAndroid Build Coastguard Worker if (!DIRECTION_IS_BACKWARD (direction))
203*2d1272b8SAndroid Build Coastguard Worker {
204*2d1272b8SAndroid Build Coastguard Worker curradvx = 0;
205*2d1272b8SAndroid Build Coastguard Worker for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
206*2d1272b8SAndroid Build Coastguard Worker {
207*2d1272b8SAndroid Build Coastguard Worker pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx;
208*2d1272b8SAndroid Build Coastguard Worker pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
209*2d1272b8SAndroid Build Coastguard Worker if (info->cluster != currclus) {
210*2d1272b8SAndroid Build Coastguard Worker pPos->x_advance = (int) info->var1;
211*2d1272b8SAndroid Build Coastguard Worker curradvx += pPos->x_advance;
212*2d1272b8SAndroid Build Coastguard Worker currclus = info->cluster;
213*2d1272b8SAndroid Build Coastguard Worker } else
214*2d1272b8SAndroid Build Coastguard Worker pPos->x_advance = 0.;
215*2d1272b8SAndroid Build Coastguard Worker
216*2d1272b8SAndroid Build Coastguard Worker pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
217*2d1272b8SAndroid Build Coastguard Worker curradvy += pPos->y_advance;
218*2d1272b8SAndroid Build Coastguard Worker }
219*2d1272b8SAndroid Build Coastguard Worker buffer_set_contents (buffer, &contents);
220*2d1272b8SAndroid Build Coastguard Worker }
221*2d1272b8SAndroid Build Coastguard Worker else
222*2d1272b8SAndroid Build Coastguard Worker {
223*2d1272b8SAndroid Build Coastguard Worker curradvx = gr_seg_advance_X(seg) * xscale;
224*2d1272b8SAndroid Build Coastguard Worker for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
225*2d1272b8SAndroid Build Coastguard Worker {
226*2d1272b8SAndroid Build Coastguard Worker if (info->cluster != currclus)
227*2d1272b8SAndroid Build Coastguard Worker {
228*2d1272b8SAndroid Build Coastguard Worker pPos->x_advance = (int) info->var1;
229*2d1272b8SAndroid Build Coastguard Worker curradvx -= pPos->x_advance;
230*2d1272b8SAndroid Build Coastguard Worker currclus = info->cluster;
231*2d1272b8SAndroid Build Coastguard Worker } else
232*2d1272b8SAndroid Build Coastguard Worker pPos->x_advance = 0.;
233*2d1272b8SAndroid Build Coastguard Worker
234*2d1272b8SAndroid Build Coastguard Worker pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
235*2d1272b8SAndroid Build Coastguard Worker curradvy -= pPos->y_advance;
236*2d1272b8SAndroid Build Coastguard Worker pPos->x_offset = gr_slot_origin_X (is) * xscale - (int) info->var1 - curradvx + pPos->x_advance;
237*2d1272b8SAndroid Build Coastguard Worker pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
238*2d1272b8SAndroid Build Coastguard Worker }
239*2d1272b8SAndroid Build Coastguard Worker buffer_set_contents (buffer, &contents);
240*2d1272b8SAndroid Build Coastguard Worker buffer_reverse_clusters (buffer);
241*2d1272b8SAndroid Build Coastguard Worker }
242*2d1272b8SAndroid Build Coastguard Worker
243*2d1272b8SAndroid Build Coastguard Worker gr_seg_destroy (seg);
244*2d1272b8SAndroid Build Coastguard Worker free (clusters);
245*2d1272b8SAndroid Build Coastguard Worker free (gids);
246*2d1272b8SAndroid Build Coastguard Worker
247*2d1272b8SAndroid Build Coastguard Worker bool ret = glyph_count;
248*2d1272b8SAndroid Build Coastguard Worker
249*2d1272b8SAndroid Build Coastguard Worker return ret;
250*2d1272b8SAndroid Build Coastguard Worker }
251