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-unicode-private.hh" 41 #include "hb-set-private.hh" 42 43 44 static hb_tag_t common_features[] = { 45 HB_TAG('c','c','m','p'), 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 53 static 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('l','i','g','a'), 59 HB_TAG('r','c','l','t'), 60 }; 61 62 static hb_tag_t vertical_features[] = { 63 HB_TAG('v','e','r','t'), 64 }; 65 66 67 68 static void 69 hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, 70 const hb_segment_properties_t *props, 71 const hb_feature_t *user_features, 72 unsigned int num_user_features) 73 { 74 hb_ot_map_builder_t *map = &planner->map; 75 76 switch (props->direction) { 77 case HB_DIRECTION_LTR: 78 map->add_global_bool_feature (HB_TAG ('l','t','r','a')); 79 map->add_global_bool_feature (HB_TAG ('l','t','r','m')); 80 break; 81 case HB_DIRECTION_RTL: 82 map->add_global_bool_feature (HB_TAG ('r','t','l','a')); 83 map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE); 84 break; 85 case HB_DIRECTION_TTB: 86 case HB_DIRECTION_BTT: 87 case HB_DIRECTION_INVALID: 88 default: 89 break; 90 } 91 92 map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE); 93 map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE); 94 map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE); 95 96 if (planner->shaper->collect_features) 97 planner->shaper->collect_features (planner); 98 99 for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) 100 map->add_global_bool_feature (common_features[i]); 101 102 if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) 103 for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) 104 map->add_feature (horizontal_features[i], 1, F_GLOBAL | 105 (horizontal_features[i] == HB_TAG('k','e','r','n') ? 106 F_HAS_FALLBACK : F_NONE)); 107 else 108 for (unsigned int i = 0; i < ARRAY_LENGTH (vertical_features); i++) 109 map->add_feature (vertical_features[i], 1, F_GLOBAL | 110 (vertical_features[i] == HB_TAG('v','k','r','n') ? 111 F_HAS_FALLBACK : F_NONE)); 112 113 if (planner->shaper->override_features) 114 planner->shaper->override_features (planner); 115 116 for (unsigned int i = 0; i < num_user_features; i++) { 117 const hb_feature_t *feature = &user_features[i]; 118 map->add_feature (feature->tag, feature->value, 119 (feature->start == 0 && feature->end == (unsigned int) -1) ? 120 F_GLOBAL : F_NONE); 121 } 122 } 123 124 125 /* 126 * shaper face data 127 */ 128 129 hb_ot_shaper_face_data_t * 130 _hb_ot_shaper_face_data_create (hb_face_t *face) 131 { 132 return _hb_ot_layout_create (face); 133 } 134 135 void 136 _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data) 137 { 138 _hb_ot_layout_destroy (data); 139 } 140 141 142 /* 143 * shaper font data 144 */ 145 146 struct hb_ot_shaper_font_data_t {}; 147 148 hb_ot_shaper_font_data_t * 149 _hb_ot_shaper_font_data_create (hb_font_t *font) 150 { 151 return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; 152 } 153 154 void 155 _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data) 156 { 157 } 158 159 160 /* 161 * shaper shape_plan data 162 */ 163 164 hb_ot_shaper_shape_plan_data_t * 165 _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan, 166 const hb_feature_t *user_features, 167 unsigned int num_user_features) 168 { 169 hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t)); 170 if (unlikely (!plan)) 171 return NULL; 172 173 hb_ot_shape_planner_t planner (shape_plan); 174 175 planner.shaper = hb_ot_shape_complex_categorize (&planner); 176 177 hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features); 178 179 planner.compile (*plan); 180 181 if (plan->shaper->data_create) { 182 plan->data = plan->shaper->data_create (plan); 183 if (unlikely (!plan->data)) 184 return NULL; 185 } 186 187 return plan; 188 } 189 190 void 191 _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan) 192 { 193 if (plan->shaper->data_destroy) 194 plan->shaper->data_destroy (const_cast<void *> (plan->data)); 195 196 plan->finish (); 197 198 free (plan); 199 } 200 201 202 /* 203 * shaper 204 */ 205 206 struct hb_ot_shape_context_t 207 { 208 hb_ot_shape_plan_t *plan; 209 hb_font_t *font; 210 hb_face_t *face; 211 hb_buffer_t *buffer; 212 const hb_feature_t *user_features; 213 unsigned int num_user_features; 214 215 /* Transient stuff */ 216 hb_direction_t target_direction; 217 }; 218 219 220 221 /* Main shaper */ 222 223 224 /* Prepare */ 225 226 static void 227 hb_set_unicode_props (hb_buffer_t *buffer) 228 { 229 unsigned int count = buffer->len; 230 hb_glyph_info_t *info = buffer->info; 231 for (unsigned int i = 0; i < count; i++) 232 _hb_glyph_info_set_unicode_props (&info[i], buffer->unicode); 233 } 234 235 static void 236 hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) 237 { 238 if (!(buffer->flags & HB_BUFFER_FLAG_BOT) || 239 buffer->context_len[0] || 240 _hb_glyph_info_get_general_category (&buffer->info[0]) != 241 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 242 return; 243 244 if (!font->has_glyph (0x25CCu)) 245 return; 246 247 hb_glyph_info_t dottedcircle = {0}; 248 dottedcircle.codepoint = 0x25CCu; 249 _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode); 250 251 buffer->clear_output (); 252 253 buffer->idx = 0; 254 hb_glyph_info_t info = dottedcircle; 255 info.cluster = buffer->cur().cluster; 256 info.mask = buffer->cur().mask; 257 buffer->output_info (info); 258 while (buffer->idx < buffer->len) 259 buffer->next_glyph (); 260 261 buffer->swap_buffers (); 262 } 263 264 static void 265 hb_form_clusters (hb_buffer_t *buffer) 266 { 267 unsigned int count = buffer->len; 268 hb_glyph_info_t *info = buffer->info; 269 for (unsigned int i = 1; i < count; i++) 270 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))) 271 buffer->merge_clusters (i - 1, i + 1); 272 } 273 274 static void 275 hb_ensure_native_direction (hb_buffer_t *buffer) 276 { 277 hb_direction_t direction = buffer->props.direction; 278 279 /* TODO vertical: 280 * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType 281 * Ogham fonts are supposed to be implemented BTT or not. Need to research that 282 * first. */ 283 if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) || 284 (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB)) 285 { 286 hb_buffer_reverse_clusters (buffer); 287 buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction); 288 } 289 } 290 291 292 /* Substitute */ 293 294 static inline void 295 hb_ot_mirror_chars (hb_ot_shape_context_t *c) 296 { 297 if (HB_DIRECTION_IS_FORWARD (c->target_direction)) 298 return; 299 300 hb_buffer_t *buffer = c->buffer; 301 hb_unicode_funcs_t *unicode = buffer->unicode; 302 hb_mask_t rtlm_mask = c->plan->rtlm_mask; 303 304 unsigned int count = buffer->len; 305 hb_glyph_info_t *info = buffer->info; 306 for (unsigned int i = 0; i < count; i++) { 307 hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint); 308 if (likely (codepoint == info[i].codepoint)) 309 info[i].mask |= rtlm_mask; 310 else 311 info[i].codepoint = codepoint; 312 } 313 } 314 315 static inline void 316 hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c) 317 { 318 if (!c->plan->has_frac) 319 return; 320 321 hb_buffer_t *buffer = c->buffer; 322 323 /* TODO look in pre/post context text also. */ 324 unsigned int count = buffer->len; 325 hb_glyph_info_t *info = buffer->info; 326 for (unsigned int i = 0; i < count; i++) 327 { 328 if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */ 329 { 330 unsigned int start = i, end = i + 1; 331 while (start && 332 _hb_glyph_info_get_general_category (&info[start - 1]) == 333 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) 334 start--; 335 while (end < count && 336 _hb_glyph_info_get_general_category (&info[end]) == 337 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) 338 end++; 339 340 for (unsigned int j = start; j < i; j++) 341 info[j].mask |= c->plan->numr_mask | c->plan->frac_mask; 342 info[i].mask |= c->plan->frac_mask; 343 for (unsigned int j = i + 1; j < end; j++) 344 info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask; 345 346 i = end - 1; 347 } 348 } 349 } 350 351 static inline void 352 hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c) 353 { 354 hb_ot_map_t *map = &c->plan->map; 355 hb_buffer_t *buffer = c->buffer; 356 357 hb_mask_t global_mask = map->get_global_mask (); 358 buffer->reset_masks (global_mask); 359 } 360 361 static inline void 362 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) 363 { 364 hb_ot_map_t *map = &c->plan->map; 365 hb_buffer_t *buffer = c->buffer; 366 367 hb_ot_shape_setup_masks_fraction (c); 368 369 if (c->plan->shaper->setup_masks) 370 c->plan->shaper->setup_masks (c->plan, buffer, c->font); 371 372 for (unsigned int i = 0; i < c->num_user_features; i++) 373 { 374 const hb_feature_t *feature = &c->user_features[i]; 375 if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { 376 unsigned int shift; 377 hb_mask_t mask = map->get_mask (feature->tag, &shift); 378 buffer->set_masks (feature->value << shift, mask, feature->start, feature->end); 379 } 380 } 381 } 382 383 static inline void 384 hb_ot_map_glyphs_fast (hb_buffer_t *buffer) 385 { 386 /* Normalization process sets up glyph_index(), we just copy it. */ 387 unsigned int count = buffer->len; 388 hb_glyph_info_t *info = buffer->info; 389 for (unsigned int i = 0; i < count; i++) 390 info[i].codepoint = info[i].glyph_index(); 391 } 392 393 static inline void 394 hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) 395 { 396 unsigned int count = c->buffer->len; 397 hb_glyph_info_t *info = c->buffer->info; 398 for (unsigned int i = 0; i < count; i++) 399 { 400 hb_ot_layout_glyph_class_mask_t klass; 401 402 /* Never mark default-ignorables as marks. 403 * They won't get in the way of lookups anyway, 404 * but having them as mark will cause them to be skipped 405 * over if the lookup-flag says so, but at least for the 406 * Mongolian variation selectors, looks like Uniscribe 407 * marks them as non-mark. Some Mongolian fonts without 408 * GDEF rely on this. Another notable character that 409 * this applies to is COMBINING GRAPHEME JOINER. */ 410 klass = (_hb_glyph_info_get_general_category (&info[i]) != 411 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK || 412 _hb_glyph_info_is_default_ignorable (&info[i])) ? 413 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 414 HB_OT_LAYOUT_GLYPH_PROPS_MARK; 415 _hb_glyph_info_set_glyph_props (&info[i], klass); 416 } 417 } 418 419 static inline void 420 hb_ot_substitute_default (hb_ot_shape_context_t *c) 421 { 422 hb_buffer_t *buffer = c->buffer; 423 424 if (c->plan->shaper->preprocess_text) 425 c->plan->shaper->preprocess_text (c->plan, buffer, c->font); 426 427 hb_ot_shape_initialize_masks (c); 428 429 hb_ot_mirror_chars (c); 430 431 HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index); 432 433 _hb_ot_shape_normalize (c->plan, buffer, c->font); 434 435 hb_ot_shape_setup_masks (c); 436 437 /* This is unfortunate to go here, but necessary... */ 438 if (!hb_ot_layout_has_positioning (c->face)) 439 _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer); 440 441 hb_ot_map_glyphs_fast (buffer); 442 443 HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index); 444 } 445 446 static inline void 447 hb_ot_substitute_complex (hb_ot_shape_context_t *c) 448 { 449 hb_buffer_t *buffer = c->buffer; 450 451 _hb_buffer_allocate_gsubgpos_vars (buffer); 452 hb_ot_layout_substitute_start (c->font, buffer); 453 454 if (!hb_ot_layout_has_glyph_classes (c->face)) 455 hb_synthesize_glyph_classes (c); 456 457 c->plan->substitute (c->font, buffer); 458 459 hb_ot_layout_substitute_finish (c->font, buffer); 460 461 return; 462 } 463 464 static inline void 465 hb_ot_substitute (hb_ot_shape_context_t *c) 466 { 467 hb_ot_substitute_default (c); 468 hb_ot_substitute_complex (c); 469 } 470 471 /* Position */ 472 473 static inline void 474 adjust_mark_offsets (hb_glyph_position_t *pos) 475 { 476 pos->x_offset -= pos->x_advance; 477 pos->y_offset -= pos->y_advance; 478 } 479 480 static inline void 481 zero_mark_width (hb_glyph_position_t *pos) 482 { 483 pos->x_advance = 0; 484 pos->y_advance = 0; 485 } 486 487 static inline void 488 zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets) 489 { 490 unsigned int count = buffer->len; 491 hb_glyph_info_t *info = buffer->info; 492 for (unsigned int i = 0; i < count; i++) 493 if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 494 { 495 if (adjust_offsets) 496 adjust_mark_offsets (&buffer->pos[i]); 497 zero_mark_width (&buffer->pos[i]); 498 } 499 } 500 501 static inline void 502 zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets) 503 { 504 unsigned int count = buffer->len; 505 hb_glyph_info_t *info = buffer->info; 506 for (unsigned int i = 0; i < count; i++) 507 if (_hb_glyph_info_is_mark (&info[i])) 508 { 509 if (adjust_offsets) 510 adjust_mark_offsets (&buffer->pos[i]); 511 zero_mark_width (&buffer->pos[i]); 512 } 513 } 514 515 static inline void 516 hb_ot_position_default (hb_ot_shape_context_t *c) 517 { 518 hb_direction_t direction = c->buffer->props.direction; 519 unsigned int count = c->buffer->len; 520 hb_glyph_info_t *info = c->buffer->info; 521 hb_glyph_position_t *pos = c->buffer->pos; 522 for (unsigned int i = 0; i < count; i++) 523 { 524 c->font->get_glyph_advance_for_direction (info[i].codepoint, 525 direction, 526 &pos[i].x_advance, 527 &pos[i].y_advance); 528 c->font->subtract_glyph_origin_for_direction (info[i].codepoint, 529 direction, 530 &pos[i].x_offset, 531 &pos[i].y_offset); 532 533 } 534 } 535 536 static inline bool 537 hb_ot_position_complex (hb_ot_shape_context_t *c) 538 { 539 bool ret = false; 540 unsigned int count = c->buffer->len; 541 bool has_positioning = hb_ot_layout_has_positioning (c->face); 542 /* If the font has no GPOS, AND, no fallback positioning will 543 * happen, AND, direction is forward, then when zeroing mark 544 * widths, we shift the mark with it, such that the mark 545 * is positioned hanging over the previous glyph. When 546 * direction is backward we don't shift and it will end up 547 * hanging over the next glyph after the final reordering. 548 * If fallback positinoing happens or GPOS is present, we don't 549 * care. 550 */ 551 bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position || 552 HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)); 553 554 switch (c->plan->shaper->zero_width_marks) 555 { 556 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: 557 zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); 558 break; 559 560 /* Not currently used for any shaper: 561 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY: 562 zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing); 563 break; 564 */ 565 566 default: 567 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: 568 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE: 569 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: 570 break; 571 } 572 573 if (has_positioning) 574 { 575 hb_glyph_info_t *info = c->buffer->info; 576 hb_glyph_position_t *pos = c->buffer->pos; 577 578 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */ 579 580 for (unsigned int i = 0; i < count; i++) { 581 c->font->add_glyph_origin_for_direction (info[i].codepoint, 582 HB_DIRECTION_LTR, 583 &pos[i].x_offset, 584 &pos[i].y_offset); 585 } 586 587 c->plan->position (c->font, c->buffer); 588 589 for (unsigned int i = 0; i < count; i++) { 590 c->font->subtract_glyph_origin_for_direction (info[i].codepoint, 591 HB_DIRECTION_LTR, 592 &pos[i].x_offset, 593 &pos[i].y_offset); 594 } 595 596 ret = true; 597 } 598 599 switch (c->plan->shaper->zero_width_marks) 600 { 601 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE: 602 zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing); 603 break; 604 605 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: 606 zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); 607 break; 608 609 default: 610 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: 611 //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY: 612 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: 613 break; 614 } 615 616 return ret; 617 } 618 619 static inline void 620 hb_ot_position (hb_ot_shape_context_t *c) 621 { 622 hb_ot_layout_position_start (c->font, c->buffer); 623 624 hb_ot_position_default (c); 625 626 hb_bool_t fallback = !hb_ot_position_complex (c); 627 628 hb_ot_layout_position_finish (c->font, c->buffer); 629 630 if (fallback && c->plan->shaper->fallback_position) 631 _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); 632 633 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) 634 hb_buffer_reverse (c->buffer); 635 636 /* Visual fallback goes here. */ 637 638 if (fallback) 639 _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); 640 641 _hb_buffer_deallocate_gsubgpos_vars (c->buffer); 642 } 643 644 645 /* Post-process */ 646 647 static void 648 hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) 649 { 650 if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) 651 return; 652 653 hb_codepoint_t space; 654 enum { 655 SPACE_DONT_KNOW, 656 SPACE_AVAILABLE, 657 SPACE_UNAVAILABLE 658 } space_status = SPACE_DONT_KNOW; 659 660 unsigned int count = c->buffer->len; 661 hb_glyph_info_t *info = c->buffer->info; 662 hb_glyph_position_t *pos = c->buffer->pos; 663 unsigned int j = 0; 664 for (unsigned int i = 0; i < count; i++) 665 { 666 if (unlikely (!_hb_glyph_info_ligated (&info[i]) && 667 _hb_glyph_info_is_default_ignorable (&info[i]))) 668 { 669 if (space_status == SPACE_DONT_KNOW) 670 space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE; 671 672 if (space_status == SPACE_AVAILABLE) 673 { 674 info[i].codepoint = space; 675 pos[i].x_advance = 0; 676 pos[i].y_advance = 0; 677 } 678 else 679 continue; /* Delete it. */ 680 } 681 if (j != i) 682 { 683 info[j] = info[i]; 684 pos[j] = pos[i]; 685 } 686 j++; 687 } 688 c->buffer->len = j; 689 } 690 691 692 /* Pull it all together! */ 693 694 static void 695 hb_ot_shape_internal (hb_ot_shape_context_t *c) 696 { 697 c->buffer->deallocate_var_all (); 698 699 /* Save the original direction, we use it later. */ 700 c->target_direction = c->buffer->props.direction; 701 702 _hb_buffer_allocate_unicode_vars (c->buffer); 703 704 c->buffer->clear_output (); 705 706 hb_set_unicode_props (c->buffer); 707 hb_insert_dotted_circle (c->buffer, c->font); 708 hb_form_clusters (c->buffer); 709 710 hb_ensure_native_direction (c->buffer); 711 712 hb_ot_substitute (c); 713 hb_ot_position (c); 714 715 hb_ot_hide_default_ignorables (c); 716 717 _hb_buffer_deallocate_unicode_vars (c->buffer); 718 719 c->buffer->props.direction = c->target_direction; 720 721 c->buffer->deallocate_var_all (); 722 } 723 724 725 hb_bool_t 726 _hb_ot_shape (hb_shape_plan_t *shape_plan, 727 hb_font_t *font, 728 hb_buffer_t *buffer, 729 const hb_feature_t *features, 730 unsigned int num_features) 731 { 732 hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features}; 733 hb_ot_shape_internal (&c); 734 735 return true; 736 } 737 738 739 void 740 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, 741 hb_tag_t table_tag, 742 hb_set_t *lookup_indexes /* OUT */) 743 { 744 /* XXX Does the first part always succeed? */ 745 HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes); 746 } 747 748 749 /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */ 750 static void 751 add_char (hb_font_t *font, 752 hb_unicode_funcs_t *unicode, 753 hb_bool_t mirror, 754 hb_codepoint_t u, 755 hb_set_t *glyphs) 756 { 757 hb_codepoint_t glyph; 758 if (font->get_glyph (u, 0, &glyph)) 759 glyphs->add (glyph); 760 if (mirror) 761 { 762 hb_codepoint_t m = unicode->mirroring (u); 763 if (m != u && font->get_glyph (m, 0, &glyph)) 764 glyphs->add (glyph); 765 } 766 } 767 768 769 void 770 hb_ot_shape_glyphs_closure (hb_font_t *font, 771 hb_buffer_t *buffer, 772 const hb_feature_t *features, 773 unsigned int num_features, 774 hb_set_t *glyphs) 775 { 776 hb_ot_shape_plan_t plan; 777 778 const char *shapers[] = {"ot", NULL}; 779 hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, 780 features, num_features, shapers); 781 782 bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL; 783 784 unsigned int count = buffer->len; 785 hb_glyph_info_t *info = buffer->info; 786 for (unsigned int i = 0; i < count; i++) 787 add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs); 788 789 hb_set_t lookups; 790 lookups.init (); 791 hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups); 792 793 /* And find transitive closure. */ 794 hb_set_t copy; 795 copy.init (); 796 do { 797 copy.set (glyphs); 798 for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);) 799 hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs); 800 } while (!copy.is_equal (glyphs)); 801 802 hb_shape_plan_destroy (shape_plan); 803 } 804