hb-ot-layout.cc revision d2c96819de9a7428b65ef0adf794416224221f36
1/* 2 * Copyright © 1998-2004 David Turner and Werner Lemberg 3 * Copyright © 2006 Behdad Esfahbod 4 * Copyright © 2007,2008,2009 Red Hat, Inc. 5 * Copyright © 2012 Google, Inc. 6 * 7 * This is part of HarfBuzz, a text shaping library. 8 * 9 * Permission is hereby granted, without written agreement and without 10 * license or royalty fees, to use, copy, modify, and distribute this 11 * software and its documentation for any purpose, provided that the 12 * above copyright notice and the following two paragraphs appear in 13 * all copies of this software. 14 * 15 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 16 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 17 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 18 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 19 * DAMAGE. 20 * 21 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 22 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 23 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 24 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 25 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 26 * 27 * Red Hat Author(s): Behdad Esfahbod 28 * Google Author(s): Behdad Esfahbod 29 */ 30 31#include "hb-ot-layout-private.hh" 32 33#include "hb-ot-layout-gdef-table.hh" 34#include "hb-ot-layout-gsub-table.hh" 35#include "hb-ot-layout-gpos-table.hh" 36 37#include "hb-ot-map-private.hh" 38 39#include <stdlib.h> 40#include <string.h> 41 42 43HB_SHAPER_DATA_ENSURE_DECLARE(ot, face) 44 45hb_ot_layout_t * 46_hb_ot_layout_create (hb_face_t *face) 47{ 48 hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t)); 49 if (unlikely (!layout)) 50 return NULL; 51 52 layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF)); 53 layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob); 54 55 layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB)); 56 layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob); 57 58 layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS)); 59 layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob); 60 61 layout->gsub_lookup_count = layout->gsub->get_lookup_count (); 62 layout->gpos_lookup_count = layout->gpos->get_lookup_count (); 63 64 layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t)); 65 layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t)); 66 67 if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) || 68 (layout->gpos_lookup_count && !layout->gpos_accels))) 69 { 70 _hb_ot_layout_destroy (layout); 71 return NULL; 72 } 73 74 for (unsigned int i = 0; i < layout->gsub_lookup_count; i++) 75 layout->gsub_accels[i].init (layout->gsub->get_lookup (i)); 76 for (unsigned int i = 0; i < layout->gpos_lookup_count; i++) 77 layout->gpos_accels[i].init (layout->gpos->get_lookup (i)); 78 79 return layout; 80} 81 82void 83_hb_ot_layout_destroy (hb_ot_layout_t *layout) 84{ 85 hb_blob_destroy (layout->gdef_blob); 86 hb_blob_destroy (layout->gsub_blob); 87 hb_blob_destroy (layout->gpos_blob); 88 89 for (unsigned int i = 0; i < layout->gsub_lookup_count; i++) 90 layout->gsub_accels[i].fini (layout->gsub->get_lookup (i)); 91 for (unsigned int i = 0; i < layout->gpos_lookup_count; i++) 92 layout->gpos_accels[i].fini (layout->gpos->get_lookup (i)); 93 94 free (layout->gsub_accels); 95 free (layout->gpos_accels); 96 97 free (layout); 98} 99 100static inline const OT::GDEF& 101_get_gdef (hb_face_t *face) 102{ 103 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF); 104 return *hb_ot_layout_from_face (face)->gdef; 105} 106static inline const OT::GSUB& 107_get_gsub (hb_face_t *face) 108{ 109 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB); 110 return *hb_ot_layout_from_face (face)->gsub; 111} 112static inline const OT::GPOS& 113_get_gpos (hb_face_t *face) 114{ 115 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS); 116 return *hb_ot_layout_from_face (face)->gpos; 117} 118 119 120/* 121 * GDEF 122 */ 123 124hb_bool_t 125hb_ot_layout_has_glyph_classes (hb_face_t *face) 126{ 127 return _get_gdef (face).has_glyph_classes (); 128} 129 130hb_ot_layout_glyph_class_t 131hb_ot_layout_get_glyph_class (hb_face_t *face, 132 hb_codepoint_t glyph) 133{ 134 return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph); 135} 136 137void 138hb_ot_layout_get_glyphs_in_class (hb_face_t *face, 139 hb_ot_layout_glyph_class_t klass, 140 hb_set_t *glyphs /* OUT */) 141{ 142 return _get_gdef (face).get_glyphs_in_class (klass, glyphs); 143} 144 145unsigned int 146hb_ot_layout_get_attach_points (hb_face_t *face, 147 hb_codepoint_t glyph, 148 unsigned int start_offset, 149 unsigned int *point_count /* IN/OUT */, 150 unsigned int *point_array /* OUT */) 151{ 152 return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array); 153} 154 155unsigned int 156hb_ot_layout_get_ligature_carets (hb_font_t *font, 157 hb_direction_t direction, 158 hb_codepoint_t glyph, 159 unsigned int start_offset, 160 unsigned int *caret_count /* IN/OUT */, 161 int *caret_array /* OUT */) 162{ 163 return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array); 164} 165 166 167/* 168 * GSUB/GPOS 169 */ 170 171static const OT::GSUBGPOS& 172get_gsubgpos_table (hb_face_t *face, 173 hb_tag_t table_tag) 174{ 175 switch (table_tag) { 176 case HB_OT_TAG_GSUB: return _get_gsub (face); 177 case HB_OT_TAG_GPOS: return _get_gpos (face); 178 default: return OT::Null(OT::GSUBGPOS); 179 } 180} 181 182 183unsigned int 184hb_ot_layout_table_get_script_tags (hb_face_t *face, 185 hb_tag_t table_tag, 186 unsigned int start_offset, 187 unsigned int *script_count /* IN/OUT */, 188 hb_tag_t *script_tags /* OUT */) 189{ 190 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 191 192 return g.get_script_tags (start_offset, script_count, script_tags); 193} 194 195#define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n') 196 197hb_bool_t 198hb_ot_layout_table_find_script (hb_face_t *face, 199 hb_tag_t table_tag, 200 hb_tag_t script_tag, 201 unsigned int *script_index) 202{ 203 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX); 204 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 205 206 if (g.find_script_index (script_tag, script_index)) 207 return true; 208 209 /* try finding 'DFLT' */ 210 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) 211 return false; 212 213 /* try with 'dflt'; MS site has had typos and many fonts use it now :(. 214 * including many versions of DejaVu Sans Mono! */ 215 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) 216 return false; 217 218 /* try with 'latn'; some old fonts put their features there even though 219 they're really trying to support Thai, for example :( */ 220 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) 221 return false; 222 223 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 224 return false; 225} 226 227hb_bool_t 228hb_ot_layout_table_choose_script (hb_face_t *face, 229 hb_tag_t table_tag, 230 const hb_tag_t *script_tags, 231 unsigned int *script_index, 232 hb_tag_t *chosen_script) 233{ 234 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX); 235 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 236 237 while (*script_tags) 238 { 239 if (g.find_script_index (*script_tags, script_index)) { 240 if (chosen_script) 241 *chosen_script = *script_tags; 242 return true; 243 } 244 script_tags++; 245 } 246 247 /* try finding 'DFLT' */ 248 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) { 249 if (chosen_script) 250 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT; 251 return false; 252 } 253 254 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ 255 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) { 256 if (chosen_script) 257 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE; 258 return false; 259 } 260 261 /* try with 'latn'; some old fonts put their features there even though 262 they're really trying to support Thai, for example :( */ 263 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) { 264 if (chosen_script) 265 *chosen_script = HB_OT_TAG_LATIN_SCRIPT; 266 return false; 267 } 268 269 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 270 if (chosen_script) 271 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 272 return false; 273} 274 275unsigned int 276hb_ot_layout_table_get_feature_tags (hb_face_t *face, 277 hb_tag_t table_tag, 278 unsigned int start_offset, 279 unsigned int *feature_count /* IN/OUT */, 280 hb_tag_t *feature_tags /* OUT */) 281{ 282 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 283 284 return g.get_feature_tags (start_offset, feature_count, feature_tags); 285} 286 287 288unsigned int 289hb_ot_layout_script_get_language_tags (hb_face_t *face, 290 hb_tag_t table_tag, 291 unsigned int script_index, 292 unsigned int start_offset, 293 unsigned int *language_count /* IN/OUT */, 294 hb_tag_t *language_tags /* OUT */) 295{ 296 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); 297 298 return s.get_lang_sys_tags (start_offset, language_count, language_tags); 299} 300 301hb_bool_t 302hb_ot_layout_script_find_language (hb_face_t *face, 303 hb_tag_t table_tag, 304 unsigned int script_index, 305 hb_tag_t language_tag, 306 unsigned int *language_index) 307{ 308 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX); 309 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); 310 311 if (s.find_lang_sys_index (language_tag, language_index)) 312 return true; 313 314 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ 315 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index)) 316 return false; 317 318 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX; 319 return false; 320} 321 322hb_bool_t 323hb_ot_layout_language_get_required_feature_index (hb_face_t *face, 324 hb_tag_t table_tag, 325 unsigned int script_index, 326 unsigned int language_index, 327 unsigned int *feature_index) 328{ 329 const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index); 330 331 if (feature_index) *feature_index = l.get_required_feature_index (); 332 333 return l.has_required_feature (); 334} 335 336unsigned int 337hb_ot_layout_language_get_feature_indexes (hb_face_t *face, 338 hb_tag_t table_tag, 339 unsigned int script_index, 340 unsigned int language_index, 341 unsigned int start_offset, 342 unsigned int *feature_count /* IN/OUT */, 343 unsigned int *feature_indexes /* OUT */) 344{ 345 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 346 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 347 348 return l.get_feature_indexes (start_offset, feature_count, feature_indexes); 349} 350 351unsigned int 352hb_ot_layout_language_get_feature_tags (hb_face_t *face, 353 hb_tag_t table_tag, 354 unsigned int script_index, 355 unsigned int language_index, 356 unsigned int start_offset, 357 unsigned int *feature_count /* IN/OUT */, 358 hb_tag_t *feature_tags /* OUT */) 359{ 360 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 361 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 362 363 ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t)); 364 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags); 365 366 if (feature_tags) { 367 unsigned int count = *feature_count; 368 for (unsigned int i = 0; i < count; i++) 369 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]); 370 } 371 372 return ret; 373} 374 375 376hb_bool_t 377hb_ot_layout_language_find_feature (hb_face_t *face, 378 hb_tag_t table_tag, 379 unsigned int script_index, 380 unsigned int language_index, 381 hb_tag_t feature_tag, 382 unsigned int *feature_index) 383{ 384 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX); 385 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 386 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 387 388 unsigned int num_features = l.get_feature_count (); 389 for (unsigned int i = 0; i < num_features; i++) { 390 unsigned int f_index = l.get_feature_index (i); 391 392 if (feature_tag == g.get_feature_tag (f_index)) { 393 if (feature_index) *feature_index = f_index; 394 return true; 395 } 396 } 397 398 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; 399 return false; 400} 401 402unsigned int 403hb_ot_layout_feature_get_lookups (hb_face_t *face, 404 hb_tag_t table_tag, 405 unsigned int feature_index, 406 unsigned int start_offset, 407 unsigned int *lookup_count /* IN/OUT */, 408 unsigned int *lookup_indexes /* OUT */) 409{ 410 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 411 const OT::Feature &f = g.get_feature (feature_index); 412 413 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes); 414} 415 416static void 417_hb_ot_layout_collect_lookups_lookups (hb_face_t *face, 418 hb_tag_t table_tag, 419 unsigned int feature_index, 420 hb_set_t *lookup_indexes /* OUT */) 421{ 422 unsigned int lookup_indices[32]; 423 unsigned int offset, len; 424 425 offset = 0; 426 do { 427 len = ARRAY_LENGTH (lookup_indices); 428 hb_ot_layout_feature_get_lookups (face, 429 table_tag, 430 feature_index, 431 offset, &len, 432 lookup_indices); 433 434 for (unsigned int i = 0; i < len; i++) 435 lookup_indexes->add (lookup_indices[i]); 436 437 offset += len; 438 } while (len == ARRAY_LENGTH (lookup_indices)); 439} 440 441static void 442_hb_ot_layout_collect_lookups_features (hb_face_t *face, 443 hb_tag_t table_tag, 444 unsigned int script_index, 445 unsigned int language_index, 446 const hb_tag_t *features, 447 hb_set_t *lookup_indexes /* OUT */) 448{ 449 unsigned int required_feature_index; 450 if (hb_ot_layout_language_get_required_feature_index (face, 451 table_tag, 452 script_index, 453 language_index, 454 &required_feature_index)) 455 _hb_ot_layout_collect_lookups_lookups (face, 456 table_tag, 457 required_feature_index, 458 lookup_indexes); 459 460 if (!features) 461 { 462 /* All features */ 463 unsigned int feature_indices[32]; 464 unsigned int offset, len; 465 466 offset = 0; 467 do { 468 len = ARRAY_LENGTH (feature_indices); 469 hb_ot_layout_language_get_feature_indexes (face, 470 table_tag, 471 script_index, 472 language_index, 473 offset, &len, 474 feature_indices); 475 476 for (unsigned int i = 0; i < len; i++) 477 _hb_ot_layout_collect_lookups_lookups (face, 478 table_tag, 479 feature_indices[i], 480 lookup_indexes); 481 482 offset += len; 483 } while (len == ARRAY_LENGTH (feature_indices)); 484 } 485 else 486 { 487 for (; *features; features++) 488 { 489 unsigned int feature_index; 490 if (hb_ot_layout_language_find_feature (face, 491 table_tag, 492 script_index, 493 language_index, 494 *features, 495 &feature_index)) 496 _hb_ot_layout_collect_lookups_lookups (face, 497 table_tag, 498 feature_index, 499 lookup_indexes); 500 } 501 } 502} 503 504static void 505_hb_ot_layout_collect_lookups_languages (hb_face_t *face, 506 hb_tag_t table_tag, 507 unsigned int script_index, 508 const hb_tag_t *languages, 509 const hb_tag_t *features, 510 hb_set_t *lookup_indexes /* OUT */) 511{ 512 _hb_ot_layout_collect_lookups_features (face, 513 table_tag, 514 script_index, 515 HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, 516 features, 517 lookup_indexes); 518 519 if (!languages) 520 { 521 /* All languages */ 522 unsigned int count = hb_ot_layout_script_get_language_tags (face, 523 table_tag, 524 script_index, 525 0, NULL, NULL); 526 for (unsigned int language_index = 0; language_index < count; language_index++) 527 _hb_ot_layout_collect_lookups_features (face, 528 table_tag, 529 script_index, 530 language_index, 531 features, 532 lookup_indexes); 533 } 534 else 535 { 536 for (; *languages; languages++) 537 { 538 unsigned int language_index; 539 if (hb_ot_layout_script_find_language (face, 540 table_tag, 541 script_index, 542 *languages, 543 &language_index)) 544 _hb_ot_layout_collect_lookups_features (face, 545 table_tag, 546 script_index, 547 language_index, 548 features, 549 lookup_indexes); 550 } 551 } 552} 553 554void 555hb_ot_layout_collect_lookups (hb_face_t *face, 556 hb_tag_t table_tag, 557 const hb_tag_t *scripts, 558 const hb_tag_t *languages, 559 const hb_tag_t *features, 560 hb_set_t *lookup_indexes /* OUT */) 561{ 562 if (!scripts) 563 { 564 /* All scripts */ 565 unsigned int count = hb_ot_layout_table_get_script_tags (face, 566 table_tag, 567 0, NULL, NULL); 568 for (unsigned int script_index = 0; script_index < count; script_index++) 569 _hb_ot_layout_collect_lookups_languages (face, 570 table_tag, 571 script_index, 572 languages, 573 features, 574 lookup_indexes); 575 } 576 else 577 { 578 for (; *scripts; scripts++) 579 { 580 unsigned int script_index; 581 if (hb_ot_layout_table_find_script (face, 582 table_tag, 583 *scripts, 584 &script_index)) 585 _hb_ot_layout_collect_lookups_languages (face, 586 table_tag, 587 script_index, 588 languages, 589 features, 590 lookup_indexes); 591 } 592 } 593} 594 595void 596hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, 597 hb_tag_t table_tag, 598 unsigned int lookup_index, 599 hb_set_t *glyphs_before, /* OUT. May be NULL */ 600 hb_set_t *glyphs_input, /* OUT. May be NULL */ 601 hb_set_t *glyphs_after, /* OUT. May be NULL */ 602 hb_set_t *glyphs_output /* OUT. May be NULL */) 603{ 604 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return; 605 606 OT::hb_collect_glyphs_context_t c (face, 607 glyphs_before, 608 glyphs_input, 609 glyphs_after, 610 glyphs_output); 611 612 switch (table_tag) 613 { 614 case HB_OT_TAG_GSUB: 615 { 616 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); 617 l.collect_glyphs_lookup (&c); 618 return; 619 } 620 case HB_OT_TAG_GPOS: 621 { 622 const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index); 623 l.collect_glyphs_lookup (&c); 624 return; 625 } 626 } 627} 628 629 630/* 631 * OT::GSUB 632 */ 633 634hb_bool_t 635hb_ot_layout_has_substitution (hb_face_t *face) 636{ 637 return &_get_gsub (face) != &OT::Null(OT::GSUB); 638} 639 640hb_bool_t 641hb_ot_layout_lookup_would_substitute (hb_face_t *face, 642 unsigned int lookup_index, 643 const hb_codepoint_t *glyphs, 644 unsigned int glyphs_length, 645 hb_bool_t zero_context) 646{ 647 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false; 648 return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context); 649} 650 651hb_bool_t 652hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face, 653 unsigned int lookup_index, 654 const hb_codepoint_t *glyphs, 655 unsigned int glyphs_length, 656 hb_bool_t zero_context) 657{ 658 if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false; 659 OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context); 660 661 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); 662 663 return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index].digest); 664} 665 666void 667hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer) 668{ 669 OT::GSUB::substitute_start (font, buffer); 670} 671 672hb_bool_t 673hb_ot_layout_substitute_lookup (hb_font_t *font, 674 hb_buffer_t *buffer, 675 unsigned int lookup_index, 676 hb_mask_t mask, 677 hb_bool_t auto_zwj) 678{ 679 if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false; 680 681 OT::hb_apply_context_t c (0, font, buffer, mask, auto_zwj); 682 683 const OT::SubstLookup& l = hb_ot_layout_from_face (font->face)->gsub->get_lookup (lookup_index); 684 685 return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gsub_accels[lookup_index].digest); 686} 687 688void 689hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer) 690{ 691 OT::GSUB::substitute_finish (font, buffer); 692} 693 694void 695hb_ot_layout_lookup_substitute_closure (hb_face_t *face, 696 unsigned int lookup_index, 697 hb_set_t *glyphs) 698{ 699 OT::hb_closure_context_t c (face, glyphs); 700 701 const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index); 702 703 l.closure (&c); 704} 705 706/* 707 * OT::GPOS 708 */ 709 710hb_bool_t 711hb_ot_layout_has_positioning (hb_face_t *face) 712{ 713 return &_get_gpos (face) != &OT::Null(OT::GPOS); 714} 715 716void 717hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer) 718{ 719 OT::GPOS::position_start (font, buffer); 720} 721 722hb_bool_t 723hb_ot_layout_position_lookup (hb_font_t *font, 724 hb_buffer_t *buffer, 725 unsigned int lookup_index, 726 hb_mask_t mask, 727 hb_bool_t auto_zwj) 728{ 729 if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false; 730 731 OT::hb_apply_context_t c (1, font, buffer, mask, auto_zwj); 732 733 const OT::PosLookup& l = hb_ot_layout_from_face (font->face)->gpos->get_lookup (lookup_index); 734 735 return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gpos_accels[lookup_index].digest); 736} 737 738void 739hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer) 740{ 741 OT::GPOS::position_finish (font, buffer); 742} 743 744hb_bool_t 745hb_ot_layout_get_size_params (hb_face_t *face, 746 unsigned int *design_size, /* OUT. May be NULL */ 747 unsigned int *subfamily_id, /* OUT. May be NULL */ 748 unsigned int *subfamily_name_id, /* OUT. May be NULL */ 749 unsigned int *range_start, /* OUT. May be NULL */ 750 unsigned int *range_end /* OUT. May be NULL */) 751{ 752 const OT::GPOS &gpos = _get_gpos (face); 753 const hb_tag_t tag = HB_TAG ('s','i','z','e'); 754 755 unsigned int num_features = gpos.get_feature_count (); 756 for (unsigned int i = 0; i < num_features; i++) 757 { 758 if (tag == gpos.get_feature_tag (i)) 759 { 760 const OT::Feature &f = gpos.get_feature (i); 761 const OT::FeatureParamsSize ¶ms = f.get_feature_params ().get_size_params (tag); 762 763 if (params.designSize) 764 { 765#define PARAM(a, A) if (a) *a = params.A 766 PARAM (design_size, designSize); 767 PARAM (subfamily_id, subfamilyID); 768 PARAM (subfamily_name_id, subfamilyNameID); 769 PARAM (range_start, rangeStart); 770 PARAM (range_end, rangeEnd); 771#undef PARAM 772 773 return true; 774 } 775 } 776 } 777 778#define PARAM(a, A) if (a) *a = 0 779 PARAM (design_size, designSize); 780 PARAM (subfamily_id, subfamilyID); 781 PARAM (subfamily_name_id, subfamilyNameID); 782 PARAM (range_start, rangeStart); 783 PARAM (range_end, rangeEnd); 784#undef PARAM 785 786 return false; 787} 788 789 790/* 791 * Parts of hb-ot-map are implemented here such that they have direct 792 * access to GSUB/GPOS lookups. 793 */ 794 795 796inline void hb_ot_map_t::apply (unsigned int table_index, 797 const hb_ot_shape_plan_t *plan, 798 hb_font_t *font, 799 hb_buffer_t *buffer) const 800{ 801 unsigned int i = 0; 802 803 for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) { 804 const stage_map_t *stage = &stages[table_index][stage_index]; 805 for (; i < stage->last_lookup; i++) 806 switch (table_index) 807 { 808 case 0: 809 hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, 810 lookups[table_index][i].mask, 811 lookups[table_index][i].auto_zwj); 812 break; 813 814 case 1: 815 hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, 816 lookups[table_index][i].mask, 817 lookups[table_index][i].auto_zwj); 818 break; 819 } 820 821 if (stage->pause_func) 822 { 823 buffer->clear_output (); 824 stage->pause_func (plan, font, buffer); 825 } 826 } 827} 828 829void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const 830{ 831 apply (0, plan, font, buffer); 832} 833 834void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const 835{ 836 apply (1, plan, font, buffer); 837} 838