hb-ot-shape.cc revision 3aeee519f0b82df5263974945ae852badc4dbded
1/* 2 * Copyright © 2009,2010 Red Hat, Inc. 3 * Copyright © 2010,2011,2012 Google, Inc. 4 * 5 * This is part of HarfBuzz, a text shaping library. 6 * 7 * Permission is hereby granted, without written agreement and without 8 * license or royalty fees, to use, copy, modify, and distribute this 9 * software and its documentation for any purpose, provided that the 10 * above copyright notice and the following two paragraphs appear in 11 * all copies of this software. 12 * 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17 * DAMAGE. 18 * 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24 * 25 * Red Hat Author(s): Behdad Esfahbod 26 * Google Author(s): Behdad Esfahbod 27 */ 28 29#define HB_SHAPER ot 30#define hb_ot_shaper_face_data_t hb_ot_layout_t 31#define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t 32#include "hb-shaper-impl-private.hh" 33 34#include "hb-ot-shape-private.hh" 35#include "hb-ot-shape-complex-private.hh" 36#include "hb-ot-shape-fallback-private.hh" 37#include "hb-ot-shape-normalize-private.hh" 38 39#include "hb-ot-layout-private.hh" 40#include "hb-set-private.hh" 41 42 43static hb_tag_t common_features[] = { 44 HB_TAG('c','c','m','p'), 45 HB_TAG('l','i','g','a'), 46 HB_TAG('l','o','c','l'), 47 HB_TAG('m','a','r','k'), 48 HB_TAG('m','k','m','k'), 49 HB_TAG('r','l','i','g'), 50}; 51 52 53static hb_tag_t horizontal_features[] = { 54 HB_TAG('c','a','l','t'), 55 HB_TAG('c','l','i','g'), 56 HB_TAG('c','u','r','s'), 57 HB_TAG('k','e','r','n'), 58 HB_TAG('r','c','l','t'), 59}; 60 61static hb_tag_t vertical_features[] = { 62 HB_TAG('v','e','r','t'), 63}; 64 65 66 67static void 68hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, 69 const hb_segment_properties_t *props, 70 const hb_feature_t *user_features, 71 unsigned int num_user_features) 72{ 73 hb_ot_map_builder_t *map = &planner->map; 74 75 switch (props->direction) { 76 case HB_DIRECTION_LTR: 77 map->add_global_bool_feature (HB_TAG ('l','t','r','a')); 78 map->add_global_bool_feature (HB_TAG ('l','t','r','m')); 79 break; 80 case HB_DIRECTION_RTL: 81 map->add_global_bool_feature (HB_TAG ('r','t','l','a')); 82 map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE); 83 break; 84 case HB_DIRECTION_TTB: 85 case HB_DIRECTION_BTT: 86 case HB_DIRECTION_INVALID: 87 default: 88 break; 89 } 90 91 map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE); 92 map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE); 93 map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE); 94 95 if (planner->shaper->collect_features) 96 planner->shaper->collect_features (planner); 97 98 for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) 99 map->add_global_bool_feature (common_features[i]); 100 101 if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) 102 for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) 103 map->add_feature (horizontal_features[i], 1, F_GLOBAL | 104 (horizontal_features[i] == HB_TAG('k','e','r','n') ? 105 F_HAS_FALLBACK : F_NONE)); 106 else 107 for (unsigned int i = 0; i < ARRAY_LENGTH (vertical_features); i++) 108 map->add_feature (vertical_features[i], 1, F_GLOBAL | 109 (vertical_features[i] == HB_TAG('v','k','r','n') ? 110 F_HAS_FALLBACK : F_NONE)); 111 112 if (planner->shaper->override_features) 113 planner->shaper->override_features (planner); 114 115 for (unsigned int i = 0; i < num_user_features; i++) { 116 const hb_feature_t *feature = &user_features[i]; 117 map->add_feature (feature->tag, feature->value, 118 (feature->start == 0 && feature->end == (unsigned int) -1) ? 119 F_GLOBAL : F_NONE); 120 } 121} 122 123 124/* 125 * shaper face data 126 */ 127 128hb_ot_shaper_face_data_t * 129_hb_ot_shaper_face_data_create (hb_face_t *face) 130{ 131 return _hb_ot_layout_create (face); 132} 133 134void 135_hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data) 136{ 137 _hb_ot_layout_destroy (data); 138} 139 140 141/* 142 * shaper font data 143 */ 144 145struct hb_ot_shaper_font_data_t {}; 146 147hb_ot_shaper_font_data_t * 148_hb_ot_shaper_font_data_create (hb_font_t *font) 149{ 150 return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; 151} 152 153void 154_hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data) 155{ 156} 157 158 159/* 160 * shaper shape_plan data 161 */ 162 163hb_ot_shaper_shape_plan_data_t * 164_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan, 165 const hb_feature_t *user_features, 166 unsigned int num_user_features) 167{ 168 hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t)); 169 if (unlikely (!plan)) 170 return NULL; 171 172 hb_ot_shape_planner_t planner (shape_plan); 173 174 planner.shaper = hb_ot_shape_complex_categorize (&planner); 175 176 hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features); 177 178 planner.compile (*plan); 179 180 if (plan->shaper->data_create) { 181 plan->data = plan->shaper->data_create (plan); 182 if (unlikely (!plan->data)) 183 return NULL; 184 } 185 186 return plan; 187} 188 189void 190_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan) 191{ 192 if (plan->shaper->data_destroy) 193 plan->shaper->data_destroy (const_cast<void *> (plan->data)); 194 195 plan->finish (); 196 197 free (plan); 198} 199 200 201/* 202 * shaper 203 */ 204 205struct hb_ot_shape_context_t 206{ 207 hb_ot_shape_plan_t *plan; 208 hb_font_t *font; 209 hb_face_t *face; 210 hb_buffer_t *buffer; 211 const hb_feature_t *user_features; 212 unsigned int num_user_features; 213 214 /* Transient stuff */ 215 hb_direction_t target_direction; 216}; 217 218 219 220/* Main shaper */ 221 222 223/* Prepare */ 224 225static void 226hb_set_unicode_props (hb_buffer_t *buffer) 227{ 228 unsigned int count = buffer->len; 229 for (unsigned int i = 0; i < count; i++) 230 _hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode); 231} 232 233static void 234hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) 235{ 236 if (!(buffer->flags & HB_BUFFER_FLAG_BOT) || 237 _hb_glyph_info_get_general_category (&buffer->info[0]) != 238 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 239 return; 240 241 hb_codepoint_t dottedcircle_glyph; 242 if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) 243 return; 244 245 hb_glyph_info_t dottedcircle; 246 dottedcircle.codepoint = 0x25CC; 247 _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode); 248 249 buffer->clear_output (); 250 251 buffer->idx = 0; 252 hb_glyph_info_t info = dottedcircle; 253 info.cluster = buffer->cur().cluster; 254 info.mask = buffer->cur().mask; 255 buffer->output_info (info); 256 while (buffer->idx < buffer->len) 257 buffer->next_glyph (); 258 259 buffer->swap_buffers (); 260} 261 262static void 263hb_form_clusters (hb_buffer_t *buffer) 264{ 265 unsigned int count = buffer->len; 266 for (unsigned int i = 1; i < count; i++) 267 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i]))) 268 buffer->merge_clusters (i - 1, i + 1); 269} 270 271static void 272hb_ensure_native_direction (hb_buffer_t *buffer) 273{ 274 hb_direction_t direction = buffer->props.direction; 275 276 /* TODO vertical: 277 * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType 278 * Ogham fonts are supposed to be implemented BTT or not. Need to research that 279 * first. */ 280 if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) || 281 (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB)) 282 { 283 hb_buffer_reverse_clusters (buffer); 284 buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction); 285 } 286} 287 288 289/* Substitute */ 290 291static inline void 292hb_ot_mirror_chars (hb_ot_shape_context_t *c) 293{ 294 if (HB_DIRECTION_IS_FORWARD (c->target_direction)) 295 return; 296 297 hb_buffer_t *buffer = c->buffer; 298 hb_unicode_funcs_t *unicode = buffer->unicode; 299 hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m')); 300 301 unsigned int count = buffer->len; 302 hb_glyph_info_t *info = buffer->info; 303 for (unsigned int i = 0; i < count; i++) { 304 hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint); 305 if (likely (codepoint == info[i].codepoint)) 306 info[i].mask |= rtlm_mask; 307 else 308 info[i].codepoint = codepoint; 309 } 310} 311 312static inline void 313hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c) 314{ 315 hb_buffer_t *buffer = c->buffer; 316 bool initialized = false; 317 hb_mask_t frac_mask = 0, numr_mask = 0, dnom_mask = 0; 318 319 /* TODO look in pre/post context text also. */ 320 unsigned int count = buffer->len; 321 hb_glyph_info_t *info = buffer->info; 322 for (unsigned int i = 0; i < count; i++) 323 { 324 if (info[i].codepoint == 0x2044) /* FRACTION SLASH */ 325 { 326 if (!initialized) 327 { 328 initialized = true; 329 330 frac_mask = c->plan->map.get_1_mask (HB_TAG ('f','r','a','c')); 331 numr_mask = c->plan->map.get_1_mask (HB_TAG ('n','u','m','r')); 332 dnom_mask = c->plan->map.get_1_mask (HB_TAG ('d','n','o','m')); 333 334 if (!(frac_mask | numr_mask | dnom_mask)) 335 return; 336 } 337 338 unsigned int start = i, end = i + 1; 339 while (start && 340 _hb_glyph_info_get_general_category (&info[start - 1]) == 341 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) 342 start--; 343 while (end < count && 344 _hb_glyph_info_get_general_category (&info[end]) == 345 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) 346 end++; 347 348 buffer->set_masks (frac_mask, frac_mask, start, end); 349 buffer->set_masks (numr_mask, numr_mask, start, i); 350 buffer->set_masks (dnom_mask, dnom_mask, i + 1, end); 351 352 i = end - 1; 353 } 354 } 355} 356 357static inline void 358hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c) 359{ 360 hb_ot_map_t *map = &c->plan->map; 361 hb_buffer_t *buffer = c->buffer; 362 363 hb_mask_t global_mask = map->get_global_mask (); 364 buffer->reset_masks (global_mask); 365} 366 367static inline void 368hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) 369{ 370 hb_ot_map_t *map = &c->plan->map; 371 hb_buffer_t *buffer = c->buffer; 372 373 hb_ot_shape_setup_masks_fraction (c); 374 375 if (c->plan->shaper->setup_masks) 376 c->plan->shaper->setup_masks (c->plan, buffer, c->font); 377 378 for (unsigned int i = 0; i < c->num_user_features; i++) 379 { 380 const hb_feature_t *feature = &c->user_features[i]; 381 if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { 382 unsigned int shift; 383 hb_mask_t mask = map->get_mask (feature->tag, &shift); 384 buffer->set_masks (feature->value << shift, mask, feature->start, feature->end); 385 } 386 } 387} 388 389static inline void 390hb_ot_map_glyphs_fast (hb_buffer_t *buffer) 391{ 392 /* Normalization process sets up glyph_index(), we just copy it. */ 393 unsigned int count = buffer->len; 394 for (unsigned int i = 0; i < count; i++) 395 buffer->info[i].codepoint = buffer->info[i].glyph_index(); 396} 397 398static inline void 399hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) 400{ 401 unsigned int count = c->buffer->len; 402 hb_glyph_info_t *info = c->buffer->info; 403 for (unsigned int i = 0; i < count; i++) 404 _hb_glyph_info_set_glyph_props (&info[i], 405 _hb_glyph_info_get_general_category (&info[i]) 406 == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ? 407 HB_OT_LAYOUT_GLYPH_PROPS_MARK : 408 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH); 409} 410 411static inline void 412hb_ot_substitute_default (hb_ot_shape_context_t *c) 413{ 414 hb_buffer_t *buffer = c->buffer; 415 416 if (c->plan->shaper->preprocess_text) 417 c->plan->shaper->preprocess_text (c->plan, buffer, c->font); 418 419 hb_ot_shape_initialize_masks (c); 420 421 hb_ot_mirror_chars (c); 422 423 HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index); 424 425 _hb_ot_shape_normalize (c->plan, buffer, c->font); 426 427 hb_ot_shape_setup_masks (c); 428 429 /* This is unfortunate to go here, but necessary... */ 430 if (!hb_ot_layout_has_positioning (c->face)) 431 _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer); 432 433 hb_ot_map_glyphs_fast (buffer); 434 435 HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index); 436} 437 438static inline void 439hb_ot_substitute_complex (hb_ot_shape_context_t *c) 440{ 441 hb_buffer_t *buffer = c->buffer; 442 443 hb_ot_layout_substitute_start (c->font, buffer); 444 445 if (!hb_ot_layout_has_glyph_classes (c->face)) 446 hb_synthesize_glyph_classes (c); 447 448 c->plan->substitute (c->font, buffer); 449 450 hb_ot_layout_substitute_finish (c->font, buffer); 451 452 return; 453} 454 455static inline void 456hb_ot_substitute (hb_ot_shape_context_t *c) 457{ 458 hb_ot_substitute_default (c); 459 hb_ot_substitute_complex (c); 460} 461 462/* Position */ 463 464static inline void 465zero_mark_widths_by_unicode (hb_buffer_t *buffer) 466{ 467 unsigned int count = buffer->len; 468 for (unsigned int i = 0; i < count; i++) 469 if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 470 { 471 buffer->pos[i].x_advance = 0; 472 buffer->pos[i].y_advance = 0; 473 } 474} 475 476static inline void 477zero_mark_widths_by_gdef (hb_buffer_t *buffer) 478{ 479 unsigned int count = buffer->len; 480 for (unsigned int i = 0; i < count; i++) 481 if (_hb_glyph_info_is_mark (&buffer->info[i])) 482 { 483 buffer->pos[i].x_advance = 0; 484 buffer->pos[i].y_advance = 0; 485 } 486} 487 488static inline void 489hb_ot_position_default (hb_ot_shape_context_t *c) 490{ 491 hb_direction_t direction = c->buffer->props.direction; 492 unsigned int count = c->buffer->len; 493 hb_glyph_info_t *info = c->buffer->info; 494 hb_glyph_position_t *pos = c->buffer->pos; 495 for (unsigned int i = 0; i < count; i++) 496 { 497 c->font->get_glyph_advance_for_direction (info[i].codepoint, 498 direction, 499 &pos[i].x_advance, 500 &pos[i].y_advance); 501 c->font->subtract_glyph_origin_for_direction (info[i].codepoint, 502 direction, 503 &pos[i].x_offset, 504 &pos[i].y_offset); 505 506 } 507} 508 509static inline bool 510hb_ot_position_complex (hb_ot_shape_context_t *c) 511{ 512 bool ret = false; 513 unsigned int count = c->buffer->len; 514 515 switch (c->plan->shaper->zero_width_marks) 516 { 517 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: 518 zero_mark_widths_by_gdef (c->buffer); 519 break; 520 521 /* Not currently used for any shaper: 522 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY: 523 zero_mark_widths_by_unicode (c->buffer); 524 break; 525 */ 526 527 default: 528 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: 529 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE: 530 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: 531 break; 532 } 533 534 if (hb_ot_layout_has_positioning (c->face)) 535 { 536 hb_glyph_info_t *info = c->buffer->info; 537 hb_glyph_position_t *pos = c->buffer->pos; 538 539 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */ 540 541 for (unsigned int i = 0; i < count; i++) { 542 c->font->add_glyph_origin_for_direction (info[i].codepoint, 543 HB_DIRECTION_LTR, 544 &pos[i].x_offset, 545 &pos[i].y_offset); 546 } 547 548 c->plan->position (c->font, c->buffer); 549 550 for (unsigned int i = 0; i < count; i++) { 551 c->font->subtract_glyph_origin_for_direction (info[i].codepoint, 552 HB_DIRECTION_LTR, 553 &pos[i].x_offset, 554 &pos[i].y_offset); 555 } 556 557 ret = true; 558 } 559 560 switch (c->plan->shaper->zero_width_marks) 561 { 562 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE: 563 zero_mark_widths_by_unicode (c->buffer); 564 break; 565 566 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: 567 zero_mark_widths_by_gdef (c->buffer); 568 break; 569 570 default: 571 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: 572 //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY: 573 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: 574 break; 575 } 576 577 return ret; 578} 579 580static inline void 581hb_ot_position (hb_ot_shape_context_t *c) 582{ 583 hb_ot_layout_position_start (c->font, c->buffer); 584 585 hb_ot_position_default (c); 586 587 hb_bool_t fallback = !hb_ot_position_complex (c); 588 589 hb_ot_layout_position_finish (c->font, c->buffer); 590 591 if (fallback && c->plan->shaper->fallback_position) 592 _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); 593 594 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) 595 hb_buffer_reverse (c->buffer); 596 597 /* Visual fallback goes here. */ 598 599 if (fallback) 600 _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); 601} 602 603 604/* Post-process */ 605 606static void 607hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) 608{ 609 if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) 610 return; 611 612 hb_codepoint_t space; 613 enum { 614 SPACE_DONT_KNOW, 615 SPACE_AVAILABLE, 616 SPACE_UNAVAILABLE 617 } space_status = SPACE_DONT_KNOW; 618 619 unsigned int count = c->buffer->len; 620 hb_glyph_info_t *info = c->buffer->info; 621 hb_glyph_position_t *pos = c->buffer->pos; 622 unsigned int j = 0; 623 for (unsigned int i = 0; i < count; i++) 624 { 625 if (unlikely (!_hb_glyph_info_ligated (&info[i]) && 626 _hb_glyph_info_is_default_ignorable (&info[i]))) 627 { 628 if (space_status == SPACE_DONT_KNOW) 629 space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE; 630 631 if (space_status == SPACE_AVAILABLE) 632 { 633 info[i].codepoint = space; 634 pos[i].x_advance = 0; 635 pos[i].y_advance = 0; 636 } 637 else 638 continue; /* Delete it. */ 639 } 640 if (j != i) 641 { 642 info[j] = info[i]; 643 pos[j] = pos[i]; 644 } 645 j++; 646 } 647 c->buffer->len = j; 648} 649 650 651/* Pull it all together! */ 652 653static void 654hb_ot_shape_internal (hb_ot_shape_context_t *c) 655{ 656 c->buffer->deallocate_var_all (); 657 658 /* Save the original direction, we use it later. */ 659 c->target_direction = c->buffer->props.direction; 660 661 _hb_buffer_allocate_unicode_vars (c->buffer); 662 663 c->buffer->clear_output (); 664 665 hb_set_unicode_props (c->buffer); 666 hb_insert_dotted_circle (c->buffer, c->font); 667 hb_form_clusters (c->buffer); 668 669 hb_ensure_native_direction (c->buffer); 670 671 hb_ot_substitute (c); 672 hb_ot_position (c); 673 674 hb_ot_hide_default_ignorables (c); 675 676 _hb_buffer_deallocate_unicode_vars (c->buffer); 677 678 c->buffer->props.direction = c->target_direction; 679 680 c->buffer->deallocate_var_all (); 681} 682 683 684hb_bool_t 685_hb_ot_shape (hb_shape_plan_t *shape_plan, 686 hb_font_t *font, 687 hb_buffer_t *buffer, 688 const hb_feature_t *features, 689 unsigned int num_features) 690{ 691 hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features}; 692 hb_ot_shape_internal (&c); 693 694 return true; 695} 696 697 698void 699hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, 700 hb_tag_t table_tag, 701 hb_set_t *lookup_indexes /* OUT */) 702{ 703 /* XXX Does the first part always succeed? */ 704 HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes); 705} 706 707 708/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */ 709static void 710add_char (hb_font_t *font, 711 hb_unicode_funcs_t *unicode, 712 hb_bool_t mirror, 713 hb_codepoint_t u, 714 hb_set_t *glyphs) 715{ 716 hb_codepoint_t glyph; 717 if (font->get_glyph (u, 0, &glyph)) 718 glyphs->add (glyph); 719 if (mirror) 720 { 721 hb_codepoint_t m = unicode->mirroring (u); 722 if (m != u && font->get_glyph (m, 0, &glyph)) 723 glyphs->add (glyph); 724 } 725} 726 727 728void 729hb_ot_shape_glyphs_closure (hb_font_t *font, 730 hb_buffer_t *buffer, 731 const hb_feature_t *features, 732 unsigned int num_features, 733 hb_set_t *glyphs) 734{ 735 hb_ot_shape_plan_t plan; 736 737 const char *shapers[] = {"ot", NULL}; 738 hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, 739 features, num_features, shapers); 740 741 bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL; 742 743 unsigned int count = buffer->len; 744 for (unsigned int i = 0; i < count; i++) 745 add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs); 746 747 hb_set_t lookups; 748 lookups.init (); 749 hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups); 750 751 /* And find transitive closure. */ 752 hb_set_t copy; 753 copy.init (); 754 do { 755 copy.set (glyphs); 756 for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);) 757 hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs); 758 } while (!copy.is_equal (glyphs)); 759 760 hb_shape_plan_destroy (shape_plan); 761} 762