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,2013 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-open-type-private.hh" 32 #include "hb-ot-layout-private.hh" 33 34 #include "hb-ot-layout-gdef-table.hh" 35 #include "hb-ot-layout-gsub-table.hh" 36 #include "hb-ot-layout-gpos-table.hh" 37 #include "hb-ot-layout-jstf-table.hh" 38 39 #include "hb-ot-map-private.hh" 40 41 #include <stdlib.h> 42 #include <string.h> 43 44 45 HB_SHAPER_DATA_ENSURE_DECLARE(ot, face) 46 47 hb_ot_layout_t * 48 _hb_ot_layout_create (hb_face_t *face) 49 { 50 hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t)); 51 if (unlikely (!layout)) 52 return NULL; 53 54 layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF)); 55 layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob); 56 57 layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB)); 58 layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob); 59 60 layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS)); 61 layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob); 62 63 { 64 /* 65 * The ugly business of blacklisting individual fonts' tables happen here! 66 * See this thread for why we finally had to bend in and do this: 67 * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html 68 */ 69 unsigned int gdef_len = hb_blob_get_length (layout->gdef_blob); 70 unsigned int gsub_len = hb_blob_get_length (layout->gsub_blob); 71 unsigned int gpos_len = hb_blob_get_length (layout->gpos_blob); 72 if (0 73 || (442 == gdef_len && 42038 == gpos_len && 2874 == gsub_len) /* Windows 7 timesi.ttf */ 74 || (430 == gdef_len && 40662 == gpos_len && 2874 == gsub_len) /* Windows 7 timesbi.ttf */ 75 || (442 == gdef_len && 39116 == gpos_len && 2874 == gsub_len) /* Windows ??? timesi.ttf */ 76 || (430 == gdef_len && 39374 == gpos_len && 2874 == gsub_len) /* Windows ??? timesbi.ttf */ 77 || (490 == gdef_len && 41638 == gpos_len && 3046 == gsub_len) /* OS X 10.11.3 Times New Roman Italic.ttf */ 78 || (478 == gdef_len && 41902 == gpos_len && 3046 == gsub_len) /* OS X 10.11.3 Times New Roman Bold Italic.ttf */ 79 ) 80 { 81 /* In certain versions of Times New Roman Italic and Bold Italic, 82 * ASCII double quotation mark U+0022, mapped to glyph 5, has wrong 83 * glyph class 3 (mark) in GDEF. Nuke the GDEF to avoid zero-width 84 * double-quote. See: 85 * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html 86 */ 87 if (3 == layout->gdef->get_glyph_class (5)) 88 layout->gdef = &OT::Null(OT::GDEF); 89 } 90 } 91 92 layout->gsub_lookup_count = layout->gsub->get_lookup_count (); 93 layout->gpos_lookup_count = layout->gpos->get_lookup_count (); 94 95 layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t)); 96 layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t)); 97 98 if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) || 99 (layout->gpos_lookup_count && !layout->gpos_accels))) 100 { 101 _hb_ot_layout_destroy (layout); 102 return NULL; 103 } 104 105 for (unsigned int i = 0; i < layout->gsub_lookup_count; i++) 106 layout->gsub_accels[i].init (layout->gsub->get_lookup (i)); 107 for (unsigned int i = 0; i < layout->gpos_lookup_count; i++) 108 layout->gpos_accels[i].init (layout->gpos->get_lookup (i)); 109 110 return layout; 111 } 112 113 void 114 _hb_ot_layout_destroy (hb_ot_layout_t *layout) 115 { 116 for (unsigned int i = 0; i < layout->gsub_lookup_count; i++) 117 layout->gsub_accels[i].fini (); 118 for (unsigned int i = 0; i < layout->gpos_lookup_count; i++) 119 layout->gpos_accels[i].fini (); 120 121 free (layout->gsub_accels); 122 free (layout->gpos_accels); 123 124 hb_blob_destroy (layout->gdef_blob); 125 hb_blob_destroy (layout->gsub_blob); 126 hb_blob_destroy (layout->gpos_blob); 127 128 free (layout); 129 } 130 131 static inline const OT::GDEF& 132 _get_gdef (hb_face_t *face) 133 { 134 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF); 135 return *hb_ot_layout_from_face (face)->gdef; 136 } 137 static inline const OT::GSUB& 138 _get_gsub (hb_face_t *face) 139 { 140 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB); 141 return *hb_ot_layout_from_face (face)->gsub; 142 } 143 static inline const OT::GPOS& 144 _get_gpos (hb_face_t *face) 145 { 146 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS); 147 return *hb_ot_layout_from_face (face)->gpos; 148 } 149 150 151 /* 152 * GDEF 153 */ 154 155 hb_bool_t 156 hb_ot_layout_has_glyph_classes (hb_face_t *face) 157 { 158 return _get_gdef (face).has_glyph_classes (); 159 } 160 161 /** 162 * hb_ot_layout_get_glyph_class: 163 * 164 * Since: 0.9.7 165 **/ 166 hb_ot_layout_glyph_class_t 167 hb_ot_layout_get_glyph_class (hb_face_t *face, 168 hb_codepoint_t glyph) 169 { 170 return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph); 171 } 172 173 /** 174 * hb_ot_layout_get_glyphs_in_class: 175 * 176 * Since: 0.9.7 177 **/ 178 void 179 hb_ot_layout_get_glyphs_in_class (hb_face_t *face, 180 hb_ot_layout_glyph_class_t klass, 181 hb_set_t *glyphs /* OUT */) 182 { 183 return _get_gdef (face).get_glyphs_in_class (klass, glyphs); 184 } 185 186 unsigned int 187 hb_ot_layout_get_attach_points (hb_face_t *face, 188 hb_codepoint_t glyph, 189 unsigned int start_offset, 190 unsigned int *point_count /* IN/OUT */, 191 unsigned int *point_array /* OUT */) 192 { 193 return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array); 194 } 195 196 unsigned int 197 hb_ot_layout_get_ligature_carets (hb_font_t *font, 198 hb_direction_t direction, 199 hb_codepoint_t glyph, 200 unsigned int start_offset, 201 unsigned int *caret_count /* IN/OUT */, 202 int *caret_array /* OUT */) 203 { 204 return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array); 205 } 206 207 208 /* 209 * GSUB/GPOS 210 */ 211 212 static const OT::GSUBGPOS& 213 get_gsubgpos_table (hb_face_t *face, 214 hb_tag_t table_tag) 215 { 216 switch (table_tag) { 217 case HB_OT_TAG_GSUB: return _get_gsub (face); 218 case HB_OT_TAG_GPOS: return _get_gpos (face); 219 default: return OT::Null(OT::GSUBGPOS); 220 } 221 } 222 223 224 unsigned int 225 hb_ot_layout_table_get_script_tags (hb_face_t *face, 226 hb_tag_t table_tag, 227 unsigned int start_offset, 228 unsigned int *script_count /* IN/OUT */, 229 hb_tag_t *script_tags /* OUT */) 230 { 231 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 232 233 return g.get_script_tags (start_offset, script_count, script_tags); 234 } 235 236 #define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n') 237 238 hb_bool_t 239 hb_ot_layout_table_find_script (hb_face_t *face, 240 hb_tag_t table_tag, 241 hb_tag_t script_tag, 242 unsigned int *script_index) 243 { 244 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX); 245 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 246 247 if (g.find_script_index (script_tag, script_index)) 248 return true; 249 250 /* try finding 'DFLT' */ 251 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) 252 return false; 253 254 /* try with 'dflt'; MS site has had typos and many fonts use it now :(. 255 * including many versions of DejaVu Sans Mono! */ 256 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) 257 return false; 258 259 /* try with 'latn'; some old fonts put their features there even though 260 they're really trying to support Thai, for example :( */ 261 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) 262 return false; 263 264 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 265 return false; 266 } 267 268 hb_bool_t 269 hb_ot_layout_table_choose_script (hb_face_t *face, 270 hb_tag_t table_tag, 271 const hb_tag_t *script_tags, 272 unsigned int *script_index, 273 hb_tag_t *chosen_script) 274 { 275 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX); 276 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 277 278 while (*script_tags) 279 { 280 if (g.find_script_index (*script_tags, script_index)) { 281 if (chosen_script) 282 *chosen_script = *script_tags; 283 return true; 284 } 285 script_tags++; 286 } 287 288 /* try finding 'DFLT' */ 289 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) { 290 if (chosen_script) 291 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT; 292 return false; 293 } 294 295 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ 296 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) { 297 if (chosen_script) 298 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE; 299 return false; 300 } 301 302 /* try with 'latn'; some old fonts put their features there even though 303 they're really trying to support Thai, for example :( */ 304 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) { 305 if (chosen_script) 306 *chosen_script = HB_OT_TAG_LATIN_SCRIPT; 307 return false; 308 } 309 310 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 311 if (chosen_script) 312 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 313 return false; 314 } 315 316 unsigned int 317 hb_ot_layout_table_get_feature_tags (hb_face_t *face, 318 hb_tag_t table_tag, 319 unsigned int start_offset, 320 unsigned int *feature_count /* IN/OUT */, 321 hb_tag_t *feature_tags /* OUT */) 322 { 323 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 324 325 return g.get_feature_tags (start_offset, feature_count, feature_tags); 326 } 327 328 hb_bool_t 329 hb_ot_layout_table_find_feature (hb_face_t *face, 330 hb_tag_t table_tag, 331 hb_tag_t feature_tag, 332 unsigned int *feature_index) 333 { 334 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX); 335 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 336 337 unsigned int num_features = g.get_feature_count (); 338 for (unsigned int i = 0; i < num_features; i++) 339 { 340 if (feature_tag == g.get_feature_tag (i)) { 341 if (feature_index) *feature_index = i; 342 return true; 343 } 344 } 345 346 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; 347 return false; 348 } 349 350 351 unsigned int 352 hb_ot_layout_script_get_language_tags (hb_face_t *face, 353 hb_tag_t table_tag, 354 unsigned int script_index, 355 unsigned int start_offset, 356 unsigned int *language_count /* IN/OUT */, 357 hb_tag_t *language_tags /* OUT */) 358 { 359 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); 360 361 return s.get_lang_sys_tags (start_offset, language_count, language_tags); 362 } 363 364 hb_bool_t 365 hb_ot_layout_script_find_language (hb_face_t *face, 366 hb_tag_t table_tag, 367 unsigned int script_index, 368 hb_tag_t language_tag, 369 unsigned int *language_index) 370 { 371 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX); 372 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); 373 374 if (s.find_lang_sys_index (language_tag, language_index)) 375 return true; 376 377 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ 378 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index)) 379 return false; 380 381 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX; 382 return false; 383 } 384 385 hb_bool_t 386 hb_ot_layout_language_get_required_feature_index (hb_face_t *face, 387 hb_tag_t table_tag, 388 unsigned int script_index, 389 unsigned int language_index, 390 unsigned int *feature_index) 391 { 392 return hb_ot_layout_language_get_required_feature (face, 393 table_tag, 394 script_index, 395 language_index, 396 feature_index, 397 NULL); 398 } 399 400 /** 401 * hb_ot_layout_language_get_required_feature: 402 * 403 * Since: 0.9.30 404 **/ 405 hb_bool_t 406 hb_ot_layout_language_get_required_feature (hb_face_t *face, 407 hb_tag_t table_tag, 408 unsigned int script_index, 409 unsigned int language_index, 410 unsigned int *feature_index, 411 hb_tag_t *feature_tag) 412 { 413 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 414 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 415 416 unsigned int index = l.get_required_feature_index (); 417 if (feature_index) *feature_index = index; 418 if (feature_tag) *feature_tag = g.get_feature_tag (index); 419 420 return l.has_required_feature (); 421 } 422 423 unsigned int 424 hb_ot_layout_language_get_feature_indexes (hb_face_t *face, 425 hb_tag_t table_tag, 426 unsigned int script_index, 427 unsigned int language_index, 428 unsigned int start_offset, 429 unsigned int *feature_count /* IN/OUT */, 430 unsigned int *feature_indexes /* OUT */) 431 { 432 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 433 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 434 435 return l.get_feature_indexes (start_offset, feature_count, feature_indexes); 436 } 437 438 unsigned int 439 hb_ot_layout_language_get_feature_tags (hb_face_t *face, 440 hb_tag_t table_tag, 441 unsigned int script_index, 442 unsigned int language_index, 443 unsigned int start_offset, 444 unsigned int *feature_count /* IN/OUT */, 445 hb_tag_t *feature_tags /* OUT */) 446 { 447 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 448 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 449 450 ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t)); 451 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags); 452 453 if (feature_tags) { 454 unsigned int count = *feature_count; 455 for (unsigned int i = 0; i < count; i++) 456 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]); 457 } 458 459 return ret; 460 } 461 462 463 hb_bool_t 464 hb_ot_layout_language_find_feature (hb_face_t *face, 465 hb_tag_t table_tag, 466 unsigned int script_index, 467 unsigned int language_index, 468 hb_tag_t feature_tag, 469 unsigned int *feature_index) 470 { 471 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX); 472 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 473 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 474 475 unsigned int num_features = l.get_feature_count (); 476 for (unsigned int i = 0; i < num_features; i++) { 477 unsigned int f_index = l.get_feature_index (i); 478 479 if (feature_tag == g.get_feature_tag (f_index)) { 480 if (feature_index) *feature_index = f_index; 481 return true; 482 } 483 } 484 485 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; 486 return false; 487 } 488 489 /** 490 * hb_ot_layout_feature_get_lookups: 491 * 492 * Since: 0.9.7 493 **/ 494 unsigned int 495 hb_ot_layout_feature_get_lookups (hb_face_t *face, 496 hb_tag_t table_tag, 497 unsigned int feature_index, 498 unsigned int start_offset, 499 unsigned int *lookup_count /* IN/OUT */, 500 unsigned int *lookup_indexes /* OUT */) 501 { 502 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 503 const OT::Feature &f = g.get_feature (feature_index); 504 505 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes); 506 } 507 508 /** 509 * hb_ot_layout_table_get_lookup_count: 510 * 511 * Since: 0.9.22 512 **/ 513 unsigned int 514 hb_ot_layout_table_get_lookup_count (hb_face_t *face, 515 hb_tag_t table_tag) 516 { 517 switch (table_tag) 518 { 519 case HB_OT_TAG_GSUB: 520 { 521 return hb_ot_layout_from_face (face)->gsub_lookup_count; 522 } 523 case HB_OT_TAG_GPOS: 524 { 525 return hb_ot_layout_from_face (face)->gpos_lookup_count; 526 } 527 } 528 return 0; 529 } 530 531 static void 532 _hb_ot_layout_collect_lookups_lookups (hb_face_t *face, 533 hb_tag_t table_tag, 534 unsigned int feature_index, 535 hb_set_t *lookup_indexes /* OUT */) 536 { 537 unsigned int lookup_indices[32]; 538 unsigned int offset, len; 539 540 offset = 0; 541 do { 542 len = ARRAY_LENGTH (lookup_indices); 543 hb_ot_layout_feature_get_lookups (face, 544 table_tag, 545 feature_index, 546 offset, &len, 547 lookup_indices); 548 549 for (unsigned int i = 0; i < len; i++) 550 lookup_indexes->add (lookup_indices[i]); 551 552 offset += len; 553 } while (len == ARRAY_LENGTH (lookup_indices)); 554 } 555 556 static void 557 _hb_ot_layout_collect_lookups_features (hb_face_t *face, 558 hb_tag_t table_tag, 559 unsigned int script_index, 560 unsigned int language_index, 561 const hb_tag_t *features, 562 hb_set_t *lookup_indexes /* OUT */) 563 { 564 if (!features) 565 { 566 unsigned int required_feature_index; 567 if (hb_ot_layout_language_get_required_feature (face, 568 table_tag, 569 script_index, 570 language_index, 571 &required_feature_index, 572 NULL)) 573 _hb_ot_layout_collect_lookups_lookups (face, 574 table_tag, 575 required_feature_index, 576 lookup_indexes); 577 578 /* All features */ 579 unsigned int feature_indices[32]; 580 unsigned int offset, len; 581 582 offset = 0; 583 do { 584 len = ARRAY_LENGTH (feature_indices); 585 hb_ot_layout_language_get_feature_indexes (face, 586 table_tag, 587 script_index, 588 language_index, 589 offset, &len, 590 feature_indices); 591 592 for (unsigned int i = 0; i < len; i++) 593 _hb_ot_layout_collect_lookups_lookups (face, 594 table_tag, 595 feature_indices[i], 596 lookup_indexes); 597 598 offset += len; 599 } while (len == ARRAY_LENGTH (feature_indices)); 600 } 601 else 602 { 603 for (; *features; features++) 604 { 605 unsigned int feature_index; 606 if (hb_ot_layout_language_find_feature (face, 607 table_tag, 608 script_index, 609 language_index, 610 *features, 611 &feature_index)) 612 _hb_ot_layout_collect_lookups_lookups (face, 613 table_tag, 614 feature_index, 615 lookup_indexes); 616 } 617 } 618 } 619 620 static void 621 _hb_ot_layout_collect_lookups_languages (hb_face_t *face, 622 hb_tag_t table_tag, 623 unsigned int script_index, 624 const hb_tag_t *languages, 625 const hb_tag_t *features, 626 hb_set_t *lookup_indexes /* OUT */) 627 { 628 _hb_ot_layout_collect_lookups_features (face, 629 table_tag, 630 script_index, 631 HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, 632 features, 633 lookup_indexes); 634 635 if (!languages) 636 { 637 /* All languages */ 638 unsigned int count = hb_ot_layout_script_get_language_tags (face, 639 table_tag, 640 script_index, 641 0, NULL, NULL); 642 for (unsigned int language_index = 0; language_index < count; language_index++) 643 _hb_ot_layout_collect_lookups_features (face, 644 table_tag, 645 script_index, 646 language_index, 647 features, 648 lookup_indexes); 649 } 650 else 651 { 652 for (; *languages; languages++) 653 { 654 unsigned int language_index; 655 if (hb_ot_layout_script_find_language (face, 656 table_tag, 657 script_index, 658 *languages, 659 &language_index)) 660 _hb_ot_layout_collect_lookups_features (face, 661 table_tag, 662 script_index, 663 language_index, 664 features, 665 lookup_indexes); 666 } 667 } 668 } 669 670 /** 671 * hb_ot_layout_collect_lookups: 672 * 673 * Since: 0.9.8 674 **/ 675 void 676 hb_ot_layout_collect_lookups (hb_face_t *face, 677 hb_tag_t table_tag, 678 const hb_tag_t *scripts, 679 const hb_tag_t *languages, 680 const hb_tag_t *features, 681 hb_set_t *lookup_indexes /* OUT */) 682 { 683 if (!scripts) 684 { 685 /* All scripts */ 686 unsigned int count = hb_ot_layout_table_get_script_tags (face, 687 table_tag, 688 0, NULL, NULL); 689 for (unsigned int script_index = 0; script_index < count; script_index++) 690 _hb_ot_layout_collect_lookups_languages (face, 691 table_tag, 692 script_index, 693 languages, 694 features, 695 lookup_indexes); 696 } 697 else 698 { 699 for (; *scripts; scripts++) 700 { 701 unsigned int script_index; 702 if (hb_ot_layout_table_find_script (face, 703 table_tag, 704 *scripts, 705 &script_index)) 706 _hb_ot_layout_collect_lookups_languages (face, 707 table_tag, 708 script_index, 709 languages, 710 features, 711 lookup_indexes); 712 } 713 } 714 } 715 716 /** 717 * hb_ot_layout_lookup_collect_glyphs: 718 * 719 * Since: 0.9.7 720 **/ 721 void 722 hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, 723 hb_tag_t table_tag, 724 unsigned int lookup_index, 725 hb_set_t *glyphs_before, /* OUT. May be NULL */ 726 hb_set_t *glyphs_input, /* OUT. May be NULL */ 727 hb_set_t *glyphs_after, /* OUT. May be NULL */ 728 hb_set_t *glyphs_output /* OUT. May be NULL */) 729 { 730 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return; 731 732 OT::hb_collect_glyphs_context_t c (face, 733 glyphs_before, 734 glyphs_input, 735 glyphs_after, 736 glyphs_output); 737 738 switch (table_tag) 739 { 740 case HB_OT_TAG_GSUB: 741 { 742 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); 743 l.collect_glyphs (&c); 744 return; 745 } 746 case HB_OT_TAG_GPOS: 747 { 748 const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index); 749 l.collect_glyphs (&c); 750 return; 751 } 752 } 753 } 754 755 756 /* 757 * OT::GSUB 758 */ 759 760 hb_bool_t 761 hb_ot_layout_has_substitution (hb_face_t *face) 762 { 763 return &_get_gsub (face) != &OT::Null(OT::GSUB); 764 } 765 766 /** 767 * hb_ot_layout_lookup_would_substitute: 768 * 769 * Since: 0.9.7 770 **/ 771 hb_bool_t 772 hb_ot_layout_lookup_would_substitute (hb_face_t *face, 773 unsigned int lookup_index, 774 const hb_codepoint_t *glyphs, 775 unsigned int glyphs_length, 776 hb_bool_t zero_context) 777 { 778 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false; 779 return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context); 780 } 781 782 hb_bool_t 783 hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face, 784 unsigned int lookup_index, 785 const hb_codepoint_t *glyphs, 786 unsigned int glyphs_length, 787 hb_bool_t zero_context) 788 { 789 if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false; 790 OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context); 791 792 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); 793 794 return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]); 795 } 796 797 void 798 hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer) 799 { 800 OT::GSUB::substitute_start (font, buffer); 801 } 802 803 /** 804 * hb_ot_layout_lookup_substitute_closure: 805 * 806 * Since: 0.9.7 807 **/ 808 void 809 hb_ot_layout_lookup_substitute_closure (hb_face_t *face, 810 unsigned int lookup_index, 811 hb_set_t *glyphs) 812 { 813 OT::hb_closure_context_t c (face, glyphs); 814 815 const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index); 816 817 l.closure (&c); 818 } 819 820 /* 821 * OT::GPOS 822 */ 823 824 hb_bool_t 825 hb_ot_layout_has_positioning (hb_face_t *face) 826 { 827 return &_get_gpos (face) != &OT::Null(OT::GPOS); 828 } 829 830 void 831 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer) 832 { 833 OT::GPOS::position_start (font, buffer); 834 } 835 836 void 837 hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer) 838 { 839 OT::GPOS::position_finish_advances (font, buffer); 840 } 841 842 void 843 hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) 844 { 845 OT::GPOS::position_finish_offsets (font, buffer); 846 } 847 848 /** 849 * hb_ot_layout_get_size_params: 850 * 851 * Since: 0.9.10 852 **/ 853 hb_bool_t 854 hb_ot_layout_get_size_params (hb_face_t *face, 855 unsigned int *design_size, /* OUT. May be NULL */ 856 unsigned int *subfamily_id, /* OUT. May be NULL */ 857 unsigned int *subfamily_name_id, /* OUT. May be NULL */ 858 unsigned int *range_start, /* OUT. May be NULL */ 859 unsigned int *range_end /* OUT. May be NULL */) 860 { 861 const OT::GPOS &gpos = _get_gpos (face); 862 const hb_tag_t tag = HB_TAG ('s','i','z','e'); 863 864 unsigned int num_features = gpos.get_feature_count (); 865 for (unsigned int i = 0; i < num_features; i++) 866 { 867 if (tag == gpos.get_feature_tag (i)) 868 { 869 const OT::Feature &f = gpos.get_feature (i); 870 const OT::FeatureParamsSize ¶ms = f.get_feature_params ().get_size_params (tag); 871 872 if (params.designSize) 873 { 874 #define PARAM(a, A) if (a) *a = params.A 875 PARAM (design_size, designSize); 876 PARAM (subfamily_id, subfamilyID); 877 PARAM (subfamily_name_id, subfamilyNameID); 878 PARAM (range_start, rangeStart); 879 PARAM (range_end, rangeEnd); 880 #undef PARAM 881 882 return true; 883 } 884 } 885 } 886 887 #define PARAM(a, A) if (a) *a = 0 888 PARAM (design_size, designSize); 889 PARAM (subfamily_id, subfamilyID); 890 PARAM (subfamily_name_id, subfamilyNameID); 891 PARAM (range_start, rangeStart); 892 PARAM (range_end, rangeEnd); 893 #undef PARAM 894 895 return false; 896 } 897 898 899 /* 900 * Parts of different types are implemented here such that they have direct 901 * access to GSUB/GPOS lookups. 902 */ 903 904 905 struct GSUBProxy 906 { 907 static const unsigned int table_index = 0; 908 static const bool inplace = false; 909 typedef OT::SubstLookup Lookup; 910 911 GSUBProxy (hb_face_t *face) : 912 table (*hb_ot_layout_from_face (face)->gsub), 913 accels (hb_ot_layout_from_face (face)->gsub_accels) {} 914 915 const OT::GSUB &table; 916 const hb_ot_layout_lookup_accelerator_t *accels; 917 }; 918 919 struct GPOSProxy 920 { 921 static const unsigned int table_index = 1; 922 static const bool inplace = true; 923 typedef OT::PosLookup Lookup; 924 925 GPOSProxy (hb_face_t *face) : 926 table (*hb_ot_layout_from_face (face)->gpos), 927 accels (hb_ot_layout_from_face (face)->gpos_accels) {} 928 929 const OT::GPOS &table; 930 const hb_ot_layout_lookup_accelerator_t *accels; 931 }; 932 933 934 struct hb_get_subtables_context_t : 935 OT::hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY> 936 { 937 template <typename Type> 938 static inline bool apply_to (const void *obj, OT::hb_apply_context_t *c) 939 { 940 const Type *typed_obj = (const Type *) obj; 941 return typed_obj->apply (c); 942 } 943 944 typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_apply_context_t *c); 945 946 struct hb_applicable_t 947 { 948 inline void init (const void *obj_, hb_apply_func_t apply_func_) 949 { 950 obj = obj_; 951 apply_func = apply_func_; 952 } 953 954 inline bool apply (OT::hb_apply_context_t *c) const { return apply_func (obj, c); } 955 956 private: 957 const void *obj; 958 hb_apply_func_t apply_func; 959 }; 960 961 typedef hb_auto_array_t<hb_applicable_t> array_t; 962 963 /* Dispatch interface. */ 964 inline const char *get_name (void) { return "GET_SUBTABLES"; } 965 template <typename T> 966 inline return_t dispatch (const T &obj) 967 { 968 hb_applicable_t *entry = array.push(); 969 if (likely (entry)) 970 entry->init (&obj, apply_to<T>); 971 return HB_VOID; 972 } 973 static return_t default_return_value (void) { return HB_VOID; } 974 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } 975 976 hb_get_subtables_context_t (array_t &array_) : 977 array (array_), 978 debug_depth (0) {} 979 980 array_t &array; 981 unsigned int debug_depth; 982 }; 983 984 static inline bool 985 apply_forward (OT::hb_apply_context_t *c, 986 const hb_ot_layout_lookup_accelerator_t &accel, 987 const hb_get_subtables_context_t::array_t &subtables) 988 { 989 bool ret = false; 990 hb_buffer_t *buffer = c->buffer; 991 while (buffer->idx < buffer->len && !buffer->in_error) 992 { 993 bool applied = false; 994 if (accel.may_have (buffer->cur().codepoint) && 995 (buffer->cur().mask & c->lookup_mask) && 996 c->check_glyph_property (&buffer->cur(), c->lookup_props)) 997 { 998 for (unsigned int i = 0; i < subtables.len; i++) 999 if (subtables[i].apply (c)) 1000 { 1001 applied = true; 1002 break; 1003 } 1004 } 1005 1006 if (applied) 1007 ret = true; 1008 else 1009 buffer->next_glyph (); 1010 } 1011 return ret; 1012 } 1013 1014 static inline bool 1015 apply_backward (OT::hb_apply_context_t *c, 1016 const hb_ot_layout_lookup_accelerator_t &accel, 1017 const hb_get_subtables_context_t::array_t &subtables) 1018 { 1019 bool ret = false; 1020 hb_buffer_t *buffer = c->buffer; 1021 do 1022 { 1023 if (accel.may_have (buffer->cur().codepoint) && 1024 (buffer->cur().mask & c->lookup_mask) && 1025 c->check_glyph_property (&buffer->cur(), c->lookup_props)) 1026 { 1027 for (unsigned int i = 0; i < subtables.len; i++) 1028 if (subtables[i].apply (c)) 1029 { 1030 ret = true; 1031 break; 1032 } 1033 } 1034 /* The reverse lookup doesn't "advance" cursor (for good reason). */ 1035 buffer->idx--; 1036 1037 } 1038 while ((int) buffer->idx >= 0); 1039 return ret; 1040 } 1041 1042 template <typename Proxy> 1043 static inline void 1044 apply_string (OT::hb_apply_context_t *c, 1045 const typename Proxy::Lookup &lookup, 1046 const hb_ot_layout_lookup_accelerator_t &accel) 1047 { 1048 hb_buffer_t *buffer = c->buffer; 1049 1050 if (unlikely (!buffer->len || !c->lookup_mask)) 1051 return; 1052 1053 c->set_lookup_props (lookup.get_props ()); 1054 1055 hb_get_subtables_context_t::array_t subtables; 1056 hb_get_subtables_context_t c_get_subtables (subtables); 1057 lookup.dispatch (&c_get_subtables); 1058 1059 if (likely (!lookup.is_reverse ())) 1060 { 1061 /* in/out forward substitution/positioning */ 1062 if (Proxy::table_index == 0) 1063 buffer->clear_output (); 1064 buffer->idx = 0; 1065 1066 bool ret; 1067 ret = apply_forward (c, accel, subtables); 1068 if (ret) 1069 { 1070 if (!Proxy::inplace) 1071 buffer->swap_buffers (); 1072 else 1073 assert (!buffer->has_separate_output ()); 1074 } 1075 } 1076 else 1077 { 1078 /* in-place backward substitution/positioning */ 1079 if (Proxy::table_index == 0) 1080 buffer->remove_output (); 1081 buffer->idx = buffer->len - 1; 1082 1083 apply_backward (c, accel, subtables); 1084 } 1085 } 1086 1087 template <typename Proxy> 1088 inline void hb_ot_map_t::apply (const Proxy &proxy, 1089 const hb_ot_shape_plan_t *plan, 1090 hb_font_t *font, 1091 hb_buffer_t *buffer) const 1092 { 1093 const unsigned int table_index = proxy.table_index; 1094 unsigned int i = 0; 1095 OT::hb_apply_context_t c (table_index, font, buffer); 1096 c.set_recurse_func (Proxy::Lookup::apply_recurse_func); 1097 1098 for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) { 1099 const stage_map_t *stage = &stages[table_index][stage_index]; 1100 for (; i < stage->last_lookup; i++) 1101 { 1102 unsigned int lookup_index = lookups[table_index][i].index; 1103 if (!buffer->message (font, "start lookup %d", lookup_index)) continue; 1104 c.set_lookup_index (lookup_index); 1105 c.set_lookup_mask (lookups[table_index][i].mask); 1106 c.set_auto_zwj (lookups[table_index][i].auto_zwj); 1107 apply_string<Proxy> (&c, 1108 proxy.table.get_lookup (lookup_index), 1109 proxy.accels[lookup_index]); 1110 (void) buffer->message (font, "end lookup %d", lookup_index); 1111 } 1112 1113 if (stage->pause_func) 1114 { 1115 buffer->clear_output (); 1116 stage->pause_func (plan, font, buffer); 1117 } 1118 } 1119 } 1120 1121 void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const 1122 { 1123 GSUBProxy proxy (font->face); 1124 apply (proxy, plan, font, buffer); 1125 } 1126 1127 void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const 1128 { 1129 GPOSProxy proxy (font->face); 1130 apply (proxy, plan, font, buffer); 1131 } 1132 1133 HB_INTERNAL void 1134 hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c, 1135 const OT::SubstLookup &lookup, 1136 const hb_ot_layout_lookup_accelerator_t &accel) 1137 { 1138 apply_string<GSUBProxy> (c, lookup, accel); 1139 } 1140