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