hb-ot-shape.cc revision 0f98fe88f42471eb8fb28d08d45eca9cd8303f7a
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 44static 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 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('l','i','g','a'), 59 HB_TAG('r','c','l','t'), 60}; 61 62 63 64static void 65hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, 66 const hb_segment_properties_t *props, 67 const hb_feature_t *user_features, 68 unsigned int num_user_features) 69{ 70 hb_ot_map_builder_t *map = &planner->map; 71 72 switch (props->direction) { 73 case HB_DIRECTION_LTR: 74 map->add_global_bool_feature (HB_TAG ('l','t','r','a')); 75 map->add_global_bool_feature (HB_TAG ('l','t','r','m')); 76 break; 77 case HB_DIRECTION_RTL: 78 map->add_global_bool_feature (HB_TAG ('r','t','l','a')); 79 map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE); 80 break; 81 case HB_DIRECTION_TTB: 82 case HB_DIRECTION_BTT: 83 case HB_DIRECTION_INVALID: 84 default: 85 break; 86 } 87 88 map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE); 89 map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE); 90 map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE); 91 92 if (planner->shaper->collect_features) 93 planner->shaper->collect_features (planner); 94 95 for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) 96 map->add_global_bool_feature (common_features[i]); 97 98 if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) 99 for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) 100 map->add_feature (horizontal_features[i], 1, F_GLOBAL | 101 (horizontal_features[i] == HB_TAG('k','e','r','n') ? 102 F_HAS_FALLBACK : F_NONE)); 103 else 104 { 105 /* We really want to find a 'vert' feature if there's any in the font, no 106 * matter which script/langsys it is listed (or not) under. 107 * See various bugs referenced from: 108 * https://github.com/behdad/harfbuzz/issues/63 */ 109 map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH); 110 } 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 hb_glyph_info_t *info = buffer->info; 230 for (unsigned int i = 0; i < count; i++) 231 _hb_glyph_info_set_unicode_props (&info[i], buffer->unicode); 232} 233 234static void 235hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) 236{ 237 if (!(buffer->flags & HB_BUFFER_FLAG_BOT) || 238 buffer->context_len[0] || 239 _hb_glyph_info_get_general_category (&buffer->info[0]) != 240 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 241 return; 242 243 if (!font->has_glyph (0x25CCu)) 244 return; 245 246 hb_glyph_info_t dottedcircle = {0}; 247 dottedcircle.codepoint = 0x25CCu; 248 _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode); 249 250 buffer->clear_output (); 251 252 buffer->idx = 0; 253 hb_glyph_info_t info = dottedcircle; 254 info.cluster = buffer->cur().cluster; 255 info.mask = buffer->cur().mask; 256 buffer->output_info (info); 257 while (buffer->idx < buffer->len) 258 buffer->next_glyph (); 259 260 buffer->swap_buffers (); 261} 262 263static void 264hb_form_clusters (hb_buffer_t *buffer) 265{ 266 if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) 267 return; 268 269 /* Loop duplicated in hb_ensure_native_direction(). */ 270 unsigned int base = 0; 271 unsigned int count = buffer->len; 272 hb_glyph_info_t *info = buffer->info; 273 for (unsigned int i = 1; i < count; i++) 274 { 275 if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) 276 { 277 buffer->merge_clusters (base, i); 278 base = i; 279 } 280 } 281 buffer->merge_clusters (base, count); 282} 283 284static void 285hb_ensure_native_direction (hb_buffer_t *buffer) 286{ 287 hb_direction_t direction = buffer->props.direction; 288 289 /* TODO vertical: 290 * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType 291 * Ogham fonts are supposed to be implemented BTT or not. Need to research that 292 * first. */ 293 if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) || 294 (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB)) 295 { 296 /* Same loop as hb_form_clusters(). 297 * Since form_clusters() merged clusters already, we don't merge. */ 298 unsigned int base = 0; 299 unsigned int count = buffer->len; 300 hb_glyph_info_t *info = buffer->info; 301 for (unsigned int i = 1; i < count; i++) 302 { 303 if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) 304 { 305 buffer->reverse_range (base, i); 306 if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) 307 buffer->merge_clusters (base, i); 308 base = i; 309 } 310 } 311 buffer->reverse_range (base, count); 312 if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) 313 buffer->merge_clusters (base, count); 314 315 buffer->reverse (); 316 317 buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction); 318 } 319} 320 321 322/* Substitute */ 323 324static inline void 325hb_ot_mirror_chars (hb_ot_shape_context_t *c) 326{ 327 if (HB_DIRECTION_IS_FORWARD (c->target_direction)) 328 return; 329 330 hb_buffer_t *buffer = c->buffer; 331 hb_unicode_funcs_t *unicode = buffer->unicode; 332 hb_mask_t rtlm_mask = c->plan->rtlm_mask; 333 334 unsigned int count = buffer->len; 335 hb_glyph_info_t *info = buffer->info; 336 for (unsigned int i = 0; i < count; i++) { 337 hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint); 338 if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint))) 339 info[i].mask |= rtlm_mask; 340 else 341 info[i].codepoint = codepoint; 342 } 343} 344 345static inline void 346hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c) 347{ 348 if (!c->plan->has_frac) 349 return; 350 351 hb_buffer_t *buffer = c->buffer; 352 353 /* TODO look in pre/post context text also. */ 354 unsigned int count = buffer->len; 355 hb_glyph_info_t *info = buffer->info; 356 for (unsigned int i = 0; i < count; i++) 357 { 358 if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */ 359 { 360 unsigned int start = i, end = i + 1; 361 while (start && 362 _hb_glyph_info_get_general_category (&info[start - 1]) == 363 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) 364 start--; 365 while (end < count && 366 _hb_glyph_info_get_general_category (&info[end]) == 367 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) 368 end++; 369 370 for (unsigned int j = start; j < i; j++) 371 info[j].mask |= c->plan->numr_mask | c->plan->frac_mask; 372 info[i].mask |= c->plan->frac_mask; 373 for (unsigned int j = i + 1; j < end; j++) 374 info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask; 375 376 i = end - 1; 377 } 378 } 379} 380 381static inline void 382hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c) 383{ 384 hb_ot_map_t *map = &c->plan->map; 385 hb_buffer_t *buffer = c->buffer; 386 387 hb_mask_t global_mask = map->get_global_mask (); 388 buffer->reset_masks (global_mask); 389} 390 391static inline void 392hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) 393{ 394 hb_ot_map_t *map = &c->plan->map; 395 hb_buffer_t *buffer = c->buffer; 396 397 hb_ot_shape_setup_masks_fraction (c); 398 399 if (c->plan->shaper->setup_masks) 400 c->plan->shaper->setup_masks (c->plan, buffer, c->font); 401 402 for (unsigned int i = 0; i < c->num_user_features; i++) 403 { 404 const hb_feature_t *feature = &c->user_features[i]; 405 if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { 406 unsigned int shift; 407 hb_mask_t mask = map->get_mask (feature->tag, &shift); 408 buffer->set_masks (feature->value << shift, mask, feature->start, feature->end); 409 } 410 } 411} 412 413static void 414hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c) 415{ 416 hb_buffer_t *buffer = c->buffer; 417 418 if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) 419 return; 420 421 unsigned int count = buffer->len; 422 hb_glyph_info_t *info = buffer->info; 423 hb_glyph_position_t *pos = buffer->pos; 424 unsigned int i = 0; 425 for (i = 0; i < count; i++) 426 if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i]))) 427 pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0; 428} 429 430static void 431hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) 432{ 433 hb_buffer_t *buffer = c->buffer; 434 435 if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) 436 return; 437 438 unsigned int count = buffer->len; 439 hb_glyph_info_t *info = buffer->info; 440 hb_glyph_position_t *pos = buffer->pos; 441 unsigned int i = 0; 442 for (i = 0; i < count; i++) 443 { 444 if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i]))) 445 break; 446 } 447 448 /* No default-ignorables found; return. */ 449 if (i == count) 450 return; 451 452 hb_codepoint_t space; 453 if (c->font->get_glyph (' ', 0, &space)) 454 { 455 /* Replace default-ignorables with a zero-advance space glyph. */ 456 for (/*continue*/; i < count; i++) 457 { 458 if (_hb_glyph_info_is_default_ignorable (&info[i])) 459 info[i].codepoint = space; 460 } 461 } 462 else 463 { 464 /* Merge clusters and delete default-ignorables. 465 * NOTE! We can't use out-buffer as we have positioning data. */ 466 unsigned int j = i; 467 for (; i < count; i++) 468 { 469 if (_hb_glyph_info_is_default_ignorable (&info[i])) 470 { 471 /* Merge clusters. 472 * Same logic as buffer->delete_glyph(), but for in-place removal. */ 473 474 unsigned int cluster = info[i].cluster; 475 if (i + 1 < count && cluster == info[i + 1].cluster) 476 continue; /* Cluster survives; do nothing. */ 477 478 if (j) 479 { 480 /* Merge cluster backward. */ 481 if (cluster < info[j - 1].cluster) 482 { 483 unsigned int old_cluster = info[j - 1].cluster; 484 for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--) 485 info[k - 1].cluster = cluster; 486 } 487 continue; 488 } 489 490 if (i + 1 < count) 491 buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */ 492 493 continue; 494 } 495 496 if (j != i) 497 { 498 info[j] = info[i]; 499 pos[j] = pos[i]; 500 } 501 j++; 502 } 503 buffer->len = j; 504 } 505} 506 507 508static inline void 509hb_ot_map_glyphs_fast (hb_buffer_t *buffer) 510{ 511 /* Normalization process sets up glyph_index(), we just copy it. */ 512 unsigned int count = buffer->len; 513 hb_glyph_info_t *info = buffer->info; 514 for (unsigned int i = 0; i < count; i++) 515 info[i].codepoint = info[i].glyph_index(); 516} 517 518static inline void 519hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) 520{ 521 unsigned int count = c->buffer->len; 522 hb_glyph_info_t *info = c->buffer->info; 523 for (unsigned int i = 0; i < count; i++) 524 { 525 hb_ot_layout_glyph_class_mask_t klass; 526 527 /* Never mark default-ignorables as marks. 528 * They won't get in the way of lookups anyway, 529 * but having them as mark will cause them to be skipped 530 * over if the lookup-flag says so, but at least for the 531 * Mongolian variation selectors, looks like Uniscribe 532 * marks them as non-mark. Some Mongolian fonts without 533 * GDEF rely on this. Another notable character that 534 * this applies to is COMBINING GRAPHEME JOINER. */ 535 klass = (_hb_glyph_info_get_general_category (&info[i]) != 536 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK || 537 _hb_glyph_info_is_default_ignorable (&info[i])) ? 538 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 539 HB_OT_LAYOUT_GLYPH_PROPS_MARK; 540 _hb_glyph_info_set_glyph_props (&info[i], klass); 541 } 542} 543 544static inline void 545hb_ot_substitute_default (hb_ot_shape_context_t *c) 546{ 547 hb_buffer_t *buffer = c->buffer; 548 549 if (c->plan->shaper->preprocess_text) 550 c->plan->shaper->preprocess_text (c->plan, buffer, c->font); 551 552 hb_ot_shape_initialize_masks (c); 553 554 hb_ot_mirror_chars (c); 555 556 HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index); 557 558 _hb_ot_shape_normalize (c->plan, buffer, c->font); 559 560 hb_ot_shape_setup_masks (c); 561 562 /* This is unfortunate to go here, but necessary... */ 563 if (!hb_ot_layout_has_positioning (c->face)) 564 _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer); 565 566 hb_ot_map_glyphs_fast (buffer); 567 568 HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index); 569} 570 571static inline void 572hb_ot_substitute_complex (hb_ot_shape_context_t *c) 573{ 574 hb_buffer_t *buffer = c->buffer; 575 576 _hb_buffer_allocate_gsubgpos_vars (buffer); 577 hb_ot_layout_substitute_start (c->font, buffer); 578 579 if (!hb_ot_layout_has_glyph_classes (c->face)) 580 hb_synthesize_glyph_classes (c); 581 582 c->plan->substitute (c->font, buffer); 583 584 hb_ot_layout_substitute_finish (c->font, buffer); 585 586 return; 587} 588 589static inline void 590hb_ot_substitute (hb_ot_shape_context_t *c) 591{ 592 hb_ot_substitute_default (c); 593 hb_ot_substitute_complex (c); 594} 595 596/* Position */ 597 598static inline void 599adjust_mark_offsets (hb_glyph_position_t *pos) 600{ 601 pos->x_offset -= pos->x_advance; 602 pos->y_offset -= pos->y_advance; 603} 604 605static inline void 606zero_mark_width (hb_glyph_position_t *pos) 607{ 608 pos->x_advance = 0; 609 pos->y_advance = 0; 610} 611 612static inline void 613zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets) 614{ 615 unsigned int count = buffer->len; 616 hb_glyph_info_t *info = buffer->info; 617 for (unsigned int i = 0; i < count; i++) 618 if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 619 { 620 if (adjust_offsets) 621 adjust_mark_offsets (&buffer->pos[i]); 622 zero_mark_width (&buffer->pos[i]); 623 } 624} 625 626static inline void 627zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets) 628{ 629 unsigned int count = buffer->len; 630 hb_glyph_info_t *info = buffer->info; 631 for (unsigned int i = 0; i < count; i++) 632 if (_hb_glyph_info_is_mark (&info[i])) 633 { 634 if (adjust_offsets) 635 adjust_mark_offsets (&buffer->pos[i]); 636 zero_mark_width (&buffer->pos[i]); 637 } 638} 639 640static inline void 641hb_ot_position_default (hb_ot_shape_context_t *c) 642{ 643 hb_direction_t direction = c->buffer->props.direction; 644 unsigned int count = c->buffer->len; 645 hb_glyph_info_t *info = c->buffer->info; 646 hb_glyph_position_t *pos = c->buffer->pos; 647 for (unsigned int i = 0; i < count; i++) 648 { 649 c->font->get_glyph_advance_for_direction (info[i].codepoint, 650 direction, 651 &pos[i].x_advance, 652 &pos[i].y_advance); 653 c->font->subtract_glyph_origin_for_direction (info[i].codepoint, 654 direction, 655 &pos[i].x_offset, 656 &pos[i].y_offset); 657 658 } 659} 660 661static inline bool 662hb_ot_position_complex (hb_ot_shape_context_t *c) 663{ 664 bool ret = false; 665 unsigned int count = c->buffer->len; 666 bool has_positioning = hb_ot_layout_has_positioning (c->face); 667 /* If the font has no GPOS, AND, no fallback positioning will 668 * happen, AND, direction is forward, then when zeroing mark 669 * widths, we shift the mark with it, such that the mark 670 * is positioned hanging over the previous glyph. When 671 * direction is backward we don't shift and it will end up 672 * hanging over the next glyph after the final reordering. 673 * If fallback positinoing happens or GPOS is present, we don't 674 * care. 675 */ 676 bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position || 677 HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)); 678 679 switch (c->plan->shaper->zero_width_marks) 680 { 681 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: 682 zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); 683 break; 684 685 /* Not currently used for any shaper: 686 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY: 687 zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing); 688 break; 689 */ 690 691 default: 692 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: 693 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE: 694 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: 695 break; 696 } 697 698 if (has_positioning) 699 { 700 hb_glyph_info_t *info = c->buffer->info; 701 hb_glyph_position_t *pos = c->buffer->pos; 702 703 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */ 704 705 for (unsigned int i = 0; i < count; i++) { 706 c->font->add_glyph_origin_for_direction (info[i].codepoint, 707 HB_DIRECTION_LTR, 708 &pos[i].x_offset, 709 &pos[i].y_offset); 710 } 711 712 c->plan->position (c->font, c->buffer); 713 714 for (unsigned int i = 0; i < count; i++) { 715 c->font->subtract_glyph_origin_for_direction (info[i].codepoint, 716 HB_DIRECTION_LTR, 717 &pos[i].x_offset, 718 &pos[i].y_offset); 719 } 720 721 ret = true; 722 } 723 724 switch (c->plan->shaper->zero_width_marks) 725 { 726 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE: 727 zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing); 728 break; 729 730 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: 731 zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); 732 break; 733 734 default: 735 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: 736 //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY: 737 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: 738 break; 739 } 740 741 return ret; 742} 743 744static inline void 745hb_ot_position (hb_ot_shape_context_t *c) 746{ 747 hb_ot_layout_position_start (c->font, c->buffer); 748 749 hb_ot_position_default (c); 750 751 hb_bool_t fallback = !hb_ot_position_complex (c); 752 753 hb_ot_zero_width_default_ignorables (c); 754 755 hb_ot_layout_position_finish (c->font, c->buffer); 756 757 if (fallback && c->plan->shaper->fallback_position) 758 _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); 759 760 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) 761 hb_buffer_reverse (c->buffer); 762 763 /* Visual fallback goes here. */ 764 765 if (fallback) 766 _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); 767 768 _hb_buffer_deallocate_gsubgpos_vars (c->buffer); 769} 770 771 772/* Pull it all together! */ 773 774static void 775hb_ot_shape_internal (hb_ot_shape_context_t *c) 776{ 777 c->buffer->deallocate_var_all (); 778 779 /* Save the original direction, we use it later. */ 780 c->target_direction = c->buffer->props.direction; 781 782 _hb_buffer_allocate_unicode_vars (c->buffer); 783 784 c->buffer->clear_output (); 785 786 hb_set_unicode_props (c->buffer); 787 hb_insert_dotted_circle (c->buffer, c->font); 788 hb_form_clusters (c->buffer); 789 790 hb_ensure_native_direction (c->buffer); 791 792 hb_ot_substitute (c); 793 hb_ot_position (c); 794 795 hb_ot_hide_default_ignorables (c); 796 797 _hb_buffer_deallocate_unicode_vars (c->buffer); 798 799 c->buffer->props.direction = c->target_direction; 800 801 c->buffer->deallocate_var_all (); 802} 803 804 805hb_bool_t 806_hb_ot_shape (hb_shape_plan_t *shape_plan, 807 hb_font_t *font, 808 hb_buffer_t *buffer, 809 const hb_feature_t *features, 810 unsigned int num_features) 811{ 812 hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features}; 813 hb_ot_shape_internal (&c); 814 815 return true; 816} 817 818 819/** 820 * Since: 0.9.7 821 **/ 822void 823hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, 824 hb_tag_t table_tag, 825 hb_set_t *lookup_indexes /* OUT */) 826{ 827 /* XXX Does the first part always succeed? */ 828 HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes); 829} 830 831 832/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */ 833static void 834add_char (hb_font_t *font, 835 hb_unicode_funcs_t *unicode, 836 hb_bool_t mirror, 837 hb_codepoint_t u, 838 hb_set_t *glyphs) 839{ 840 hb_codepoint_t glyph; 841 if (font->get_glyph (u, 0, &glyph)) 842 glyphs->add (glyph); 843 if (mirror) 844 { 845 hb_codepoint_t m = unicode->mirroring (u); 846 if (m != u && font->get_glyph (m, 0, &glyph)) 847 glyphs->add (glyph); 848 } 849} 850 851 852/** 853 * Since: 0.9.2 854 **/ 855void 856hb_ot_shape_glyphs_closure (hb_font_t *font, 857 hb_buffer_t *buffer, 858 const hb_feature_t *features, 859 unsigned int num_features, 860 hb_set_t *glyphs) 861{ 862 hb_ot_shape_plan_t plan; 863 864 const char *shapers[] = {"ot", NULL}; 865 hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, 866 features, num_features, shapers); 867 868 bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL; 869 870 unsigned int count = buffer->len; 871 hb_glyph_info_t *info = buffer->info; 872 for (unsigned int i = 0; i < count; i++) 873 add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs); 874 875 hb_set_t lookups; 876 lookups.init (); 877 hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups); 878 879 /* And find transitive closure. */ 880 hb_set_t copy; 881 copy.init (); 882 do { 883 copy.set (glyphs); 884 for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);) 885 hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs); 886 } while (!copy.is_equal (glyphs)); 887 888 hb_shape_plan_destroy (shape_plan); 889} 890