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