1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 // This file is available under and governed by the GNU General Public 26 // License version 2 only, as published by the Free Software Foundation. 27 // However, the following notice accompanied the original version of this 28 // file: 29 // 30 /* 31 * Copyright © 1998-2004 David Turner and Werner Lemberg 32 * Copyright © 2006 Behdad Esfahbod 33 * Copyright © 2007,2008,2009 Red Hat, Inc. 34 * Copyright © 2012,2013 Google, Inc. 35 * 36 * This is part of HarfBuzz, a text shaping library. 37 * 38 * Permission is hereby granted, without written agreement and without 39 * license or royalty fees, to use, copy, modify, and distribute this 40 * software and its documentation for any purpose, provided that the 41 * above copyright notice and the following two paragraphs appear in 42 * all copies of this software. 43 * 44 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 45 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 46 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 47 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 48 * DAMAGE. 49 * 50 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 51 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 52 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 53 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 54 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 55 * 56 * Red Hat Author(s): Behdad Esfahbod 57 * Google Author(s): Behdad Esfahbod 58 */ 59 60 #include "hb-open-type-private.hh" 61 #include "hb-ot-layout-private.hh" 62 63 #include "hb-ot-layout-gdef-table.hh" 64 #include "hb-ot-layout-gsub-table.hh" 65 #include "hb-ot-layout-gpos-table.hh" 66 #include "hb-ot-layout-jstf-table.hh" 67 68 #include "hb-ot-map-private.hh" 69 70 #include <stdlib.h> 71 #include <string.h> 72 73 74 HB_SHAPER_DATA_ENSURE_DECLARE(ot, face) 75 76 hb_ot_layout_t * 77 _hb_ot_layout_create (hb_face_t *face) 78 { 79 hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t)); 80 if (unlikely (!layout)) 81 return NULL; 82 83 layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF)); 84 layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob); 85 86 layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB)); 87 layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob); 88 89 layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS)); 90 layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob); 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 * Since: 0.9.7 163 **/ 164 hb_ot_layout_glyph_class_t 165 hb_ot_layout_get_glyph_class (hb_face_t *face, 166 hb_codepoint_t glyph) 167 { 168 return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph); 169 } 170 171 /** 172 * Since: 0.9.7 173 **/ 174 void 175 hb_ot_layout_get_glyphs_in_class (hb_face_t *face, 176 hb_ot_layout_glyph_class_t klass, 177 hb_set_t *glyphs /* OUT */) 178 { 179 return _get_gdef (face).get_glyphs_in_class (klass, glyphs); 180 } 181 182 unsigned int 183 hb_ot_layout_get_attach_points (hb_face_t *face, 184 hb_codepoint_t glyph, 185 unsigned int start_offset, 186 unsigned int *point_count /* IN/OUT */, 187 unsigned int *point_array /* OUT */) 188 { 189 return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array); 190 } 191 192 unsigned int 193 hb_ot_layout_get_ligature_carets (hb_font_t *font, 194 hb_direction_t direction, 195 hb_codepoint_t glyph, 196 unsigned int start_offset, 197 unsigned int *caret_count /* IN/OUT */, 198 int *caret_array /* OUT */) 199 { 200 return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array); 201 } 202 203 204 /* 205 * GSUB/GPOS 206 */ 207 208 static const OT::GSUBGPOS& 209 get_gsubgpos_table (hb_face_t *face, 210 hb_tag_t table_tag) 211 { 212 switch (table_tag) { 213 case HB_OT_TAG_GSUB: return _get_gsub (face); 214 case HB_OT_TAG_GPOS: return _get_gpos (face); 215 default: return OT::Null(OT::GSUBGPOS); 216 } 217 } 218 219 220 unsigned int 221 hb_ot_layout_table_get_script_tags (hb_face_t *face, 222 hb_tag_t table_tag, 223 unsigned int start_offset, 224 unsigned int *script_count /* IN/OUT */, 225 hb_tag_t *script_tags /* OUT */) 226 { 227 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 228 229 return g.get_script_tags (start_offset, script_count, script_tags); 230 } 231 232 #define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n') 233 234 hb_bool_t 235 hb_ot_layout_table_find_script (hb_face_t *face, 236 hb_tag_t table_tag, 237 hb_tag_t script_tag, 238 unsigned int *script_index) 239 { 240 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX); 241 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 242 243 if (g.find_script_index (script_tag, script_index)) 244 return true; 245 246 /* try finding 'DFLT' */ 247 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) 248 return false; 249 250 /* try with 'dflt'; MS site has had typos and many fonts use it now :(. 251 * including many versions of DejaVu Sans Mono! */ 252 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) 253 return false; 254 255 /* try with 'latn'; some old fonts put their features there even though 256 they're really trying to support Thai, for example :( */ 257 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) 258 return false; 259 260 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 261 return false; 262 } 263 264 hb_bool_t 265 hb_ot_layout_table_choose_script (hb_face_t *face, 266 hb_tag_t table_tag, 267 const hb_tag_t *script_tags, 268 unsigned int *script_index, 269 hb_tag_t *chosen_script) 270 { 271 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX); 272 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 273 274 while (*script_tags) 275 { 276 if (g.find_script_index (*script_tags, script_index)) { 277 if (chosen_script) 278 *chosen_script = *script_tags; 279 return true; 280 } 281 script_tags++; 282 } 283 284 /* try finding 'DFLT' */ 285 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) { 286 if (chosen_script) 287 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT; 288 return false; 289 } 290 291 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ 292 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) { 293 if (chosen_script) 294 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE; 295 return false; 296 } 297 298 /* try with 'latn'; some old fonts put their features there even though 299 they're really trying to support Thai, for example :( */ 300 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) { 301 if (chosen_script) 302 *chosen_script = HB_OT_TAG_LATIN_SCRIPT; 303 return false; 304 } 305 306 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 307 if (chosen_script) 308 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX; 309 return false; 310 } 311 312 unsigned int 313 hb_ot_layout_table_get_feature_tags (hb_face_t *face, 314 hb_tag_t table_tag, 315 unsigned int start_offset, 316 unsigned int *feature_count /* IN/OUT */, 317 hb_tag_t *feature_tags /* OUT */) 318 { 319 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 320 321 return g.get_feature_tags (start_offset, feature_count, feature_tags); 322 } 323 324 hb_bool_t 325 hb_ot_layout_table_find_feature (hb_face_t *face, 326 hb_tag_t table_tag, 327 hb_tag_t feature_tag, 328 unsigned int *feature_index) 329 { 330 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX); 331 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 332 333 unsigned int num_features = g.get_feature_count (); 334 for (unsigned int i = 0; i < num_features; i++) 335 { 336 if (feature_tag == g.get_feature_tag (i)) { 337 if (feature_index) *feature_index = i; 338 return true; 339 } 340 } 341 342 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; 343 return false; 344 } 345 346 347 unsigned int 348 hb_ot_layout_script_get_language_tags (hb_face_t *face, 349 hb_tag_t table_tag, 350 unsigned int script_index, 351 unsigned int start_offset, 352 unsigned int *language_count /* IN/OUT */, 353 hb_tag_t *language_tags /* OUT */) 354 { 355 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); 356 357 return s.get_lang_sys_tags (start_offset, language_count, language_tags); 358 } 359 360 hb_bool_t 361 hb_ot_layout_script_find_language (hb_face_t *face, 362 hb_tag_t table_tag, 363 unsigned int script_index, 364 hb_tag_t language_tag, 365 unsigned int *language_index) 366 { 367 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX); 368 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); 369 370 if (s.find_lang_sys_index (language_tag, language_index)) 371 return true; 372 373 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ 374 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index)) 375 return false; 376 377 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX; 378 return false; 379 } 380 381 hb_bool_t 382 hb_ot_layout_language_get_required_feature_index (hb_face_t *face, 383 hb_tag_t table_tag, 384 unsigned int script_index, 385 unsigned int language_index, 386 unsigned int *feature_index) 387 { 388 return hb_ot_layout_language_get_required_feature (face, 389 table_tag, 390 script_index, 391 language_index, 392 feature_index, 393 NULL); 394 } 395 396 /** 397 * Since: 0.9.30 398 **/ 399 hb_bool_t 400 hb_ot_layout_language_get_required_feature (hb_face_t *face, 401 hb_tag_t table_tag, 402 unsigned int script_index, 403 unsigned int language_index, 404 unsigned int *feature_index, 405 hb_tag_t *feature_tag) 406 { 407 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 408 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 409 410 unsigned int index = l.get_required_feature_index (); 411 if (feature_index) *feature_index = index; 412 if (feature_tag) *feature_tag = g.get_feature_tag (index); 413 414 return l.has_required_feature (); 415 } 416 417 unsigned int 418 hb_ot_layout_language_get_feature_indexes (hb_face_t *face, 419 hb_tag_t table_tag, 420 unsigned int script_index, 421 unsigned int language_index, 422 unsigned int start_offset, 423 unsigned int *feature_count /* IN/OUT */, 424 unsigned int *feature_indexes /* OUT */) 425 { 426 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 427 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 428 429 return l.get_feature_indexes (start_offset, feature_count, feature_indexes); 430 } 431 432 unsigned int 433 hb_ot_layout_language_get_feature_tags (hb_face_t *face, 434 hb_tag_t table_tag, 435 unsigned int script_index, 436 unsigned int language_index, 437 unsigned int start_offset, 438 unsigned int *feature_count /* IN/OUT */, 439 hb_tag_t *feature_tags /* OUT */) 440 { 441 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 442 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 443 444 ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t)); 445 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags); 446 447 if (feature_tags) { 448 unsigned int count = *feature_count; 449 for (unsigned int i = 0; i < count; i++) 450 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]); 451 } 452 453 return ret; 454 } 455 456 457 hb_bool_t 458 hb_ot_layout_language_find_feature (hb_face_t *face, 459 hb_tag_t table_tag, 460 unsigned int script_index, 461 unsigned int language_index, 462 hb_tag_t feature_tag, 463 unsigned int *feature_index) 464 { 465 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX); 466 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 467 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); 468 469 unsigned int num_features = l.get_feature_count (); 470 for (unsigned int i = 0; i < num_features; i++) { 471 unsigned int f_index = l.get_feature_index (i); 472 473 if (feature_tag == g.get_feature_tag (f_index)) { 474 if (feature_index) *feature_index = f_index; 475 return true; 476 } 477 } 478 479 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; 480 return false; 481 } 482 483 /** 484 * Since: 0.9.7 485 **/ 486 unsigned int 487 hb_ot_layout_feature_get_lookups (hb_face_t *face, 488 hb_tag_t table_tag, 489 unsigned int feature_index, 490 unsigned int start_offset, 491 unsigned int *lookup_count /* IN/OUT */, 492 unsigned int *lookup_indexes /* OUT */) 493 { 494 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); 495 const OT::Feature &f = g.get_feature (feature_index); 496 497 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes); 498 } 499 500 /** 501 * Since: 0.9.22 502 **/ 503 unsigned int 504 hb_ot_layout_table_get_lookup_count (hb_face_t *face, 505 hb_tag_t table_tag) 506 { 507 switch (table_tag) 508 { 509 case HB_OT_TAG_GSUB: 510 { 511 return hb_ot_layout_from_face (face)->gsub_lookup_count; 512 } 513 case HB_OT_TAG_GPOS: 514 { 515 return hb_ot_layout_from_face (face)->gpos_lookup_count; 516 } 517 } 518 return 0; 519 } 520 521 static void 522 _hb_ot_layout_collect_lookups_lookups (hb_face_t *face, 523 hb_tag_t table_tag, 524 unsigned int feature_index, 525 hb_set_t *lookup_indexes /* OUT */) 526 { 527 unsigned int lookup_indices[32]; 528 unsigned int offset, len; 529 530 offset = 0; 531 do { 532 len = ARRAY_LENGTH (lookup_indices); 533 hb_ot_layout_feature_get_lookups (face, 534 table_tag, 535 feature_index, 536 offset, &len, 537 lookup_indices); 538 539 for (unsigned int i = 0; i < len; i++) 540 lookup_indexes->add (lookup_indices[i]); 541 542 offset += len; 543 } while (len == ARRAY_LENGTH (lookup_indices)); 544 } 545 546 static void 547 _hb_ot_layout_collect_lookups_features (hb_face_t *face, 548 hb_tag_t table_tag, 549 unsigned int script_index, 550 unsigned int language_index, 551 const hb_tag_t *features, 552 hb_set_t *lookup_indexes /* OUT */) 553 { 554 if (!features) 555 { 556 unsigned int required_feature_index; 557 if (hb_ot_layout_language_get_required_feature (face, 558 table_tag, 559 script_index, 560 language_index, 561 &required_feature_index, 562 NULL)) 563 _hb_ot_layout_collect_lookups_lookups (face, 564 table_tag, 565 required_feature_index, 566 lookup_indexes); 567 568 /* All features */ 569 unsigned int feature_indices[32]; 570 unsigned int offset, len; 571 572 offset = 0; 573 do { 574 len = ARRAY_LENGTH (feature_indices); 575 hb_ot_layout_language_get_feature_indexes (face, 576 table_tag, 577 script_index, 578 language_index, 579 offset, &len, 580 feature_indices); 581 582 for (unsigned int i = 0; i < len; i++) 583 _hb_ot_layout_collect_lookups_lookups (face, 584 table_tag, 585 feature_indices[i], 586 lookup_indexes); 587 588 offset += len; 589 } while (len == ARRAY_LENGTH (feature_indices)); 590 } 591 else 592 { 593 for (; *features; features++) 594 { 595 unsigned int feature_index; 596 if (hb_ot_layout_language_find_feature (face, 597 table_tag, 598 script_index, 599 language_index, 600 *features, 601 &feature_index)) 602 _hb_ot_layout_collect_lookups_lookups (face, 603 table_tag, 604 feature_index, 605 lookup_indexes); 606 } 607 } 608 } 609 610 static void 611 _hb_ot_layout_collect_lookups_languages (hb_face_t *face, 612 hb_tag_t table_tag, 613 unsigned int script_index, 614 const hb_tag_t *languages, 615 const hb_tag_t *features, 616 hb_set_t *lookup_indexes /* OUT */) 617 { 618 _hb_ot_layout_collect_lookups_features (face, 619 table_tag, 620 script_index, 621 HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, 622 features, 623 lookup_indexes); 624 625 if (!languages) 626 { 627 /* All languages */ 628 unsigned int count = hb_ot_layout_script_get_language_tags (face, 629 table_tag, 630 script_index, 631 0, NULL, NULL); 632 for (unsigned int language_index = 0; language_index < count; language_index++) 633 _hb_ot_layout_collect_lookups_features (face, 634 table_tag, 635 script_index, 636 language_index, 637 features, 638 lookup_indexes); 639 } 640 else 641 { 642 for (; *languages; languages++) 643 { 644 unsigned int language_index; 645 if (hb_ot_layout_script_find_language (face, 646 table_tag, 647 script_index, 648 *languages, 649 &language_index)) 650 _hb_ot_layout_collect_lookups_features (face, 651 table_tag, 652 script_index, 653 language_index, 654 features, 655 lookup_indexes); 656 } 657 } 658 } 659 660 /** 661 * Since: 0.9.8 662 **/ 663 void 664 hb_ot_layout_collect_lookups (hb_face_t *face, 665 hb_tag_t table_tag, 666 const hb_tag_t *scripts, 667 const hb_tag_t *languages, 668 const hb_tag_t *features, 669 hb_set_t *lookup_indexes /* OUT */) 670 { 671 if (!scripts) 672 { 673 /* All scripts */ 674 unsigned int count = hb_ot_layout_table_get_script_tags (face, 675 table_tag, 676 0, NULL, NULL); 677 for (unsigned int script_index = 0; script_index < count; script_index++) 678 _hb_ot_layout_collect_lookups_languages (face, 679 table_tag, 680 script_index, 681 languages, 682 features, 683 lookup_indexes); 684 } 685 else 686 { 687 for (; *scripts; scripts++) 688 { 689 unsigned int script_index; 690 if (hb_ot_layout_table_find_script (face, 691 table_tag, 692 *scripts, 693 &script_index)) 694 _hb_ot_layout_collect_lookups_languages (face, 695 table_tag, 696 script_index, 697 languages, 698 features, 699 lookup_indexes); 700 } 701 } 702 } 703 704 /** 705 * Since: 0.9.7 706 **/ 707 void 708 hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, 709 hb_tag_t table_tag, 710 unsigned int lookup_index, 711 hb_set_t *glyphs_before, /* OUT. May be NULL */ 712 hb_set_t *glyphs_input, /* OUT. May be NULL */ 713 hb_set_t *glyphs_after, /* OUT. May be NULL */ 714 hb_set_t *glyphs_output /* OUT. May be NULL */) 715 { 716 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return; 717 718 OT::hb_collect_glyphs_context_t c (face, 719 glyphs_before, 720 glyphs_input, 721 glyphs_after, 722 glyphs_output); 723 724 switch (table_tag) 725 { 726 case HB_OT_TAG_GSUB: 727 { 728 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); 729 l.collect_glyphs (&c); 730 return; 731 } 732 case HB_OT_TAG_GPOS: 733 { 734 const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index); 735 l.collect_glyphs (&c); 736 return; 737 } 738 } 739 } 740 741 742 /* 743 * OT::GSUB 744 */ 745 746 hb_bool_t 747 hb_ot_layout_has_substitution (hb_face_t *face) 748 { 749 return &_get_gsub (face) != &OT::Null(OT::GSUB); 750 } 751 752 /** 753 * Since: 0.9.7 754 **/ 755 hb_bool_t 756 hb_ot_layout_lookup_would_substitute (hb_face_t *face, 757 unsigned int lookup_index, 758 const hb_codepoint_t *glyphs, 759 unsigned int glyphs_length, 760 hb_bool_t zero_context) 761 { 762 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false; 763 return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context); 764 } 765 766 hb_bool_t 767 hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face, 768 unsigned int lookup_index, 769 const hb_codepoint_t *glyphs, 770 unsigned int glyphs_length, 771 hb_bool_t zero_context) 772 { 773 if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false; 774 OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context); 775 776 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); 777 778 return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]); 779 } 780 781 void 782 hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer) 783 { 784 OT::GSUB::substitute_start (font, buffer); 785 } 786 787 void 788 hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer) 789 { 790 OT::GSUB::substitute_finish (font, buffer); 791 } 792 793 /** 794 * Since: 0.9.7 795 **/ 796 void 797 hb_ot_layout_lookup_substitute_closure (hb_face_t *face, 798 unsigned int lookup_index, 799 hb_set_t *glyphs) 800 { 801 OT::hb_closure_context_t c (face, glyphs); 802 803 const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index); 804 805 l.closure (&c); 806 } 807 808 /* 809 * OT::GPOS 810 */ 811 812 hb_bool_t 813 hb_ot_layout_has_positioning (hb_face_t *face) 814 { 815 return &_get_gpos (face) != &OT::Null(OT::GPOS); 816 } 817 818 void 819 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer) 820 { 821 OT::GPOS::position_start (font, buffer); 822 } 823 824 void 825 hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer) 826 { 827 OT::GPOS::position_finish (font, buffer); 828 } 829 830 /** 831 * Since: 0.9.10 832 **/ 833 hb_bool_t 834 hb_ot_layout_get_size_params (hb_face_t *face, 835 unsigned int *design_size, /* OUT. May be NULL */ 836 unsigned int *subfamily_id, /* OUT. May be NULL */ 837 unsigned int *subfamily_name_id, /* OUT. May be NULL */ 838 unsigned int *range_start, /* OUT. May be NULL */ 839 unsigned int *range_end /* OUT. May be NULL */) 840 { 841 const OT::GPOS &gpos = _get_gpos (face); 842 const hb_tag_t tag = HB_TAG ('s','i','z','e'); 843 844 unsigned int num_features = gpos.get_feature_count (); 845 for (unsigned int i = 0; i < num_features; i++) 846 { 847 if (tag == gpos.get_feature_tag (i)) 848 { 849 const OT::Feature &f = gpos.get_feature (i); 850 const OT::FeatureParamsSize ¶ms = f.get_feature_params ().get_size_params (tag); 851 852 if (params.designSize) 853 { 854 #define PARAM(a, A) if (a) *a = params.A 855 PARAM (design_size, designSize); 856 PARAM (subfamily_id, subfamilyID); 857 PARAM (subfamily_name_id, subfamilyNameID); 858 PARAM (range_start, rangeStart); 859 PARAM (range_end, rangeEnd); 860 #undef PARAM 861 862 return true; 863 } 864 } 865 } 866 867 #define PARAM(a, A) if (a) *a = 0 868 PARAM (design_size, designSize); 869 PARAM (subfamily_id, subfamilyID); 870 PARAM (subfamily_name_id, subfamilyNameID); 871 PARAM (range_start, rangeStart); 872 PARAM (range_end, rangeEnd); 873 #undef PARAM 874 875 return false; 876 } 877 878 879 /* 880 * Parts of different types are implemented here such that they have direct 881 * access to GSUB/GPOS lookups. 882 */ 883 884 885 struct GSUBProxy 886 { 887 static const unsigned int table_index = 0; 888 static const bool inplace = false; 889 typedef OT::SubstLookup Lookup; 890 891 GSUBProxy (hb_face_t *face) : 892 table (*hb_ot_layout_from_face (face)->gsub), 893 accels (hb_ot_layout_from_face (face)->gsub_accels) {} 894 895 const OT::GSUB &table; 896 const hb_ot_layout_lookup_accelerator_t *accels; 897 }; 898 899 struct GPOSProxy 900 { 901 static const unsigned int table_index = 1; 902 static const bool inplace = true; 903 typedef OT::PosLookup Lookup; 904 905 GPOSProxy (hb_face_t *face) : 906 table (*hb_ot_layout_from_face (face)->gpos), 907 accels (hb_ot_layout_from_face (face)->gpos_accels) {} 908 909 const OT::GPOS &table; 910 const hb_ot_layout_lookup_accelerator_t *accels; 911 }; 912 913 914 template <typename Obj> 915 static inline bool 916 apply_forward (OT::hb_apply_context_t *c, 917 const Obj &obj, 918 const hb_ot_layout_lookup_accelerator_t &accel) 919 { 920 bool ret = false; 921 hb_buffer_t *buffer = c->buffer; 922 while (buffer->idx < buffer->len) 923 { 924 if (accel.may_have (buffer->cur().codepoint) && 925 (buffer->cur().mask & c->lookup_mask) && 926 c->check_glyph_property (&buffer->cur(), c->lookup_props) && 927 obj.apply (c)) 928 ret = true; 929 else 930 buffer->next_glyph (); 931 } 932 return ret; 933 } 934 935 template <typename Obj> 936 static inline bool 937 apply_backward (OT::hb_apply_context_t *c, 938 const Obj &obj, 939 const hb_ot_layout_lookup_accelerator_t &accel) 940 { 941 bool ret = false; 942 hb_buffer_t *buffer = c->buffer; 943 do 944 { 945 if (accel.may_have (buffer->cur().codepoint) && 946 (buffer->cur().mask & c->lookup_mask) && 947 c->check_glyph_property (&buffer->cur(), c->lookup_props) && 948 obj.apply (c)) 949 ret = true; 950 /* The reverse lookup doesn't "advance" cursor (for good reason). */ 951 buffer->idx--; 952 953 } 954 while ((int) buffer->idx >= 0); 955 return ret; 956 } 957 958 struct hb_apply_forward_context_t : 959 OT::hb_dispatch_context_t<hb_apply_forward_context_t, bool, HB_DEBUG_APPLY> 960 { 961 inline const char *get_name (void) { return "APPLY_FWD"; } 962 template <typename T> 963 inline return_t dispatch (const T &obj) { return apply_forward (c, obj, accel); } 964 static return_t default_return_value (void) { return false; } 965 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return true; } 966 967 hb_apply_forward_context_t (OT::hb_apply_context_t *c_, 968 const hb_ot_layout_lookup_accelerator_t &accel_) : 969 c (c_), 970 accel (accel_), 971 debug_depth (0) {} 972 973 OT::hb_apply_context_t *c; 974 const hb_ot_layout_lookup_accelerator_t &accel; 975 unsigned int debug_depth; 976 }; 977 978 template <typename Proxy> 979 static inline void 980 apply_string (OT::hb_apply_context_t *c, 981 const typename Proxy::Lookup &lookup, 982 const hb_ot_layout_lookup_accelerator_t &accel) 983 { 984 hb_buffer_t *buffer = c->buffer; 985 986 if (unlikely (!buffer->len || !c->lookup_mask)) 987 return; 988 989 c->set_lookup_props (lookup.get_props ()); 990 991 if (likely (!lookup.is_reverse ())) 992 { 993 /* in/out forward substitution/positioning */ 994 if (Proxy::table_index == 0) 995 buffer->clear_output (); 996 buffer->idx = 0; 997 998 bool ret; 999 if (lookup.get_subtable_count () == 1) 1000 { 1001 hb_apply_forward_context_t c_forward (c, accel); 1002 ret = lookup.dispatch (&c_forward); 1003 } 1004 else 1005 ret = apply_forward (c, lookup, accel); 1006 if (ret) 1007 { 1008 if (!Proxy::inplace) 1009 buffer->swap_buffers (); 1010 else 1011 assert (!buffer->has_separate_output ()); 1012 } 1013 } 1014 else 1015 { 1016 /* in-place backward substitution/positioning */ 1017 if (Proxy::table_index == 0) 1018 buffer->remove_output (); 1019 buffer->idx = buffer->len - 1; 1020 1021 apply_backward (c, lookup, accel); 1022 } 1023 } 1024 1025 template <typename Proxy> 1026 inline void hb_ot_map_t::apply (const Proxy &proxy, 1027 const hb_ot_shape_plan_t *plan, 1028 hb_font_t *font, 1029 hb_buffer_t *buffer) const 1030 { 1031 const unsigned int table_index = proxy.table_index; 1032 unsigned int i = 0; 1033 OT::hb_apply_context_t c (table_index, font, buffer); 1034 c.set_recurse_func (Proxy::Lookup::apply_recurse_func); 1035 1036 for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) { 1037 const stage_map_t *stage = &stages[table_index][stage_index]; 1038 for (; i < stage->last_lookup; i++) 1039 { 1040 #if 0 1041 char buf[4096]; 1042 hb_buffer_serialize_glyphs (buffer, 0, buffer->len, 1043 buf, sizeof (buf), NULL, 1044 font, 1045 HB_BUFFER_SERIALIZE_FORMAT_TEXT, 1046 Proxy::table_index == 0 ? 1047 HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS : 1048 HB_BUFFER_SERIALIZE_FLAG_DEFAULT); 1049 printf ("buf: [%s]\n", buf); 1050 #endif 1051 1052 unsigned int lookup_index = lookups[table_index][i].index; 1053 c.set_lookup_index (lookup_index); 1054 c.set_lookup_mask (lookups[table_index][i].mask); 1055 c.set_auto_zwj (lookups[table_index][i].auto_zwj); 1056 apply_string<Proxy> (&c, 1057 proxy.table.get_lookup (lookup_index), 1058 proxy.accels[lookup_index]); 1059 } 1060 1061 if (stage->pause_func) 1062 { 1063 buffer->clear_output (); 1064 stage->pause_func (plan, font, buffer); 1065 } 1066 } 1067 } 1068 1069 void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const 1070 { 1071 GSUBProxy proxy (font->face); 1072 apply (proxy, plan, font, buffer); 1073 } 1074 1075 void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const 1076 { 1077 GPOSProxy proxy (font->face); 1078 apply (proxy, plan, font, buffer); 1079 } 1080 1081 HB_INTERNAL void 1082 hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c, 1083 const OT::SubstLookup &lookup, 1084 const hb_ot_layout_lookup_accelerator_t &accel) 1085 { 1086 apply_string<GSUBProxy> (c, lookup, accel); 1087 }