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