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 #include "hb-ot-layout-gsubgpos-private.hh" 44 //#include "hb-aat-layout-private.hh" 45 46 static hb_tag_t common_features[] = { 47 HB_TAG('c','c','m','p'), 48 HB_TAG('l','o','c','l'), 49 HB_TAG('m','a','r','k'), 50 HB_TAG('m','k','m','k'), 51 HB_TAG('r','l','i','g'), 52 }; 53 54 55 static hb_tag_t horizontal_features[] = { 56 HB_TAG('c','a','l','t'), 57 HB_TAG('c','l','i','g'), 58 HB_TAG('c','u','r','s'), 59 HB_TAG('k','e','r','n'), 60 HB_TAG('l','i','g','a'), 61 HB_TAG('r','c','l','t'), 62 }; 63 64 65 66 static void 67 hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, 68 const hb_segment_properties_t *props, 69 const hb_feature_t *user_features, 70 unsigned int num_user_features) 71 { 72 hb_ot_map_builder_t *map = &planner->map; 73 74 map->add_global_bool_feature (HB_TAG('r','v','r','n')); 75 map->add_gsub_pause (nullptr); 76 77 switch (props->direction) { 78 case HB_DIRECTION_LTR: 79 map->add_global_bool_feature (HB_TAG ('l','t','r','a')); 80 map->add_global_bool_feature (HB_TAG ('l','t','r','m')); 81 break; 82 case HB_DIRECTION_RTL: 83 map->add_global_bool_feature (HB_TAG ('r','t','l','a')); 84 map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE); 85 break; 86 case HB_DIRECTION_TTB: 87 case HB_DIRECTION_BTT: 88 case HB_DIRECTION_INVALID: 89 default: 90 break; 91 } 92 93 map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE); 94 map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE); 95 map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE); 96 97 if (planner->shaper->collect_features) 98 planner->shaper->collect_features (planner); 99 100 for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) 101 map->add_global_bool_feature (common_features[i]); 102 103 if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) 104 for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) 105 map->add_feature (horizontal_features[i], 1, F_GLOBAL | 106 (horizontal_features[i] == HB_TAG('k','e','r','n') ? 107 F_HAS_FALLBACK : F_NONE)); 108 else 109 { 110 /* We really want to find a 'vert' feature if there's any in the font, no 111 * matter which script/langsys it is listed (or not) under. 112 * See various bugs referenced from: 113 * https://github.com/harfbuzz/harfbuzz/issues/63 */ 114 map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH); 115 } 116 117 if (planner->shaper->override_features) 118 planner->shaper->override_features (planner); 119 120 for (unsigned int i = 0; i < num_user_features; i++) { 121 const hb_feature_t *feature = &user_features[i]; 122 map->add_feature (feature->tag, feature->value, 123 (feature->start == 0 && feature->end == (unsigned int) -1) ? 124 F_GLOBAL : F_NONE); 125 } 126 } 127 128 129 /* 130 * shaper face data 131 */ 132 133 HB_SHAPER_DATA_ENSURE_DEFINE(ot, face) 134 135 hb_ot_shaper_face_data_t * 136 _hb_ot_shaper_face_data_create (hb_face_t *face) 137 { 138 return _hb_ot_layout_create (face); 139 } 140 141 void 142 _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data) 143 { 144 _hb_ot_layout_destroy (data); 145 } 146 147 148 /* 149 * shaper font data 150 */ 151 152 HB_SHAPER_DATA_ENSURE_DEFINE(ot, font) 153 154 struct hb_ot_shaper_font_data_t {}; 155 156 hb_ot_shaper_font_data_t * 157 _hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED) 158 { 159 return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; 160 } 161 162 void 163 _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data) 164 { 165 } 166 167 168 /* 169 * shaper shape_plan data 170 */ 171 172 hb_ot_shaper_shape_plan_data_t * 173 _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan, 174 const hb_feature_t *user_features, 175 unsigned int num_user_features, 176 const int *coords, 177 unsigned int num_coords) 178 { 179 hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t)); 180 if (unlikely (!plan)) 181 return nullptr; 182 183 plan->init (); 184 185 hb_ot_shape_planner_t planner (shape_plan); 186 187 planner.shaper = hb_ot_shape_complex_categorize (&planner); 188 189 hb_ot_shape_collect_features (&planner, &shape_plan->props, 190 user_features, num_user_features); 191 192 planner.compile (*plan, coords, num_coords); 193 194 if (plan->shaper->data_create) { 195 plan->data = plan->shaper->data_create (plan); 196 if (unlikely (!plan->data)) { 197 free(plan); 198 return nullptr; 199 } 200 } 201 202 return plan; 203 } 204 205 void 206 _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan) 207 { 208 if (plan->shaper->data_destroy) 209 plan->shaper->data_destroy (const_cast<void *> (plan->data)); 210 211 plan->fini (); 212 213 free (plan); 214 } 215 216 217 /* 218 * shaper 219 */ 220 221 struct hb_ot_shape_context_t 222 { 223 hb_ot_shape_plan_t *plan; 224 hb_font_t *font; 225 hb_face_t *face; 226 hb_buffer_t *buffer; 227 const hb_feature_t *user_features; 228 unsigned int num_user_features; 229 230 /* Transient stuff */ 231 bool fallback_positioning; 232 bool fallback_glyph_classes; 233 hb_direction_t target_direction; 234 }; 235 236 237 238 /* Main shaper */ 239 240 241 /* Prepare */ 242 243 static void 244 hb_set_unicode_props (hb_buffer_t *buffer) 245 { 246 unsigned int count = buffer->len; 247 hb_glyph_info_t *info = buffer->info; 248 for (unsigned int i = 0; i < count; i++) 249 _hb_glyph_info_set_unicode_props (&info[i], buffer); 250 } 251 252 static void 253 hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) 254 { 255 if (!(buffer->flags & HB_BUFFER_FLAG_BOT) || 256 buffer->context_len[0] || 257 _hb_glyph_info_get_general_category (&buffer->info[0]) != 258 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 259 return; 260 261 if (!font->has_glyph (0x25CCu)) 262 return; 263 264 hb_glyph_info_t dottedcircle = {0}; 265 dottedcircle.codepoint = 0x25CCu; 266 _hb_glyph_info_set_unicode_props (&dottedcircle, buffer); 267 268 buffer->clear_output (); 269 270 buffer->idx = 0; 271 hb_glyph_info_t info = dottedcircle; 272 info.cluster = buffer->cur().cluster; 273 info.mask = buffer->cur().mask; 274 buffer->output_info (info); 275 while (buffer->idx < buffer->len && buffer->successful) 276 buffer->next_glyph (); 277 278 buffer->swap_buffers (); 279 } 280 281 static void 282 hb_form_clusters (hb_buffer_t *buffer) 283 { 284 if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII)) 285 return; 286 287 /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */ 288 unsigned int base = 0; 289 unsigned int count = buffer->len; 290 hb_glyph_info_t *info = buffer->info; 291 for (unsigned int i = 1; i < count; i++) 292 { 293 if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) && 294 !_hb_glyph_info_is_joiner (&info[i]))) 295 { 296 if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) 297 buffer->merge_clusters (base, i); 298 else 299 buffer->unsafe_to_break (base, i); 300 base = i; 301 } 302 } 303 if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) 304 buffer->merge_clusters (base, count); 305 else 306 buffer->unsafe_to_break (base, count); 307 } 308 309 static void 310 hb_ensure_native_direction (hb_buffer_t *buffer) 311 { 312 hb_direction_t direction = buffer->props.direction; 313 hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script); 314 315 /* TODO vertical: 316 * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType 317 * Ogham fonts are supposed to be implemented BTT or not. Need to research that 318 * first. */ 319 if ((HB_DIRECTION_IS_HORIZONTAL (direction) && 320 direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) || 321 (HB_DIRECTION_IS_VERTICAL (direction) && 322 direction != HB_DIRECTION_TTB)) 323 { 324 /* Same loop as hb_form_clusters(). 325 * Since form_clusters() merged clusters already, we don't merge. */ 326 unsigned int base = 0; 327 unsigned int count = buffer->len; 328 hb_glyph_info_t *info = buffer->info; 329 for (unsigned int i = 1; i < count; i++) 330 { 331 if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) 332 { 333 if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) 334 buffer->merge_clusters (base, i); 335 buffer->reverse_range (base, i); 336 337 base = i; 338 } 339 } 340 if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) 341 buffer->merge_clusters (base, count); 342 buffer->reverse_range (base, count); 343 344 buffer->reverse (); 345 346 buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction); 347 } 348 } 349 350 351 /* Substitute */ 352 353 static inline void 354 hb_ot_mirror_chars (hb_ot_shape_context_t *c) 355 { 356 if (HB_DIRECTION_IS_FORWARD (c->target_direction)) 357 return; 358 359 hb_buffer_t *buffer = c->buffer; 360 hb_unicode_funcs_t *unicode = buffer->unicode; 361 hb_mask_t rtlm_mask = c->plan->rtlm_mask; 362 363 unsigned int count = buffer->len; 364 hb_glyph_info_t *info = buffer->info; 365 for (unsigned int i = 0; i < count; i++) { 366 hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint); 367 if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint))) 368 info[i].mask |= rtlm_mask; 369 else 370 info[i].codepoint = codepoint; 371 } 372 } 373 374 static inline void 375 hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c) 376 { 377 if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) || 378 !c->plan->has_frac) 379 return; 380 381 hb_buffer_t *buffer = c->buffer; 382 383 hb_mask_t pre_mask, post_mask; 384 if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) 385 { 386 pre_mask = c->plan->numr_mask | c->plan->frac_mask; 387 post_mask = c->plan->frac_mask | c->plan->dnom_mask; 388 } 389 else 390 { 391 pre_mask = c->plan->frac_mask | c->plan->dnom_mask; 392 post_mask = c->plan->numr_mask | c->plan->frac_mask; 393 } 394 395 unsigned int count = buffer->len; 396 hb_glyph_info_t *info = buffer->info; 397 for (unsigned int i = 0; i < count; i++) 398 { 399 if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */ 400 { 401 unsigned int start = i, end = i + 1; 402 while (start && 403 _hb_glyph_info_get_general_category (&info[start - 1]) == 404 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) 405 start--; 406 while (end < count && 407 _hb_glyph_info_get_general_category (&info[end]) == 408 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) 409 end++; 410 411 buffer->unsafe_to_break (start, end); 412 413 for (unsigned int j = start; j < i; j++) 414 info[j].mask |= pre_mask; 415 info[i].mask |= c->plan->frac_mask; 416 for (unsigned int j = i + 1; j < end; j++) 417 info[j].mask |= post_mask; 418 419 i = end - 1; 420 } 421 } 422 } 423 424 static inline void 425 hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c) 426 { 427 hb_ot_map_t *map = &c->plan->map; 428 hb_buffer_t *buffer = c->buffer; 429 430 hb_mask_t global_mask = map->get_global_mask (); 431 buffer->reset_masks (global_mask); 432 } 433 434 static inline void 435 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) 436 { 437 hb_ot_map_t *map = &c->plan->map; 438 hb_buffer_t *buffer = c->buffer; 439 440 hb_ot_shape_setup_masks_fraction (c); 441 442 if (c->plan->shaper->setup_masks) 443 c->plan->shaper->setup_masks (c->plan, buffer, c->font); 444 445 for (unsigned int i = 0; i < c->num_user_features; i++) 446 { 447 const hb_feature_t *feature = &c->user_features[i]; 448 if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { 449 unsigned int shift; 450 hb_mask_t mask = map->get_mask (feature->tag, &shift); 451 buffer->set_masks (feature->value << shift, mask, feature->start, feature->end); 452 } 453 } 454 } 455 456 static void 457 hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c) 458 { 459 hb_buffer_t *buffer = c->buffer; 460 461 if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) || 462 (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) || 463 (buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES)) 464 return; 465 466 unsigned int count = buffer->len; 467 hb_glyph_info_t *info = buffer->info; 468 hb_glyph_position_t *pos = buffer->pos; 469 unsigned int i = 0; 470 for (i = 0; i < count; i++) 471 if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i]))) 472 pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0; 473 } 474 475 static void 476 hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) 477 { 478 hb_buffer_t *buffer = c->buffer; 479 480 if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) || 481 (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)) 482 return; 483 484 unsigned int count = buffer->len; 485 hb_glyph_info_t *info = buffer->info; 486 hb_glyph_position_t *pos = buffer->pos; 487 unsigned int i = 0; 488 for (i = 0; i < count; i++) 489 { 490 if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i]))) 491 break; 492 } 493 494 /* No default-ignorables found; return. */ 495 if (i == count) 496 return; 497 498 hb_codepoint_t space; 499 if (!(buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) && 500 c->font->get_nominal_glyph (' ', &space)) 501 { 502 /* Replace default-ignorables with a zero-advance space glyph. */ 503 for (/*continue*/; i < count; i++) 504 { 505 if (_hb_glyph_info_is_default_ignorable (&info[i])) 506 info[i].codepoint = space; 507 } 508 } 509 else 510 { 511 /* Merge clusters and delete default-ignorables. 512 * NOTE! We can't use out-buffer as we have positioning data. */ 513 unsigned int j = i; 514 for (; i < count; i++) 515 { 516 if (_hb_glyph_info_is_default_ignorable (&info[i])) 517 { 518 /* Merge clusters. 519 * Same logic as buffer->delete_glyph(), but for in-place removal. */ 520 521 unsigned int cluster = info[i].cluster; 522 if (i + 1 < count && cluster == info[i + 1].cluster) 523 continue; /* Cluster survives; do nothing. */ 524 525 if (j) 526 { 527 /* Merge cluster backward. */ 528 if (cluster < info[j - 1].cluster) 529 { 530 unsigned int mask = info[i].mask; 531 unsigned int old_cluster = info[j - 1].cluster; 532 for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--) 533 buffer->set_cluster (info[k - 1], cluster, mask); 534 } 535 continue; 536 } 537 538 if (i + 1 < count) 539 buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */ 540 541 continue; 542 } 543 544 if (j != i) 545 { 546 info[j] = info[i]; 547 pos[j] = pos[i]; 548 } 549 j++; 550 } 551 buffer->len = j; 552 } 553 } 554 555 556 static inline void 557 hb_ot_map_glyphs_fast (hb_buffer_t *buffer) 558 { 559 /* Normalization process sets up glyph_index(), we just copy it. */ 560 unsigned int count = buffer->len; 561 hb_glyph_info_t *info = buffer->info; 562 for (unsigned int i = 0; i < count; i++) 563 info[i].codepoint = info[i].glyph_index(); 564 565 buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS; 566 } 567 568 static inline void 569 hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) 570 { 571 unsigned int count = c->buffer->len; 572 hb_glyph_info_t *info = c->buffer->info; 573 for (unsigned int i = 0; i < count; i++) 574 { 575 hb_ot_layout_glyph_props_flags_t klass; 576 577 /* Never mark default-ignorables as marks. 578 * They won't get in the way of lookups anyway, 579 * but having them as mark will cause them to be skipped 580 * over if the lookup-flag says so, but at least for the 581 * Mongolian variation selectors, looks like Uniscribe 582 * marks them as non-mark. Some Mongolian fonts without 583 * GDEF rely on this. Another notable character that 584 * this applies to is COMBINING GRAPHEME JOINER. */ 585 klass = (_hb_glyph_info_get_general_category (&info[i]) != 586 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK || 587 _hb_glyph_info_is_default_ignorable (&info[i])) ? 588 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 589 HB_OT_LAYOUT_GLYPH_PROPS_MARK; 590 _hb_glyph_info_set_glyph_props (&info[i], klass); 591 } 592 } 593 594 static inline void 595 hb_ot_substitute_default (hb_ot_shape_context_t *c) 596 { 597 hb_buffer_t *buffer = c->buffer; 598 599 hb_ot_mirror_chars (c); 600 601 HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index); 602 603 _hb_ot_shape_normalize (c->plan, buffer, c->font); 604 605 hb_ot_shape_setup_masks (c); 606 607 /* This is unfortunate to go here, but necessary... */ 608 if (c->fallback_positioning) 609 _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer); 610 611 hb_ot_map_glyphs_fast (buffer); 612 613 HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index); 614 } 615 616 static inline void 617 hb_ot_substitute_complex (hb_ot_shape_context_t *c) 618 { 619 hb_buffer_t *buffer = c->buffer; 620 621 hb_ot_layout_substitute_start (c->font, buffer); 622 623 if (!hb_ot_layout_has_glyph_classes (c->face)) 624 hb_synthesize_glyph_classes (c); 625 626 c->plan->substitute (c->font, buffer); 627 628 /* XXX Call morx instead. */ 629 //hb_aat_layout_substitute (c->font, c->buffer); 630 } 631 632 static inline void 633 hb_ot_substitute (hb_ot_shape_context_t *c) 634 { 635 hb_ot_substitute_default (c); 636 637 _hb_buffer_allocate_gsubgpos_vars (c->buffer); 638 639 hb_ot_substitute_complex (c); 640 } 641 642 /* Position */ 643 644 static inline void 645 adjust_mark_offsets (hb_glyph_position_t *pos) 646 { 647 pos->x_offset -= pos->x_advance; 648 pos->y_offset -= pos->y_advance; 649 } 650 651 static inline void 652 zero_mark_width (hb_glyph_position_t *pos) 653 { 654 pos->x_advance = 0; 655 pos->y_advance = 0; 656 } 657 658 static inline void 659 zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets) 660 { 661 unsigned int count = buffer->len; 662 hb_glyph_info_t *info = buffer->info; 663 for (unsigned int i = 0; i < count; i++) 664 if (_hb_glyph_info_is_mark (&info[i])) 665 { 666 if (adjust_offsets) 667 adjust_mark_offsets (&buffer->pos[i]); 668 zero_mark_width (&buffer->pos[i]); 669 } 670 } 671 672 static inline void 673 hb_ot_position_default (hb_ot_shape_context_t *c) 674 { 675 hb_direction_t direction = c->buffer->props.direction; 676 unsigned int count = c->buffer->len; 677 hb_glyph_info_t *info = c->buffer->info; 678 hb_glyph_position_t *pos = c->buffer->pos; 679 680 if (HB_DIRECTION_IS_HORIZONTAL (direction)) 681 { 682 for (unsigned int i = 0; i < count; i++) 683 pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint); 684 /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ 685 if (c->font->has_glyph_h_origin_func ()) 686 for (unsigned int i = 0; i < count; i++) 687 c->font->subtract_glyph_h_origin (info[i].codepoint, 688 &pos[i].x_offset, 689 &pos[i].y_offset); 690 } 691 else 692 { 693 for (unsigned int i = 0; i < count; i++) 694 { 695 pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint); 696 c->font->subtract_glyph_v_origin (info[i].codepoint, 697 &pos[i].x_offset, 698 &pos[i].y_offset); 699 } 700 } 701 if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK) 702 _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer); 703 } 704 705 static inline void 706 hb_ot_position_complex (hb_ot_shape_context_t *c) 707 { 708 unsigned int count = c->buffer->len; 709 hb_glyph_info_t *info = c->buffer->info; 710 hb_glyph_position_t *pos = c->buffer->pos; 711 712 /* If the font has no GPOS, AND, no fallback positioning will 713 * happen, AND, direction is forward, then when zeroing mark 714 * widths, we shift the mark with it, such that the mark 715 * is positioned hanging over the previous glyph. When 716 * direction is backward we don't shift and it will end up 717 * hanging over the next glyph after the final reordering. 718 * If fallback positinoing happens or GPOS is present, we don't 719 * care. 720 */ 721 bool adjust_offsets_when_zeroing = c->fallback_positioning && 722 !c->plan->shaper->fallback_position && 723 HB_DIRECTION_IS_FORWARD (c->buffer->props.direction); 724 725 /* We change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */ 726 727 /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ 728 if (c->font->has_glyph_h_origin_func ()) 729 for (unsigned int i = 0; i < count; i++) 730 c->font->add_glyph_h_origin (info[i].codepoint, 731 &pos[i].x_offset, 732 &pos[i].y_offset); 733 734 hb_ot_layout_position_start (c->font, c->buffer); 735 736 switch (c->plan->shaper->zero_width_marks) 737 { 738 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: 739 zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); 740 break; 741 742 default: 743 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: 744 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: 745 break; 746 } 747 748 if (likely (!c->fallback_positioning)) 749 c->plan->position (c->font, c->buffer); 750 751 switch (c->plan->shaper->zero_width_marks) 752 { 753 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: 754 zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); 755 break; 756 757 default: 758 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: 759 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: 760 break; 761 } 762 763 /* Finishing off GPOS has to follow a certain order. */ 764 hb_ot_layout_position_finish_advances (c->font, c->buffer); 765 hb_ot_zero_width_default_ignorables (c); 766 hb_ot_layout_position_finish_offsets (c->font, c->buffer); 767 768 /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ 769 if (c->font->has_glyph_h_origin_func ()) 770 for (unsigned int i = 0; i < count; i++) 771 c->font->subtract_glyph_h_origin (info[i].codepoint, 772 &pos[i].x_offset, 773 &pos[i].y_offset); 774 } 775 776 static inline void 777 hb_ot_position (hb_ot_shape_context_t *c) 778 { 779 c->buffer->clear_positions (); 780 781 hb_ot_position_default (c); 782 783 hb_ot_position_complex (c); 784 785 if (c->fallback_positioning && c->plan->shaper->fallback_position) 786 _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); 787 788 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) 789 hb_buffer_reverse (c->buffer); 790 791 /* Visual fallback goes here. */ 792 793 if (c->fallback_positioning) 794 _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); 795 796 _hb_buffer_deallocate_gsubgpos_vars (c->buffer); 797 798 //hb_aat_layout_position (c->font, c->buffer); 799 } 800 801 static inline void 802 hb_propagate_flags (hb_buffer_t *buffer) 803 { 804 /* Propagate cluster-level glyph flags to be the same on all cluster glyphs. 805 * Simplifies using them. */ 806 807 if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK)) 808 return; 809 810 hb_glyph_info_t *info = buffer->info; 811 812 foreach_cluster (buffer, start, end) 813 { 814 unsigned int mask = 0; 815 for (unsigned int i = start; i < end; i++) 816 if (info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) 817 { 818 mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK; 819 break; 820 } 821 if (mask) 822 for (unsigned int i = start; i < end; i++) 823 info[i].mask |= mask; 824 } 825 } 826 827 /* Pull it all together! */ 828 829 static void 830 hb_ot_shape_internal (hb_ot_shape_context_t *c) 831 { 832 c->buffer->deallocate_var_all (); 833 c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; 834 if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR))) 835 { 836 c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR, 837 (unsigned) HB_BUFFER_MAX_LEN_MIN); 838 } 839 if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR))) 840 { 841 c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR, 842 (unsigned) HB_BUFFER_MAX_OPS_MIN); 843 } 844 845 bool disable_otl = c->plan->shaper->disable_otl && c->plan->shaper->disable_otl (c->plan); 846 //c->fallback_substitute = disable_otl || !hb_ot_layout_has_substitution (c->face); 847 c->fallback_positioning = disable_otl || !hb_ot_layout_has_positioning (c->face); 848 c->fallback_glyph_classes = disable_otl || !hb_ot_layout_has_glyph_classes (c->face); 849 850 /* Save the original direction, we use it later. */ 851 c->target_direction = c->buffer->props.direction; 852 853 _hb_buffer_allocate_unicode_vars (c->buffer); 854 855 c->buffer->clear_output (); 856 857 hb_ot_shape_initialize_masks (c); 858 hb_set_unicode_props (c->buffer); 859 hb_insert_dotted_circle (c->buffer, c->font); 860 861 hb_form_clusters (c->buffer); 862 863 hb_ensure_native_direction (c->buffer); 864 865 if (c->plan->shaper->preprocess_text) 866 c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font); 867 868 hb_ot_substitute (c); 869 hb_ot_position (c); 870 871 hb_ot_hide_default_ignorables (c); 872 873 if (c->plan->shaper->postprocess_glyphs) 874 c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font); 875 876 hb_propagate_flags (c->buffer); 877 878 _hb_buffer_deallocate_unicode_vars (c->buffer); 879 880 c->buffer->props.direction = c->target_direction; 881 882 c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT; 883 c->buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT; 884 c->buffer->deallocate_var_all (); 885 } 886 887 888 hb_bool_t 889 _hb_ot_shape (hb_shape_plan_t *shape_plan, 890 hb_font_t *font, 891 hb_buffer_t *buffer, 892 const hb_feature_t *features, 893 unsigned int num_features) 894 { 895 hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features}; 896 hb_ot_shape_internal (&c); 897 898 return true; 899 } 900 901 902 /** 903 * hb_ot_shape_plan_collect_lookups: 904 * 905 * Since: 0.9.7 906 **/ 907 void 908 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, 909 hb_tag_t table_tag, 910 hb_set_t *lookup_indexes /* OUT */) 911 { 912 /* XXX Does the first part always succeed? */ 913 HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes); 914 } 915 916 917 /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */ 918 static void 919 add_char (hb_font_t *font, 920 hb_unicode_funcs_t *unicode, 921 hb_bool_t mirror, 922 hb_codepoint_t u, 923 hb_set_t *glyphs) 924 { 925 hb_codepoint_t glyph; 926 if (font->get_nominal_glyph (u, &glyph)) 927 glyphs->add (glyph); 928 if (mirror) 929 { 930 hb_codepoint_t m = unicode->mirroring (u); 931 if (m != u && font->get_nominal_glyph (m, &glyph)) 932 glyphs->add (glyph); 933 } 934 } 935 936 937 /** 938 * hb_ot_shape_glyphs_closure: 939 * 940 * Since: 0.9.2 941 **/ 942 void 943 hb_ot_shape_glyphs_closure (hb_font_t *font, 944 hb_buffer_t *buffer, 945 const hb_feature_t *features, 946 unsigned int num_features, 947 hb_set_t *glyphs) 948 { 949 const char *shapers[] = {"ot", nullptr}; 950 hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, 951 features, num_features, shapers); 952 953 bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL; 954 955 unsigned int count = buffer->len; 956 hb_glyph_info_t *info = buffer->info; 957 for (unsigned int i = 0; i < count; i++) 958 add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs); 959 960 hb_set_t *lookups = hb_set_create (); 961 hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, lookups); 962 hb_ot_layout_lookups_substitute_closure (font->face, lookups, glyphs); 963 964 hb_set_destroy (lookups); 965 966 hb_shape_plan_destroy (shape_plan); 967 }