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