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