hb-ot-shape.cc revision 9722b8f005a10fd16e841df4da3ccd80be66e296
1/* 2 * Copyright (C) 2009 Red Hat, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Red Hat Author(s): Behdad Esfahbod 25 */ 26 27#include "hb-ot-shape.h" 28 29#include "hb-buffer-private.hh" 30 31#include "hb-ot-layout.h" 32 33hb_tag_t default_features[] = { 34 /* GSUB */ 35 HB_TAG('c','c','m','p'), 36 HB_TAG('l','o','c','l'), 37 HB_TAG('l','i','g','a'), 38 HB_TAG('c','l','i','g'), 39 /* GPOS */ 40 HB_TAG('k','e','r','n'), 41 HB_TAG('m','a','r','k'), 42 HB_TAG('m','k','m','k'), 43}; 44 45struct lookup_map { 46 unsigned int index; 47 hb_mask_t mask; 48}; 49 50 51static void 52add_feature (hb_face_t *face, 53 hb_tag_t table_tag, 54 unsigned int feature_index, 55 hb_mask_t mask, 56 lookup_map *lookups, 57 unsigned int *num_lookups, 58 unsigned int room_lookups) 59{ 60 unsigned int i = room_lookups - *num_lookups; 61 lookups += *num_lookups; 62 63 unsigned int *lookup_indices = (unsigned int *) lookups; 64 65 hb_ot_layout_feature_get_lookup_indexes (face, table_tag, feature_index, 0, 66 &i, 67 lookup_indices); 68 69 *num_lookups += i; 70 71 while (i--) { 72 lookups[i].mask = mask; 73 lookups[i].index = lookup_indices[i]; 74 } 75} 76 77static int 78cmp_lookups (const void *p1, const void *p2) 79{ 80 const lookup_map *a = (const lookup_map *) p1; 81 const lookup_map *b = (const lookup_map *) p2; 82 83 return a->index - b->index; 84} 85 86static void 87setup_lookups (hb_face_t *face, 88 hb_buffer_t *buffer, 89 hb_feature_t *features, 90 unsigned int num_features, 91 hb_tag_t table_tag, 92 lookup_map *lookups, 93 unsigned int *num_lookups) 94{ 95 unsigned int i, j, script_index, language_index, feature_index, room_lookups; 96 97 room_lookups = *num_lookups; 98 *num_lookups = 0; 99 100 hb_ot_layout_table_choose_script (face, table_tag, 101 hb_ot_tags_from_script (buffer->script), 102 &script_index); 103 hb_ot_layout_script_find_language (face, table_tag, script_index, 104 hb_ot_tag_from_language (buffer->language), 105 &language_index); 106 107 if (hb_ot_layout_language_get_required_feature_index (face, table_tag, script_index, language_index, 108 &feature_index)) 109 add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups); 110 111 for (i = 0; i < ARRAY_LENGTH (default_features); i++) 112 { 113 if (hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index, 114 default_features[i], 115 &feature_index)) 116 add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups); 117 } 118 119 /* Clear buffer masks. */ 120 unsigned int count = buffer->len; 121 for (unsigned int i = 0; i < count; i++) 122 buffer->info[i].mask = 1; 123 124 unsigned int last_bit_used = 1; 125 unsigned int global_values = 0; 126 for (i = 0; i < num_features; i++) 127 { 128 if (!hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index, 129 features[i].tag, 130 &feature_index)) 131 continue; 132 133 unsigned int bits_needed = _hb_bit_storage (features[i].value); 134 if (!bits_needed) 135 continue; 136 unsigned int mask = (1 << (last_bit_used + bits_needed)) - (1 << last_bit_used); 137 unsigned int value = features[i].value << last_bit_used; 138 last_bit_used += bits_needed; 139 140 add_feature (face, table_tag, feature_index, mask, lookups, num_lookups, room_lookups); 141 142 if (features[i].start == 0 && features[i].end == (unsigned int)-1) 143 global_values |= value; 144 else 145 { 146 unsigned int start = features[i].start, end = features[i].end; 147 unsigned int a = 0, b = buffer->len; 148 while (a < b) 149 { 150 unsigned int h = a + ((b - a) / 2); 151 if (buffer->info[h].cluster < start) 152 a = h + 1; 153 else 154 b = h; 155 } 156 unsigned int count = buffer->len; 157 for (unsigned int j = a; j < count && buffer->info[j].cluster < end; j++) 158 buffer->info[j].mask |= value; 159 } 160 } 161 162 if (global_values) 163 { 164 unsigned int count = buffer->len; 165 for (unsigned int j = 0; j < count; j++) 166 buffer->info[j].mask |= global_values; 167 } 168 169 qsort (lookups, *num_lookups, sizeof (lookups[0]), cmp_lookups); 170 171 if (*num_lookups) 172 { 173 for (i = 1, j = 0; i < *num_lookups; i++) 174 if (lookups[i].index != lookups[j].index) 175 lookups[++j] = lookups[i]; 176 else 177 lookups[j].mask |= lookups[i].mask; 178 j++; 179 *num_lookups = j; 180 } 181} 182 183 184static hb_bool_t 185hb_ot_substitute_complex (hb_font_t *font HB_UNUSED, 186 hb_face_t *face, 187 hb_buffer_t *buffer, 188 hb_feature_t *features, 189 unsigned int num_features) 190{ 191 lookup_map lookups[1000]; 192 unsigned int num_lookups = ARRAY_LENGTH (lookups); 193 unsigned int i; 194 195 if (!hb_ot_layout_has_substitution (face)) 196 return FALSE; 197 198 setup_lookups (face, buffer, features, num_features, 199 HB_OT_TAG_GSUB, 200 lookups, &num_lookups); 201 202 for (i = 0; i < num_lookups; i++) 203 hb_ot_layout_substitute_lookup (face, buffer, lookups[i].index, lookups[i].mask); 204 205 return TRUE; 206} 207 208static hb_bool_t 209hb_ot_position_complex (hb_font_t *font, 210 hb_face_t *face, 211 hb_buffer_t *buffer, 212 hb_feature_t *features, 213 unsigned int num_features) 214{ 215 lookup_map lookups[1000]; 216 unsigned int num_lookups = ARRAY_LENGTH (lookups); 217 unsigned int i; 218 219 if (!hb_ot_layout_has_positioning (face)) 220 return FALSE; 221 222 setup_lookups (face, buffer, features, num_features, 223 HB_OT_TAG_GPOS, 224 lookups, &num_lookups); 225 226 for (i = 0; i < num_lookups; i++) 227 hb_ot_layout_position_lookup (font, face, buffer, lookups[i].index, lookups[i].mask); 228 229 hb_ot_layout_position_finish (font, face, buffer); 230 231 return TRUE; 232} 233 234 235/* Main shaper */ 236 237/* Prepare */ 238 239static inline hb_bool_t 240is_variation_selector (hb_codepoint_t unicode) 241{ 242 return unlikely ((unicode >= 0x180B && unicode <= 0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */ 243 (unicode >= 0xFE00 && unicode <= 0xFE0F) || /* VARIATION SELECTOR-1..16 */ 244 (unicode >= 0xE0100 && unicode <= 0xE01EF)); /* VARIATION SELECTOR-17..256 */ 245} 246 247static void 248hb_form_clusters (hb_buffer_t *buffer) 249{ 250 unsigned int count = buffer->len; 251 for (unsigned int i = 1; i < count; i++) 252 if (buffer->unicode->get_general_category (buffer->info[i].codepoint) == HB_CATEGORY_NON_SPACING_MARK) 253 buffer->info[i].cluster = buffer->info[i - 1].cluster; 254} 255 256static hb_direction_t 257hb_ensure_native_direction (hb_buffer_t *buffer) 258{ 259 hb_direction_t original_direction = buffer->direction; 260 261 /* TODO vertical */ 262 if (HB_DIRECTION_IS_HORIZONTAL (original_direction) && 263 original_direction != _hb_script_get_horizontal_direction (buffer->script)) 264 { 265 hb_buffer_reverse_clusters (buffer); 266 buffer->direction = HB_DIRECTION_REVERSE (buffer->direction); 267 } 268 269 return original_direction; 270} 271 272 273/* Substitute */ 274 275static void 276hb_mirror_chars (hb_buffer_t *buffer) 277{ 278 hb_unicode_get_mirroring_func_t get_mirroring = buffer->unicode->get_mirroring; 279 280 if (HB_DIRECTION_IS_FORWARD (buffer->direction)) 281 return; 282 283 unsigned int count = buffer->len; 284 for (unsigned int i = 0; i < count; i++) { 285 buffer->info[i].codepoint = get_mirroring (buffer->info[i].codepoint); 286 } 287} 288 289static void 290hb_map_glyphs (hb_font_t *font, 291 hb_face_t *face, 292 hb_buffer_t *buffer) 293{ 294 if (unlikely (!buffer->len)) 295 return; 296 297 unsigned int count = buffer->len - 1; 298 for (unsigned int i = 0; i < count; i++) { 299 if (unlikely (is_variation_selector (buffer->info[i + 1].codepoint))) { 300 buffer->info[i].codepoint = hb_font_get_glyph (font, face, buffer->info[i].codepoint, buffer->info[i + 1].codepoint); 301 i++; 302 } else { 303 buffer->info[i].codepoint = hb_font_get_glyph (font, face, buffer->info[i].codepoint, 0); 304 } 305 } 306 buffer->info[count].codepoint = hb_font_get_glyph (font, face, buffer->info[count].codepoint, 0); 307} 308 309static void 310hb_substitute_default (hb_font_t *font, 311 hb_face_t *face, 312 hb_buffer_t *buffer, 313 hb_feature_t *features HB_UNUSED, 314 unsigned int num_features HB_UNUSED) 315{ 316 hb_mirror_chars (buffer); 317 hb_map_glyphs (font, face, buffer); 318} 319 320static void 321hb_substitute_complex_fallback (hb_font_t *font HB_UNUSED, 322 hb_face_t *face HB_UNUSED, 323 hb_buffer_t *buffer HB_UNUSED, 324 hb_feature_t *features HB_UNUSED, 325 unsigned int num_features HB_UNUSED) 326{ 327 /* TODO Arabic */ 328} 329 330 331/* Position */ 332 333static void 334hb_position_default (hb_font_t *font, 335 hb_face_t *face, 336 hb_buffer_t *buffer, 337 hb_feature_t *features HB_UNUSED, 338 unsigned int num_features HB_UNUSED) 339{ 340 hb_buffer_clear_positions (buffer); 341 342 unsigned int count = buffer->len; 343 for (unsigned int i = 0; i < count; i++) { 344 hb_glyph_metrics_t metrics; 345 hb_font_get_glyph_metrics (font, face, buffer->info[i].codepoint, &metrics); 346 buffer->pos[i].x_advance = metrics.x_advance; 347 buffer->pos[i].y_advance = metrics.y_advance; 348 } 349} 350 351static void 352hb_position_complex_fallback (hb_font_t *font HB_UNUSED, 353 hb_face_t *face HB_UNUSED, 354 hb_buffer_t *buffer HB_UNUSED, 355 hb_feature_t *features HB_UNUSED, 356 unsigned int num_features HB_UNUSED) 357{ 358 /* TODO Mark pos */ 359} 360 361static void 362hb_truetype_kern (hb_font_t *font, 363 hb_face_t *face, 364 hb_buffer_t *buffer, 365 hb_feature_t *features HB_UNUSED, 366 unsigned int num_features HB_UNUSED) 367{ 368 /* TODO Check for kern=0 */ 369 unsigned int count = buffer->len; 370 for (unsigned int i = 1; i < count; i++) { 371 hb_position_t kern, kern1, kern2; 372 kern = hb_font_get_kerning (font, face, buffer->info[i - 1].codepoint, buffer->info[i].codepoint); 373 kern1 = kern >> 1; 374 kern2 = kern - kern1; 375 buffer->pos[i - 1].x_advance += kern1; 376 buffer->pos[i].x_advance += kern2; 377 buffer->pos[i].x_offset += kern2; 378 } 379} 380 381static void 382hb_position_complex_fallback_visual (hb_font_t *font, 383 hb_face_t *face, 384 hb_buffer_t *buffer, 385 hb_feature_t *features, 386 unsigned int num_features) 387{ 388 hb_truetype_kern (font, face, buffer, features, num_features); 389} 390 391 392/* Do it! */ 393 394void 395hb_ot_shape (hb_font_t *font, 396 hb_face_t *face, 397 hb_buffer_t *buffer, 398 hb_feature_t *features, 399 unsigned int num_features) 400{ 401 hb_direction_t original_direction; 402 hb_bool_t substitute_fallback, position_fallback; 403 404 hb_form_clusters (buffer); 405 406 hb_substitute_default (font, face, buffer, features, num_features); 407 408 /* We do this after substitute_default because mirroring needs to 409 * see the original direction. */ 410 original_direction = hb_ensure_native_direction (buffer); 411 412 substitute_fallback = !hb_ot_substitute_complex (font, face, buffer, features, num_features); 413 414 if (substitute_fallback) 415 hb_substitute_complex_fallback (font, face, buffer, features, num_features); 416 417 hb_position_default (font, face, buffer, features, num_features); 418 419 position_fallback = !hb_ot_position_complex (font, face, buffer, features, num_features); 420 421 if (position_fallback) 422 hb_position_complex_fallback (font, face, buffer, features, num_features); 423 424 if (HB_DIRECTION_IS_BACKWARD (buffer->direction)) 425 hb_buffer_reverse (buffer); 426 427 if (position_fallback) 428 hb_position_complex_fallback_visual (font, face, buffer, features, num_features); 429 430 buffer->direction = original_direction; 431} 432