hb-ot-shape.cc revision a7e8bbb080aef318b16750ca1771d0d3af3d0ae9
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 /* Only proceed if frac exists, or both numr and dnom exist. */ 335 if (!frac_mask && (!numr_mask || !dnom_mask)) 336 return; 337 } 338 339 unsigned int start = i, end = i + 1; 340 while (start && 341 _hb_glyph_info_get_general_category (&info[start - 1]) == 342 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) 343 start--; 344 while (end < count && 345 _hb_glyph_info_get_general_category (&info[end]) == 346 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) 347 end++; 348 349 for (unsigned int j = start; j < i; j++) 350 info[j].mask |= numr_mask | frac_mask; 351 info[i].mask |= frac_mask; 352 for (unsigned int j = i + 1; j < end; j++) 353 info[j].mask |= frac_mask | dnom_mask; 354 355 i = end - 1; 356 } 357 } 358} 359 360static inline void 361hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c) 362{ 363 hb_ot_map_t *map = &c->plan->map; 364 hb_buffer_t *buffer = c->buffer; 365 366 hb_mask_t global_mask = map->get_global_mask (); 367 buffer->reset_masks (global_mask); 368} 369 370static inline void 371hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) 372{ 373 hb_ot_map_t *map = &c->plan->map; 374 hb_buffer_t *buffer = c->buffer; 375 376 hb_ot_shape_setup_masks_fraction (c); 377 378 if (c->plan->shaper->setup_masks) 379 c->plan->shaper->setup_masks (c->plan, buffer, c->font); 380 381 for (unsigned int i = 0; i < c->num_user_features; i++) 382 { 383 const hb_feature_t *feature = &c->user_features[i]; 384 if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { 385 unsigned int shift; 386 hb_mask_t mask = map->get_mask (feature->tag, &shift); 387 buffer->set_masks (feature->value << shift, mask, feature->start, feature->end); 388 } 389 } 390} 391 392static inline void 393hb_ot_map_glyphs_fast (hb_buffer_t *buffer) 394{ 395 /* Normalization process sets up glyph_index(), we just copy it. */ 396 unsigned int count = buffer->len; 397 for (unsigned int i = 0; i < count; i++) 398 buffer->info[i].codepoint = buffer->info[i].glyph_index(); 399} 400 401static inline void 402hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) 403{ 404 unsigned int count = c->buffer->len; 405 hb_glyph_info_t *info = c->buffer->info; 406 for (unsigned int i = 0; i < count; i++) 407 _hb_glyph_info_set_glyph_props (&info[i], 408 _hb_glyph_info_get_general_category (&info[i]) 409 == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ? 410 HB_OT_LAYOUT_GLYPH_PROPS_MARK : 411 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH); 412} 413 414static inline void 415hb_ot_substitute_default (hb_ot_shape_context_t *c) 416{ 417 hb_buffer_t *buffer = c->buffer; 418 419 if (c->plan->shaper->preprocess_text) 420 c->plan->shaper->preprocess_text (c->plan, buffer, c->font); 421 422 hb_ot_shape_initialize_masks (c); 423 424 hb_ot_mirror_chars (c); 425 426 HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index); 427 428 _hb_ot_shape_normalize (c->plan, buffer, c->font); 429 430 hb_ot_shape_setup_masks (c); 431 432 /* This is unfortunate to go here, but necessary... */ 433 if (!hb_ot_layout_has_positioning (c->face)) 434 _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer); 435 436 hb_ot_map_glyphs_fast (buffer); 437 438 HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index); 439} 440 441static inline void 442hb_ot_substitute_complex (hb_ot_shape_context_t *c) 443{ 444 hb_buffer_t *buffer = c->buffer; 445 446 hb_ot_layout_substitute_start (c->font, buffer); 447 448 if (!hb_ot_layout_has_glyph_classes (c->face)) 449 hb_synthesize_glyph_classes (c); 450 451 c->plan->substitute (c->font, buffer); 452 453 hb_ot_layout_substitute_finish (c->font, buffer); 454 455 return; 456} 457 458static inline void 459hb_ot_substitute (hb_ot_shape_context_t *c) 460{ 461 hb_ot_substitute_default (c); 462 hb_ot_substitute_complex (c); 463} 464 465/* Position */ 466 467static inline void 468zero_mark_widths_by_unicode (hb_buffer_t *buffer) 469{ 470 unsigned int count = buffer->len; 471 for (unsigned int i = 0; i < count; i++) 472 if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 473 { 474 buffer->pos[i].x_advance = 0; 475 buffer->pos[i].y_advance = 0; 476 } 477} 478 479static inline void 480zero_mark_widths_by_gdef (hb_buffer_t *buffer) 481{ 482 unsigned int count = buffer->len; 483 for (unsigned int i = 0; i < count; i++) 484 if (_hb_glyph_info_is_mark (&buffer->info[i])) 485 { 486 buffer->pos[i].x_advance = 0; 487 buffer->pos[i].y_advance = 0; 488 } 489} 490 491static inline void 492hb_ot_position_default (hb_ot_shape_context_t *c) 493{ 494 hb_direction_t direction = c->buffer->props.direction; 495 unsigned int count = c->buffer->len; 496 hb_glyph_info_t *info = c->buffer->info; 497 hb_glyph_position_t *pos = c->buffer->pos; 498 for (unsigned int i = 0; i < count; i++) 499 { 500 c->font->get_glyph_advance_for_direction (info[i].codepoint, 501 direction, 502 &pos[i].x_advance, 503 &pos[i].y_advance); 504 c->font->subtract_glyph_origin_for_direction (info[i].codepoint, 505 direction, 506 &pos[i].x_offset, 507 &pos[i].y_offset); 508 509 } 510} 511 512static inline bool 513hb_ot_position_complex (hb_ot_shape_context_t *c) 514{ 515 bool ret = false; 516 unsigned int count = c->buffer->len; 517 518 switch (c->plan->shaper->zero_width_marks) 519 { 520 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: 521 zero_mark_widths_by_gdef (c->buffer); 522 break; 523 524 /* Not currently used for any shaper: 525 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY: 526 zero_mark_widths_by_unicode (c->buffer); 527 break; 528 */ 529 530 default: 531 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: 532 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE: 533 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: 534 break; 535 } 536 537 if (hb_ot_layout_has_positioning (c->face)) 538 { 539 hb_glyph_info_t *info = c->buffer->info; 540 hb_glyph_position_t *pos = c->buffer->pos; 541 542 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */ 543 544 for (unsigned int i = 0; i < count; i++) { 545 c->font->add_glyph_origin_for_direction (info[i].codepoint, 546 HB_DIRECTION_LTR, 547 &pos[i].x_offset, 548 &pos[i].y_offset); 549 } 550 551 c->plan->position (c->font, c->buffer); 552 553 for (unsigned int i = 0; i < count; i++) { 554 c->font->subtract_glyph_origin_for_direction (info[i].codepoint, 555 HB_DIRECTION_LTR, 556 &pos[i].x_offset, 557 &pos[i].y_offset); 558 } 559 560 ret = true; 561 } 562 563 switch (c->plan->shaper->zero_width_marks) 564 { 565 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE: 566 zero_mark_widths_by_unicode (c->buffer); 567 break; 568 569 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: 570 zero_mark_widths_by_gdef (c->buffer); 571 break; 572 573 default: 574 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: 575 //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY: 576 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: 577 break; 578 } 579 580 return ret; 581} 582 583static inline void 584hb_ot_position (hb_ot_shape_context_t *c) 585{ 586 hb_ot_layout_position_start (c->font, c->buffer); 587 588 hb_ot_position_default (c); 589 590 hb_bool_t fallback = !hb_ot_position_complex (c); 591 592 hb_ot_layout_position_finish (c->font, c->buffer); 593 594 if (fallback && c->plan->shaper->fallback_position) 595 _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); 596 597 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) 598 hb_buffer_reverse (c->buffer); 599 600 /* Visual fallback goes here. */ 601 602 if (fallback) 603 _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); 604} 605 606 607/* Post-process */ 608 609static void 610hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) 611{ 612 if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) 613 return; 614 615 hb_codepoint_t space; 616 enum { 617 SPACE_DONT_KNOW, 618 SPACE_AVAILABLE, 619 SPACE_UNAVAILABLE 620 } space_status = SPACE_DONT_KNOW; 621 622 unsigned int count = c->buffer->len; 623 hb_glyph_info_t *info = c->buffer->info; 624 hb_glyph_position_t *pos = c->buffer->pos; 625 unsigned int j = 0; 626 for (unsigned int i = 0; i < count; i++) 627 { 628 if (unlikely (!_hb_glyph_info_ligated (&info[i]) && 629 _hb_glyph_info_is_default_ignorable (&info[i]))) 630 { 631 if (space_status == SPACE_DONT_KNOW) 632 space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE; 633 634 if (space_status == SPACE_AVAILABLE) 635 { 636 info[i].codepoint = space; 637 pos[i].x_advance = 0; 638 pos[i].y_advance = 0; 639 } 640 else 641 continue; /* Delete it. */ 642 } 643 if (j != i) 644 { 645 info[j] = info[i]; 646 pos[j] = pos[i]; 647 } 648 j++; 649 } 650 c->buffer->len = j; 651} 652 653 654/* Pull it all together! */ 655 656static void 657hb_ot_shape_internal (hb_ot_shape_context_t *c) 658{ 659 c->buffer->deallocate_var_all (); 660 661 /* Save the original direction, we use it later. */ 662 c->target_direction = c->buffer->props.direction; 663 664 _hb_buffer_allocate_unicode_vars (c->buffer); 665 666 c->buffer->clear_output (); 667 668 hb_set_unicode_props (c->buffer); 669 hb_insert_dotted_circle (c->buffer, c->font); 670 hb_form_clusters (c->buffer); 671 672 hb_ensure_native_direction (c->buffer); 673 674 hb_ot_substitute (c); 675 hb_ot_position (c); 676 677 hb_ot_hide_default_ignorables (c); 678 679 _hb_buffer_deallocate_unicode_vars (c->buffer); 680 681 c->buffer->props.direction = c->target_direction; 682 683 c->buffer->deallocate_var_all (); 684} 685 686 687hb_bool_t 688_hb_ot_shape (hb_shape_plan_t *shape_plan, 689 hb_font_t *font, 690 hb_buffer_t *buffer, 691 const hb_feature_t *features, 692 unsigned int num_features) 693{ 694 hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features}; 695 hb_ot_shape_internal (&c); 696 697 return true; 698} 699 700 701void 702hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, 703 hb_tag_t table_tag, 704 hb_set_t *lookup_indexes /* OUT */) 705{ 706 /* XXX Does the first part always succeed? */ 707 HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes); 708} 709 710 711/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */ 712static void 713add_char (hb_font_t *font, 714 hb_unicode_funcs_t *unicode, 715 hb_bool_t mirror, 716 hb_codepoint_t u, 717 hb_set_t *glyphs) 718{ 719 hb_codepoint_t glyph; 720 if (font->get_glyph (u, 0, &glyph)) 721 glyphs->add (glyph); 722 if (mirror) 723 { 724 hb_codepoint_t m = unicode->mirroring (u); 725 if (m != u && font->get_glyph (m, 0, &glyph)) 726 glyphs->add (glyph); 727 } 728} 729 730 731void 732hb_ot_shape_glyphs_closure (hb_font_t *font, 733 hb_buffer_t *buffer, 734 const hb_feature_t *features, 735 unsigned int num_features, 736 hb_set_t *glyphs) 737{ 738 hb_ot_shape_plan_t plan; 739 740 const char *shapers[] = {"ot", NULL}; 741 hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, 742 features, num_features, shapers); 743 744 bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL; 745 746 unsigned int count = buffer->len; 747 for (unsigned int i = 0; i < count; i++) 748 add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs); 749 750 hb_set_t lookups; 751 lookups.init (); 752 hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups); 753 754 /* And find transitive closure. */ 755 hb_set_t copy; 756 copy.init (); 757 do { 758 copy.set (glyphs); 759 for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);) 760 hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs); 761 } while (!copy.is_equal (glyphs)); 762 763 hb_shape_plan_destroy (shape_plan); 764} 765