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