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