hb-ot-shape.cc revision 4e4ef24e46f273ad2bdda2f718223e05b37dd50f
1/* 2 * Copyright (C) 2009,2010 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-open-type-private.hh" 32 33#include "hb-ot-layout.h" 34 35HB_BEGIN_DECLS 36 37 38/* XXX vertical */ 39hb_tag_t default_features[] = { 40 HB_TAG('c','a','l','t'), 41 HB_TAG('c','c','m','p'), 42 HB_TAG('c','l','i','g'), 43 HB_TAG('c','s','w','h'), 44 HB_TAG('c','u','r','s'), 45 HB_TAG('k','e','r','n'), 46 HB_TAG('l','i','g','a'), 47 HB_TAG('l','o','c','l'), 48 HB_TAG('m','a','r','k'), 49 HB_TAG('m','k','m','k'), 50 HB_TAG('r','l','i','g') 51}; 52 53struct lookup_map { 54 unsigned int index; 55 hb_mask_t mask; 56}; 57 58 59static void 60add_feature (hb_face_t *face, 61 hb_tag_t table_tag, 62 unsigned int feature_index, 63 hb_mask_t mask, 64 lookup_map *lookups, 65 unsigned int *num_lookups, 66 unsigned int room_lookups) 67{ 68 unsigned int i = room_lookups - *num_lookups; 69 lookups += *num_lookups; 70 71 unsigned int *lookup_indices = (unsigned int *) lookups; 72 73 hb_ot_layout_feature_get_lookup_indexes (face, table_tag, feature_index, 0, 74 &i, 75 lookup_indices); 76 77 *num_lookups += i; 78 79 while (i--) { 80 lookups[i].mask = mask; 81 lookups[i].index = lookup_indices[i]; 82 } 83} 84 85static int 86cmp_lookups (const void *p1, const void *p2) 87{ 88 const lookup_map *a = (const lookup_map *) p1; 89 const lookup_map *b = (const lookup_map *) p2; 90 91 return a->index - b->index; 92} 93 94 95#define MAX_FEATURES 100 96 97struct hb_mask_allocator_t { 98 99 struct feature_info_t { 100 hb_tag_t tag; 101 unsigned int value; 102 unsigned int seq; 103 bool global; 104 105 static int 106 cmp (const void *p1, const void *p2) 107 { 108 const feature_info_t *a = (const feature_info_t *) p1; 109 const feature_info_t *b = (const feature_info_t *) p2; 110 111 if (a->tag != b->tag) 112 return a->tag < b->tag ? -1 : 1; 113 114 return a->seq < b->seq ? -1 : 1; 115 } 116 }; 117 118 struct feature_map_t { 119 hb_tag_t tag; /* should be first */ 120 unsigned int index; 121 unsigned int shift; 122 hb_mask_t mask; 123 124 static int 125 cmp (const void *p1, const void *p2) 126 { 127 const feature_map_t *a = (const feature_map_t *) p1; 128 const feature_map_t *b = (const feature_map_t *) p2; 129 130 return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; 131 } 132 }; 133 134 hb_mask_allocator_t (void) : count (0) {} 135 136 void add_feature (hb_tag_t tag, 137 unsigned int value, 138 bool global) 139 { 140 feature_info_t *info = &infos[count++]; 141 info->tag = tag; 142 info->value = value; 143 info->seq = count; 144 info->global = global; 145 } 146 147 void compile (hb_face_t *face, 148 hb_tag_t table_tag, 149 unsigned int script_index, 150 unsigned int language_index) 151 { 152 global_mask = 0; 153 unsigned int next_bit = 1; 154 155 if (!count) 156 return; 157 158 qsort (infos, count, sizeof (infos[0]), feature_info_t::cmp); 159 160 unsigned int j = 0; 161 for (unsigned int i = 1; i < count; i++) 162 if (infos[i].tag != infos[j].tag) 163 infos[++j] = infos[i]; 164 else { 165 if (infos[i].global) 166 infos[j] = infos[i]; 167 else { 168 infos[j].global = infos[j].global && (infos[j].value == infos[i].value); 169 infos[j].value = MAX (infos[j].value, infos[i].value); 170 } 171 } 172 count = j + 1; 173 174 /* Allocate bits now */ 175 j = 0; 176 for (unsigned int i = 0; i < count; i++) { 177 const feature_info_t *info = &infos[i]; 178 179 unsigned int bits_needed; 180 181 if (info->global && info->value == 1) 182 /* Uses the global bit */ 183 bits_needed = 0; 184 else 185 bits_needed = _hb_bit_storage (info->value); 186 187 if (!info->value || next_bit + bits_needed > 8 * sizeof (hb_mask_t)) 188 continue; /* Feature disabled, or not enough bits. */ 189 190 unsigned int feature_index; 191 if (!hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index, 192 info->tag, &feature_index)) 193 continue; 194 195 feature_map_t *map = &maps[j++]; 196 197 map->tag = info->tag; 198 map->index = feature_index; 199 if (info->global && info->value == 1) { 200 /* Uses the global bit */ 201 map->shift = 0; 202 map->mask = 1; 203 } else { 204 map->shift = next_bit; 205 map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit); 206 next_bit += bits_needed; 207 } 208 209 if (info->global && map->mask != 1) 210 global_mask |= map->mask; 211 } 212 count = j; 213 } 214 215 hb_mask_t get_global_mask (void) { return global_mask; } 216 const feature_map_t *find_feature (hb_tag_t tag) const { 217 static const feature_map_t off_map = { HB_TAG_NONE, Index::NOT_FOUND_INDEX, 0, 0 }; 218 const feature_map_t *map = (const feature_map_t *) bsearch (&tag, maps, count, sizeof (maps[0]), feature_map_t::cmp); 219 return map ? map : &off_map; 220 } 221 222 223 private: 224 225 unsigned int count; 226 feature_info_t infos[MAX_FEATURES]; 227 228 feature_map_t maps[MAX_FEATURES]; 229 hb_mask_t global_mask; 230}; 231 232static void 233setup_lookups (hb_face_t *face, 234 hb_buffer_t *buffer, 235 hb_feature_t *features, 236 unsigned int num_features, 237 hb_tag_t table_tag, 238 lookup_map *lookups, 239 unsigned int *num_lookups, 240 hb_direction_t original_direction) 241{ 242 unsigned int i, j, script_index, language_index, feature_index, room_lookups; 243 244 room_lookups = *num_lookups; 245 *num_lookups = 0; 246 247 hb_ot_layout_table_choose_script (face, table_tag, 248 hb_ot_tags_from_script (buffer->props.script), 249 &script_index); 250 hb_ot_layout_script_find_language (face, table_tag, script_index, 251 hb_ot_tag_from_language (buffer->props.language), 252 &language_index); 253 254 if (hb_ot_layout_language_get_required_feature_index (face, table_tag, script_index, language_index, 255 &feature_index)) 256 add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups); 257 258 259 hb_mask_allocator_t allocator; 260 261 switch (original_direction) { 262 case HB_DIRECTION_LTR: 263 allocator.add_feature (HB_TAG ('l','t','r','a'), 1, true); 264 allocator.add_feature (HB_TAG ('l','t','r','m'), 1, true); 265 break; 266 case HB_DIRECTION_RTL: 267 allocator.add_feature (HB_TAG ('r','t','l','a'), 1, true); 268 allocator.add_feature (HB_TAG ('r','t','l','m'), 1, false); 269 break; 270 case HB_DIRECTION_TTB: 271 case HB_DIRECTION_BTT: 272 default: 273 break; 274 } 275 276 for (i = 0; i < ARRAY_LENGTH (default_features); i++) 277 allocator.add_feature (default_features[i], 1, true); 278 279 /* XXX complex-shaper features go here */ 280 281 for (unsigned int i = 0; i < num_features; i++) { 282 const hb_feature_t *feature = &features[i]; 283 allocator.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1)); 284 } 285 286 287 /* Compile features */ 288 allocator.compile (face, table_tag, script_index, language_index); 289 290 291 /* Gather lookup indices for features and set buffer masks at the same time */ 292 293 const hb_mask_allocator_t::feature_map_t *map; 294 295 hb_mask_t global_mask = allocator.get_global_mask (); 296 if (global_mask) 297 buffer->set_masks (global_mask, global_mask, 0, (unsigned int) -1); 298 299 switch (original_direction) { 300 case HB_DIRECTION_LTR: 301 map = allocator.find_feature (HB_TAG ('l','t','r','a')); 302 add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups); 303 map = allocator.find_feature (HB_TAG ('l','t','r','m')); 304 add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups); 305 break; 306 case HB_DIRECTION_RTL: 307 map = allocator.find_feature (HB_TAG ('r','t','l','a')); 308 add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups); 309 map = allocator.find_feature (HB_TAG ('r','t','l','m')); 310 add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups); 311 break; 312 case HB_DIRECTION_TTB: 313 case HB_DIRECTION_BTT: 314 default: 315 break; 316 } 317 318 for (i = 0; i < ARRAY_LENGTH (default_features); i++) 319 { 320 map = allocator.find_feature (default_features[i]); 321 add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups); 322 } 323 324 for (i = 0; i < num_features; i++) 325 { 326 hb_feature_t *feature = &features[i]; 327 map = allocator.find_feature (feature->tag); 328 add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups); 329 if (!(feature->start == 0 && feature->end == (unsigned int)-1)) 330 buffer->set_masks (features[i].value << map->shift, map->mask, feature->start, feature->end); 331 } 332 333 334 /* Sort lookups and merge duplicates */ 335 336 qsort (lookups, *num_lookups, sizeof (lookups[0]), cmp_lookups); 337 338 if (*num_lookups) 339 { 340 for (i = 1, j = 0; i < *num_lookups; i++) 341 if (lookups[i].index != lookups[j].index) 342 lookups[++j] = lookups[i]; 343 else 344 lookups[j].mask |= lookups[i].mask; 345 j++; 346 *num_lookups = j; 347 } 348} 349 350 351static hb_bool_t 352hb_ot_substitute_complex (hb_font_t *font HB_UNUSED, 353 hb_face_t *face, 354 hb_buffer_t *buffer, 355 hb_feature_t *features, 356 unsigned int num_features, 357 hb_direction_t original_direction) 358{ 359 lookup_map lookups[1000]; /* FIXME */ 360 unsigned int num_lookups = ARRAY_LENGTH (lookups); 361 unsigned int i; 362 363 if (!hb_ot_layout_has_substitution (face)) 364 return FALSE; 365 366 setup_lookups (face, buffer, features, num_features, 367 HB_OT_TAG_GSUB, 368 lookups, &num_lookups, 369 original_direction); 370 371 for (i = 0; i < num_lookups; i++) 372 hb_ot_layout_substitute_lookup (face, buffer, lookups[i].index, lookups[i].mask); 373 374 return TRUE; 375} 376 377static hb_bool_t 378hb_ot_position_complex (hb_font_t *font, 379 hb_face_t *face, 380 hb_buffer_t *buffer, 381 hb_feature_t *features, 382 unsigned int num_features, 383 hb_direction_t original_direction) 384{ 385 lookup_map lookups[1000]; 386 unsigned int num_lookups = ARRAY_LENGTH (lookups); 387 unsigned int i; 388 389 if (!hb_ot_layout_has_positioning (face)) 390 return FALSE; 391 392 setup_lookups (face, buffer, features, num_features, 393 HB_OT_TAG_GPOS, 394 lookups, &num_lookups, 395 original_direction); 396 397 for (i = 0; i < num_lookups; i++) 398 hb_ot_layout_position_lookup (font, face, buffer, lookups[i].index, lookups[i].mask); 399 400 hb_ot_layout_position_finish (font, face, buffer); 401 402 return TRUE; 403} 404 405 406/* Main shaper */ 407 408/* Prepare */ 409 410static inline hb_bool_t 411is_variation_selector (hb_codepoint_t unicode) 412{ 413 return unlikely ((unicode >= 0x180B && unicode <= 0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */ 414 (unicode >= 0xFE00 && unicode <= 0xFE0F) || /* VARIATION SELECTOR-1..16 */ 415 (unicode >= 0xE0100 && unicode <= 0xE01EF)); /* VARIATION SELECTOR-17..256 */ 416} 417 418static void 419hb_form_clusters (hb_buffer_t *buffer) 420{ 421 unsigned int count = buffer->len; 422 for (unsigned int i = 1; i < count; i++) 423 if (buffer->unicode->v.get_general_category (buffer->info[i].codepoint) == HB_CATEGORY_NON_SPACING_MARK) 424 buffer->info[i].cluster = buffer->info[i - 1].cluster; 425} 426 427static hb_direction_t 428hb_ensure_native_direction (hb_buffer_t *buffer) 429{ 430 hb_direction_t original_direction = buffer->props.direction; 431 432 /* TODO vertical */ 433 if (HB_DIRECTION_IS_HORIZONTAL (original_direction) && 434 original_direction != _hb_script_get_horizontal_direction (buffer->props.script)) 435 { 436 hb_buffer_reverse_clusters (buffer); 437 buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction); 438 } 439 440 return original_direction; 441} 442 443 444/* Substitute */ 445 446static void 447hb_mirror_chars (hb_buffer_t *buffer) 448{ 449 hb_unicode_get_mirroring_func_t get_mirroring = buffer->unicode->v.get_mirroring; 450 451 if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) 452 return; 453 454// map = allocator.find_feature (HB_TAG ('r','t','l','m')); 455 456 unsigned int count = buffer->len; 457 for (unsigned int i = 0; i < count; i++) { 458 hb_codepoint_t codepoint = get_mirroring (buffer->info[i].codepoint); 459 if (likely (codepoint == buffer->info[i].codepoint)) 460;// buffer->info[i].mask |= map->mask; 461 else 462 buffer->info[i].codepoint = codepoint; 463 } 464} 465 466static void 467hb_map_glyphs (hb_font_t *font, 468 hb_face_t *face, 469 hb_buffer_t *buffer) 470{ 471 if (unlikely (!buffer->len)) 472 return; 473 474 buffer->clear_output (); 475 unsigned int count = buffer->len - 1; 476 for (buffer->i = 0; buffer->i < count;) { 477 if (unlikely (is_variation_selector (buffer->info[buffer->i + 1].codepoint))) { 478 buffer->add_output_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, buffer->info[buffer->i + 1].codepoint)); 479 buffer->i++; 480 } else { 481 buffer->add_output_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0)); 482 } 483 } 484 if (likely (buffer->i < buffer->len)) 485 buffer->add_output_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0)); 486 buffer->swap (); 487} 488 489static void 490hb_substitute_default (hb_font_t *font, 491 hb_face_t *face, 492 hb_buffer_t *buffer, 493 hb_feature_t *features HB_UNUSED, 494 unsigned int num_features HB_UNUSED) 495{ 496 hb_map_glyphs (font, face, buffer); 497} 498 499static void 500hb_substitute_complex_fallback (hb_font_t *font HB_UNUSED, 501 hb_face_t *face HB_UNUSED, 502 hb_buffer_t *buffer HB_UNUSED, 503 hb_feature_t *features HB_UNUSED, 504 unsigned int num_features HB_UNUSED) 505{ 506 /* TODO Arabic */ 507} 508 509 510/* Position */ 511 512static void 513hb_position_default (hb_font_t *font, 514 hb_face_t *face, 515 hb_buffer_t *buffer, 516 hb_feature_t *features HB_UNUSED, 517 unsigned int num_features HB_UNUSED) 518{ 519 hb_buffer_clear_positions (buffer); 520 521 unsigned int count = buffer->len; 522 for (unsigned int i = 0; i < count; i++) { 523 hb_glyph_metrics_t metrics; 524 hb_font_get_glyph_metrics (font, face, buffer->info[i].codepoint, &metrics); 525 buffer->pos[i].x_advance = metrics.x_advance; 526 buffer->pos[i].y_advance = metrics.y_advance; 527 } 528} 529 530static void 531hb_position_complex_fallback (hb_font_t *font HB_UNUSED, 532 hb_face_t *face HB_UNUSED, 533 hb_buffer_t *buffer HB_UNUSED, 534 hb_feature_t *features HB_UNUSED, 535 unsigned int num_features HB_UNUSED) 536{ 537 /* TODO Mark pos */ 538} 539 540static void 541hb_truetype_kern (hb_font_t *font, 542 hb_face_t *face, 543 hb_buffer_t *buffer, 544 hb_feature_t *features HB_UNUSED, 545 unsigned int num_features HB_UNUSED) 546{ 547 /* TODO Check for kern=0 */ 548 unsigned int count = buffer->len; 549 for (unsigned int i = 1; i < count; i++) { 550 hb_position_t kern, kern1, kern2; 551 kern = hb_font_get_kerning (font, face, buffer->info[i - 1].codepoint, buffer->info[i].codepoint); 552 kern1 = kern >> 1; 553 kern2 = kern - kern1; 554 buffer->pos[i - 1].x_advance += kern1; 555 buffer->pos[i].x_advance += kern2; 556 buffer->pos[i].x_offset += kern2; 557 } 558} 559 560static void 561hb_position_complex_fallback_visual (hb_font_t *font, 562 hb_face_t *face, 563 hb_buffer_t *buffer, 564 hb_feature_t *features, 565 unsigned int num_features) 566{ 567 hb_truetype_kern (font, face, buffer, features, num_features); 568} 569 570 571/* Do it! */ 572 573void 574hb_ot_shape (hb_font_t *font, 575 hb_face_t *face, 576 hb_buffer_t *buffer, 577 hb_feature_t *features, 578 unsigned int num_features) 579{ 580 hb_direction_t original_direction; 581 hb_bool_t substitute_fallback, position_fallback; 582 583 hb_form_clusters (buffer); 584 585 /* SUBSTITUTE */ 586 { 587 buffer->clear_masks (); 588 589 /* Mirroring needs to see the original direction */ 590 hb_mirror_chars (buffer); 591 592 original_direction = hb_ensure_native_direction (buffer); 593 594 hb_substitute_default (font, face, buffer, features, num_features); 595 596 substitute_fallback = !hb_ot_substitute_complex (font, face, buffer, features, num_features, original_direction); 597 598 if (substitute_fallback) 599 hb_substitute_complex_fallback (font, face, buffer, features, num_features); 600 } 601 602 /* POSITION */ 603 { 604 buffer->clear_masks (); 605 606 hb_position_default (font, face, buffer, features, num_features); 607 608 position_fallback = !hb_ot_position_complex (font, face, buffer, features, num_features, original_direction); 609 610 if (position_fallback) 611 hb_position_complex_fallback (font, face, buffer, features, num_features); 612 613 if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) 614 hb_buffer_reverse (buffer); 615 616 if (position_fallback) 617 hb_position_complex_fallback_visual (font, face, buffer, features, num_features); 618 } 619 620 buffer->props.direction = original_direction; 621} 622 623 624HB_END_DECLS 625