Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/harfbuzz/src/hb-ot-layout.cc @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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.hh" | |
| 32 | |
| 33 #ifndef HB_NO_OT_LAYOUT | |
| 34 | |
| 35 #ifdef HB_NO_OT_TAG | |
| 36 #error "Cannot compile hb-ot-layout.cc with HB_NO_OT_TAG." | |
| 37 #endif | |
| 38 | |
| 39 #include "hb-open-type.hh" | |
| 40 #include "hb-ot-layout.hh" | |
| 41 #include "hb-ot-face.hh" | |
| 42 #include "hb-ot-map.hh" | |
| 43 #include "hb-map.hh" | |
| 44 | |
| 45 #include "hb-ot-kern-table.hh" | |
| 46 #include "hb-ot-layout-gdef-table.hh" | |
| 47 #include "hb-ot-layout-gsub-table.hh" | |
| 48 #include "hb-ot-layout-gpos-table.hh" | |
| 49 #include "hb-ot-layout-base-table.hh" | |
| 50 #include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise. | |
| 51 #include "hb-ot-name-table.hh" | |
| 52 #include "hb-ot-os2-table.hh" | |
| 53 | |
| 54 #include "hb-aat-layout-morx-table.hh" | |
| 55 #include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise. | |
| 56 | |
| 57 using OT::Layout::GSUB; | |
| 58 using OT::Layout::GPOS; | |
| 59 | |
| 60 /** | |
| 61 * SECTION:hb-ot-layout | |
| 62 * @title: hb-ot-layout | |
| 63 * @short_description: OpenType Layout | |
| 64 * @include: hb-ot.h | |
| 65 * | |
| 66 * Functions for querying OpenType Layout features in the font face. | |
| 67 **/ | |
| 68 | |
| 69 | |
| 70 /* | |
| 71 * kern | |
| 72 */ | |
| 73 | |
| 74 #ifndef HB_NO_OT_KERN | |
| 75 /** | |
| 76 * hb_ot_layout_has_kerning: | |
| 77 * @face: The #hb_face_t to work on | |
| 78 * | |
| 79 * Tests whether a face includes any kerning data in the 'kern' table. | |
| 80 * Does NOT test for kerning lookups in the GPOS table. | |
| 81 * | |
| 82 * Return value: `true` if data found, `false` otherwise | |
| 83 * | |
| 84 **/ | |
| 85 bool | |
| 86 hb_ot_layout_has_kerning (hb_face_t *face) | |
| 87 { | |
| 88 return face->table.kern->has_data (); | |
| 89 } | |
| 90 | |
| 91 /** | |
| 92 * hb_ot_layout_has_machine_kerning: | |
| 93 * @face: The #hb_face_t to work on | |
| 94 * | |
| 95 * Tests whether a face includes any state-machine kerning in the 'kern' table. | |
| 96 * Does NOT examine the GPOS table. | |
| 97 * | |
| 98 * Return value: `true` if data found, `false` otherwise | |
| 99 * | |
| 100 **/ | |
| 101 bool | |
| 102 hb_ot_layout_has_machine_kerning (hb_face_t *face) | |
| 103 { | |
| 104 return face->table.kern->has_state_machine (); | |
| 105 } | |
| 106 | |
| 107 /** | |
| 108 * hb_ot_layout_has_cross_kerning: | |
| 109 * @face: The #hb_face_t to work on | |
| 110 * | |
| 111 * Tests whether a face has any cross-stream kerning (i.e., kerns | |
| 112 * that make adjustments perpendicular to the direction of the text | |
| 113 * flow: Y adjustments in horizontal text or X adjustments in | |
| 114 * vertical text) in the 'kern' table. | |
| 115 * | |
| 116 * Does NOT examine the GPOS table. | |
| 117 * | |
| 118 * Return value: `true` is data found, `false` otherwise | |
| 119 * | |
| 120 **/ | |
| 121 bool | |
| 122 hb_ot_layout_has_cross_kerning (hb_face_t *face) | |
| 123 { | |
| 124 return face->table.kern->has_cross_stream (); | |
| 125 } | |
| 126 | |
| 127 void | |
| 128 hb_ot_layout_kern (const hb_ot_shape_plan_t *plan, | |
| 129 hb_font_t *font, | |
| 130 hb_buffer_t *buffer) | |
| 131 { | |
| 132 hb_blob_t *blob = font->face->table.kern.get_blob (); | |
| 133 const AAT::kern& kern = *blob->as<AAT::kern> (); | |
| 134 | |
| 135 AAT::hb_aat_apply_context_t c (plan, font, buffer, blob); | |
| 136 | |
| 137 if (!buffer->message (font, "start table kern")) return; | |
| 138 kern.apply (&c); | |
| 139 (void) buffer->message (font, "end table kern"); | |
| 140 } | |
| 141 #endif | |
| 142 | |
| 143 | |
| 144 /* | |
| 145 * GDEF | |
| 146 */ | |
| 147 | |
| 148 bool | |
| 149 OT::GDEF::is_blocklisted (hb_blob_t *blob, | |
| 150 hb_face_t *face) const | |
| 151 { | |
| 152 #ifdef HB_NO_OT_LAYOUT_BLOCKLIST | |
| 153 return false; | |
| 154 #endif | |
| 155 /* The ugly business of blocklisting individual fonts' tables happen here! | |
| 156 * See this thread for why we finally had to bend in and do this: | |
| 157 * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html | |
| 158 * | |
| 159 * In certain versions of Times New Roman Italic and Bold Italic, | |
| 160 * ASCII double quotation mark U+0022 has wrong glyph class 3 (mark) | |
| 161 * in GDEF. Many versions of Tahoma have bad GDEF tables that | |
| 162 * incorrectly classify some spacing marks such as certain IPA | |
| 163 * symbols as glyph class 3. So do older versions of Microsoft | |
| 164 * Himalaya, and the version of Cantarell shipped by Ubuntu 16.04. | |
| 165 * | |
| 166 * Nuke the GDEF tables of to avoid unwanted width-zeroing. | |
| 167 * | |
| 168 * See https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 | |
| 169 * https://bugzilla.mozilla.org/show_bug.cgi?id=1279693 | |
| 170 * https://bugzilla.mozilla.org/show_bug.cgi?id=1279875 | |
| 171 */ | |
| 172 switch HB_CODEPOINT_ENCODE3(blob->length, | |
| 173 face->table.GSUB->table.get_length (), | |
| 174 face->table.GPOS->table.get_length ()) | |
| 175 { | |
| 176 /* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */ | |
| 177 case HB_CODEPOINT_ENCODE3 (442, 2874, 42038): | |
| 178 /* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */ | |
| 179 case HB_CODEPOINT_ENCODE3 (430, 2874, 40662): | |
| 180 /* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */ | |
| 181 case HB_CODEPOINT_ENCODE3 (442, 2874, 39116): | |
| 182 /* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */ | |
| 183 case HB_CODEPOINT_ENCODE3 (430, 2874, 39374): | |
| 184 /* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */ | |
| 185 case HB_CODEPOINT_ENCODE3 (490, 3046, 41638): | |
| 186 /* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */ | |
| 187 case HB_CODEPOINT_ENCODE3 (478, 3046, 41902): | |
| 188 /* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c tahoma.ttf from Windows 8 */ | |
| 189 case HB_CODEPOINT_ENCODE3 (898, 12554, 46470): | |
| 190 /* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc tahomabd.ttf from Windows 8 */ | |
| 191 case HB_CODEPOINT_ENCODE3 (910, 12566, 47732): | |
| 192 /* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e tahoma.ttf from Windows 8.1 */ | |
| 193 case HB_CODEPOINT_ENCODE3 (928, 23298, 59332): | |
| 194 /* sha1sum:6d400781948517c3c0441ba42acb309584b73033 tahomabd.ttf from Windows 8.1 */ | |
| 195 case HB_CODEPOINT_ENCODE3 (940, 23310, 60732): | |
| 196 /* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ | |
| 197 case HB_CODEPOINT_ENCODE3 (964, 23836, 60072): | |
| 198 /* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ | |
| 199 case HB_CODEPOINT_ENCODE3 (976, 23832, 61456): | |
| 200 /* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846 tahoma.ttf from Windows 10 */ | |
| 201 case HB_CODEPOINT_ENCODE3 (994, 24474, 60336): | |
| 202 /* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343 tahomabd.ttf from Windows 10 */ | |
| 203 case HB_CODEPOINT_ENCODE3 (1006, 24470, 61740): | |
| 204 /* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ | |
| 205 case HB_CODEPOINT_ENCODE3 (1006, 24576, 61346): | |
| 206 /* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ | |
| 207 case HB_CODEPOINT_ENCODE3 (1018, 24572, 62828): | |
| 208 /* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5 tahoma.ttf from Windows 10 AU */ | |
| 209 case HB_CODEPOINT_ENCODE3 (1006, 24576, 61352): | |
| 210 /* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2 tahomabd.ttf from Windows 10 AU */ | |
| 211 case HB_CODEPOINT_ENCODE3 (1018, 24572, 62834): | |
| 212 /* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7 Tahoma.ttf from Mac OS X 10.9 */ | |
| 213 case HB_CODEPOINT_ENCODE3 (832, 7324, 47162): | |
| 214 /* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba Tahoma Bold.ttf from Mac OS X 10.9 */ | |
| 215 case HB_CODEPOINT_ENCODE3 (844, 7302, 45474): | |
| 216 /* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc himalaya.ttf from Windows 7 */ | |
| 217 case HB_CODEPOINT_ENCODE3 (180, 13054, 7254): | |
| 218 /* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0 himalaya.ttf from Windows 8 */ | |
| 219 case HB_CODEPOINT_ENCODE3 (192, 12638, 7254): | |
| 220 /* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427 himalaya.ttf from Windows 8.1 */ | |
| 221 case HB_CODEPOINT_ENCODE3 (192, 12690, 7254): | |
| 222 /* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44 cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */ | |
| 223 /* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371 cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */ | |
| 224 case HB_CODEPOINT_ENCODE3 (188, 248, 3852): | |
| 225 /* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */ | |
| 226 /* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */ | |
| 227 case HB_CODEPOINT_ENCODE3 (188, 264, 3426): | |
| 228 /* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */ | |
| 229 case HB_CODEPOINT_ENCODE3 (1058, 47032, 11818): | |
| 230 /* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/ | |
| 231 case HB_CODEPOINT_ENCODE3 (1046, 47030, 12600): | |
| 232 /* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */ | |
| 233 case HB_CODEPOINT_ENCODE3 (1058, 71796, 16770): | |
| 234 /* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */ | |
| 235 case HB_CODEPOINT_ENCODE3 (1046, 71790, 17862): | |
| 236 /* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */ | |
| 237 case HB_CODEPOINT_ENCODE3 (1046, 71788, 17112): | |
| 238 /* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */ | |
| 239 case HB_CODEPOINT_ENCODE3 (1058, 71794, 17514): | |
| 240 /* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */ | |
| 241 case HB_CODEPOINT_ENCODE3 (1330, 109904, 57938): | |
| 242 /* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */ | |
| 243 case HB_CODEPOINT_ENCODE3 (1330, 109904, 58972): | |
| 244 /* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85 Padauk.ttf | |
| 245 * "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */ | |
| 246 case HB_CODEPOINT_ENCODE3 (1004, 59092, 14836): | |
| 247 return true; | |
| 248 } | |
| 249 return false; | |
| 250 } | |
| 251 | |
| 252 static void | |
| 253 _hb_ot_layout_set_glyph_props (hb_font_t *font, | |
| 254 hb_buffer_t *buffer) | |
| 255 { | |
| 256 _hb_buffer_assert_gsubgpos_vars (buffer); | |
| 257 | |
| 258 const OT::GDEF &gdef = *font->face->table.GDEF->table; | |
| 259 unsigned int count = buffer->len; | |
| 260 for (unsigned int i = 0; i < count; i++) | |
| 261 { | |
| 262 _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint)); | |
| 263 _hb_glyph_info_clear_lig_props (&buffer->info[i]); | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 /* Public API */ | |
| 268 | |
| 269 /** | |
| 270 * hb_ot_layout_has_glyph_classes: | |
| 271 * @face: #hb_face_t to work upon | |
| 272 * | |
| 273 * Tests whether a face has any glyph classes defined in its GDEF table. | |
| 274 * | |
| 275 * Return value: `true` if data found, `false` otherwise | |
| 276 * | |
| 277 **/ | |
| 278 hb_bool_t | |
| 279 hb_ot_layout_has_glyph_classes (hb_face_t *face) | |
| 280 { | |
| 281 return face->table.GDEF->table->has_glyph_classes (); | |
| 282 } | |
| 283 | |
| 284 /** | |
| 285 * hb_ot_layout_get_glyph_class: | |
| 286 * @face: The #hb_face_t to work on | |
| 287 * @glyph: The #hb_codepoint_t code point to query | |
| 288 * | |
| 289 * Fetches the GDEF class of the requested glyph in the specified face. | |
| 290 * | |
| 291 * Return value: The #hb_ot_layout_glyph_class_t glyph class of the given code | |
| 292 * point in the GDEF table of the face. | |
| 293 * | |
| 294 * Since: 0.9.7 | |
| 295 **/ | |
| 296 hb_ot_layout_glyph_class_t | |
| 297 hb_ot_layout_get_glyph_class (hb_face_t *face, | |
| 298 hb_codepoint_t glyph) | |
| 299 { | |
| 300 return (hb_ot_layout_glyph_class_t) face->table.GDEF->table->get_glyph_class (glyph); | |
| 301 } | |
| 302 | |
| 303 /** | |
| 304 * hb_ot_layout_get_glyphs_in_class: | |
| 305 * @face: The #hb_face_t to work on | |
| 306 * @klass: The #hb_ot_layout_glyph_class_t GDEF class to retrieve | |
| 307 * @glyphs: (out): The #hb_set_t set of all glyphs belonging to the requested | |
| 308 * class. | |
| 309 * | |
| 310 * Retrieves the set of all glyphs from the face that belong to the requested | |
| 311 * glyph class in the face's GDEF table. | |
| 312 * | |
| 313 * Since: 0.9.7 | |
| 314 **/ | |
| 315 void | |
| 316 hb_ot_layout_get_glyphs_in_class (hb_face_t *face, | |
| 317 hb_ot_layout_glyph_class_t klass, | |
| 318 hb_set_t *glyphs /* OUT */) | |
| 319 { | |
| 320 return face->table.GDEF->table->get_glyphs_in_class (klass, glyphs); | |
| 321 } | |
| 322 | |
| 323 #ifndef HB_NO_LAYOUT_UNUSED | |
| 324 /** | |
| 325 * hb_ot_layout_get_attach_points: | |
| 326 * @face: The #hb_face_t to work on | |
| 327 * @glyph: The #hb_codepoint_t code point to query | |
| 328 * @start_offset: offset of the first attachment point to retrieve | |
| 329 * @point_count: (inout) (optional): Input = the maximum number of attachment points to return; | |
| 330 * Output = the actual number of attachment points returned (may be zero) | |
| 331 * @point_array: (out) (array length=point_count): The array of attachment points found for the query | |
| 332 * | |
| 333 * Fetches a list of all attachment points for the specified glyph in the GDEF | |
| 334 * table of the face. The list returned will begin at the offset provided. | |
| 335 * | |
| 336 * Useful if the client program wishes to cache the list. | |
| 337 * | |
| 338 * Return value: Total number of attachment points for @glyph. | |
| 339 * | |
| 340 **/ | |
| 341 unsigned int | |
| 342 hb_ot_layout_get_attach_points (hb_face_t *face, | |
| 343 hb_codepoint_t glyph, | |
| 344 unsigned int start_offset, | |
| 345 unsigned int *point_count /* IN/OUT */, | |
| 346 unsigned int *point_array /* OUT */) | |
| 347 { | |
| 348 return face->table.GDEF->table->get_attach_points (glyph, | |
| 349 start_offset, | |
| 350 point_count, | |
| 351 point_array); | |
| 352 } | |
| 353 /** | |
| 354 * hb_ot_layout_get_ligature_carets: | |
| 355 * @font: The #hb_font_t to work on | |
| 356 * @direction: The #hb_direction_t text direction to use | |
| 357 * @glyph: The #hb_codepoint_t code point to query | |
| 358 * @start_offset: offset of the first caret position to retrieve | |
| 359 * @caret_count: (inout) (optional): Input = the maximum number of caret positions to return; | |
| 360 * Output = the actual number of caret positions returned (may be zero) | |
| 361 * @caret_array: (out) (array length=caret_count): The array of caret positions found for the query | |
| 362 * | |
| 363 * Fetches a list of the caret positions defined for a ligature glyph in the GDEF | |
| 364 * table of the font. The list returned will begin at the offset provided. | |
| 365 * | |
| 366 * Note that a ligature that is formed from n characters will have n-1 | |
| 367 * caret positions. The first character is not represented in the array, | |
| 368 * since its caret position is the glyph position. | |
| 369 * | |
| 370 * The positions returned by this function are 'unshaped', and will have to | |
| 371 * be fixed up for kerning that may be applied to the ligature glyph. | |
| 372 * | |
| 373 * Return value: Total number of ligature caret positions for @glyph. | |
| 374 * | |
| 375 **/ | |
| 376 unsigned int | |
| 377 hb_ot_layout_get_ligature_carets (hb_font_t *font, | |
| 378 hb_direction_t direction, | |
| 379 hb_codepoint_t glyph, | |
| 380 unsigned int start_offset, | |
| 381 unsigned int *caret_count /* IN/OUT */, | |
| 382 hb_position_t *caret_array /* OUT */) | |
| 383 { | |
| 384 return font->face->table.GDEF->table->get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array); | |
| 385 } | |
| 386 #endif | |
| 387 | |
| 388 | |
| 389 /* | |
| 390 * GSUB/GPOS | |
| 391 */ | |
| 392 | |
| 393 bool | |
| 394 GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED, | |
| 395 hb_face_t *face) const | |
| 396 { | |
| 397 #ifdef HB_NO_OT_LAYOUT_BLOCKLIST | |
| 398 return false; | |
| 399 #endif | |
| 400 return false; | |
| 401 } | |
| 402 | |
| 403 bool | |
| 404 GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED, | |
| 405 hb_face_t *face HB_UNUSED) const | |
| 406 { | |
| 407 #ifdef HB_NO_OT_LAYOUT_BLOCKLIST | |
| 408 return false; | |
| 409 #endif | |
| 410 return false; | |
| 411 } | |
| 412 | |
| 413 static const OT::GSUBGPOS& | |
| 414 get_gsubgpos_table (hb_face_t *face, | |
| 415 hb_tag_t table_tag) | |
| 416 { | |
| 417 switch (table_tag) { | |
| 418 case HB_OT_TAG_GSUB: return *face->table.GSUB->table; | |
| 419 case HB_OT_TAG_GPOS: return *face->table.GPOS->table; | |
| 420 default: return Null (OT::GSUBGPOS); | |
| 421 } | |
| 422 } | |
| 423 | |
| 424 | |
| 425 /** | |
| 426 * hb_ot_layout_table_get_script_tags: | |
| 427 * @face: #hb_face_t to work upon | |
| 428 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 429 * @start_offset: offset of the first script tag to retrieve | |
| 430 * @script_count: (inout) (optional): Input = the maximum number of script tags to return; | |
| 431 * Output = the actual number of script tags returned (may be zero) | |
| 432 * @script_tags: (out) (array length=script_count): The array of #hb_tag_t script tags found for the query | |
| 433 * | |
| 434 * Fetches a list of all scripts enumerated in the specified face's GSUB table | |
| 435 * or GPOS table. The list returned will begin at the offset provided. | |
| 436 * | |
| 437 * Return value: Total number of script tags. | |
| 438 * | |
| 439 **/ | |
| 440 unsigned int | |
| 441 hb_ot_layout_table_get_script_tags (hb_face_t *face, | |
| 442 hb_tag_t table_tag, | |
| 443 unsigned int start_offset, | |
| 444 unsigned int *script_count /* IN/OUT */, | |
| 445 hb_tag_t *script_tags /* OUT */) | |
| 446 { | |
| 447 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 448 | |
| 449 return g.get_script_tags (start_offset, script_count, script_tags); | |
| 450 } | |
| 451 | |
| 452 #define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n') | |
| 453 | |
| 454 /** | |
| 455 * hb_ot_layout_table_find_script: | |
| 456 * @face: #hb_face_t to work upon | |
| 457 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 458 * @script_tag: #hb_tag_t of the script tag requested | |
| 459 * @script_index: (out): The index of the requested script tag | |
| 460 * | |
| 461 * Fetches the index if a given script tag in the specified face's GSUB table | |
| 462 * or GPOS table. | |
| 463 * | |
| 464 * Return value: `true` if the script is found, `false` otherwise | |
| 465 * | |
| 466 **/ | |
| 467 hb_bool_t | |
| 468 hb_ot_layout_table_find_script (hb_face_t *face, | |
| 469 hb_tag_t table_tag, | |
| 470 hb_tag_t script_tag, | |
| 471 unsigned int *script_index /* OUT */) | |
| 472 { | |
| 473 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), ""); | |
| 474 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 475 | |
| 476 if (g.find_script_index (script_tag, script_index)) | |
| 477 return true; | |
| 478 | |
| 479 /* try finding 'DFLT' */ | |
| 480 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) | |
| 481 return false; | |
| 482 | |
| 483 /* try with 'dflt'; MS site has had typos and many fonts use it now :(. | |
| 484 * including many versions of DejaVu Sans Mono! */ | |
| 485 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) | |
| 486 return false; | |
| 487 | |
| 488 /* try with 'latn'; some old fonts put their features there even though | |
| 489 they're really trying to support Thai, for example :( */ | |
| 490 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) | |
| 491 return false; | |
| 492 | |
| 493 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; | |
| 494 return false; | |
| 495 } | |
| 496 | |
| 497 #ifndef HB_DISABLE_DEPRECATED | |
| 498 /** | |
| 499 * hb_ot_layout_table_choose_script: | |
| 500 * @face: #hb_face_t to work upon | |
| 501 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 502 * @script_tags: Array of #hb_tag_t script tags | |
| 503 * @script_index: (out): The index of the requested script tag | |
| 504 * @chosen_script: (out): #hb_tag_t of the script tag requested | |
| 505 * | |
| 506 * Deprecated since 2.0.0 | |
| 507 **/ | |
| 508 hb_bool_t | |
| 509 hb_ot_layout_table_choose_script (hb_face_t *face, | |
| 510 hb_tag_t table_tag, | |
| 511 const hb_tag_t *script_tags, | |
| 512 unsigned int *script_index /* OUT */, | |
| 513 hb_tag_t *chosen_script /* OUT */) | |
| 514 { | |
| 515 const hb_tag_t *t; | |
| 516 for (t = script_tags; *t; t++); | |
| 517 return hb_ot_layout_table_select_script (face, table_tag, t - script_tags, script_tags, script_index, chosen_script); | |
| 518 } | |
| 519 #endif | |
| 520 | |
| 521 /** | |
| 522 * hb_ot_layout_table_select_script: | |
| 523 * @face: #hb_face_t to work upon | |
| 524 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 525 * @script_count: Number of script tags in the array | |
| 526 * @script_tags: Array of #hb_tag_t script tags | |
| 527 * @script_index: (out) (optional): The index of the requested script | |
| 528 * @chosen_script: (out) (optional): #hb_tag_t of the requested script | |
| 529 * | |
| 530 * Selects an OpenType script for @table_tag from the @script_tags array. | |
| 531 * | |
| 532 * If the table does not have any of the requested scripts, then `DFLT`, | |
| 533 * `dflt`, and `latn` tags are tried in that order. If the table still does not | |
| 534 * have any of these scripts, @script_index and @chosen_script are set to | |
| 535 * #HB_OT_LAYOUT_NO_SCRIPT_INDEX. | |
| 536 * | |
| 537 * Return value: | |
| 538 * `true` if one of the requested scripts is selected, `false` if a fallback | |
| 539 * script is selected or if no scripts are selected. | |
| 540 * | |
| 541 * Since: 2.0.0 | |
| 542 **/ | |
| 543 hb_bool_t | |
| 544 hb_ot_layout_table_select_script (hb_face_t *face, | |
| 545 hb_tag_t table_tag, | |
| 546 unsigned int script_count, | |
| 547 const hb_tag_t *script_tags, | |
| 548 unsigned int *script_index /* OUT */, | |
| 549 hb_tag_t *chosen_script /* OUT */) | |
| 550 { | |
| 551 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), ""); | |
| 552 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 553 unsigned int i; | |
| 554 | |
| 555 for (i = 0; i < script_count; i++) | |
| 556 { | |
| 557 if (g.find_script_index (script_tags[i], script_index)) | |
| 558 { | |
| 559 if (chosen_script) | |
| 560 *chosen_script = script_tags[i]; | |
| 561 return true; | |
| 562 } | |
| 563 } | |
| 564 | |
| 565 /* try finding 'DFLT' */ | |
| 566 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) { | |
| 567 if (chosen_script) | |
| 568 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT; | |
| 569 return false; | |
| 570 } | |
| 571 | |
| 572 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */ | |
| 573 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) { | |
| 574 if (chosen_script) | |
| 575 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE; | |
| 576 return false; | |
| 577 } | |
| 578 | |
| 579 /* try with 'latn'; some old fonts put their features there even though | |
| 580 they're really trying to support Thai, for example :( */ | |
| 581 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) { | |
| 582 if (chosen_script) | |
| 583 *chosen_script = HB_OT_TAG_LATIN_SCRIPT; | |
| 584 return false; | |
| 585 } | |
| 586 | |
| 587 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; | |
| 588 if (chosen_script) | |
| 589 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX; | |
| 590 return false; | |
| 591 } | |
| 592 | |
| 593 | |
| 594 /** | |
| 595 * hb_ot_layout_table_get_feature_tags: | |
| 596 * @face: #hb_face_t to work upon | |
| 597 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 598 * @start_offset: offset of the first feature tag to retrieve | |
| 599 * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return; | |
| 600 * Output = the actual number of feature tags returned (may be zero) | |
| 601 * @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table | |
| 602 * | |
| 603 * Fetches a list of all feature tags in the given face's GSUB or GPOS table. | |
| 604 * Note that there might be duplicate feature tags, belonging to different | |
| 605 * script/language-system pairs of the table. | |
| 606 * | |
| 607 * Return value: Total number of feature tags. | |
| 608 * | |
| 609 * Since: 0.6.0 | |
| 610 * | |
| 611 **/ | |
| 612 unsigned int | |
| 613 hb_ot_layout_table_get_feature_tags (hb_face_t *face, | |
| 614 hb_tag_t table_tag, | |
| 615 unsigned int start_offset, | |
| 616 unsigned int *feature_count /* IN/OUT */, | |
| 617 hb_tag_t *feature_tags /* OUT */) | |
| 618 { | |
| 619 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 620 | |
| 621 return g.get_feature_tags (start_offset, feature_count, feature_tags); | |
| 622 } | |
| 623 | |
| 624 | |
| 625 /** | |
| 626 * hb_ot_layout_table_find_feature: | |
| 627 * @face: #hb_face_t to work upon | |
| 628 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 629 * @feature_tag: The #hb_tag_t of the requested feature tag | |
| 630 * @feature_index: (out): The index of the requested feature | |
| 631 * | |
| 632 * Fetches the index for a given feature tag in the specified face's GSUB table | |
| 633 * or GPOS table. | |
| 634 * | |
| 635 * Return value: `true` if the feature is found, `false` otherwise | |
| 636 * | |
| 637 * Since: 0.6.0 | |
| 638 * | |
| 639 **/ | |
| 640 bool | |
| 641 hb_ot_layout_table_find_feature (hb_face_t *face, | |
| 642 hb_tag_t table_tag, | |
| 643 hb_tag_t feature_tag, | |
| 644 unsigned int *feature_index /* OUT */) | |
| 645 { | |
| 646 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), ""); | |
| 647 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 648 | |
| 649 unsigned int num_features = g.get_feature_count (); | |
| 650 for (unsigned int i = 0; i < num_features; i++) | |
| 651 { | |
| 652 if (feature_tag == g.get_feature_tag (i)) { | |
| 653 if (feature_index) *feature_index = i; | |
| 654 return true; | |
| 655 } | |
| 656 } | |
| 657 | |
| 658 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; | |
| 659 return false; | |
| 660 } | |
| 661 | |
| 662 | |
| 663 /** | |
| 664 * hb_ot_layout_script_get_language_tags: | |
| 665 * @face: #hb_face_t to work upon | |
| 666 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 667 * @script_index: The index of the requested script tag | |
| 668 * @start_offset: offset of the first language tag to retrieve | |
| 669 * @language_count: (inout) (optional): Input = the maximum number of language tags to return; | |
| 670 * Output = the actual number of language tags returned (may be zero) | |
| 671 * @language_tags: (out) (array length=language_count): Array of language tags found in the table | |
| 672 * | |
| 673 * Fetches a list of language tags in the given face's GSUB or GPOS table, underneath | |
| 674 * the specified script index. The list returned will begin at the offset provided. | |
| 675 * | |
| 676 * Return value: Total number of language tags. | |
| 677 * | |
| 678 * Since: 0.6.0 | |
| 679 * | |
| 680 **/ | |
| 681 unsigned int | |
| 682 hb_ot_layout_script_get_language_tags (hb_face_t *face, | |
| 683 hb_tag_t table_tag, | |
| 684 unsigned int script_index, | |
| 685 unsigned int start_offset, | |
| 686 unsigned int *language_count /* IN/OUT */, | |
| 687 hb_tag_t *language_tags /* OUT */) | |
| 688 { | |
| 689 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); | |
| 690 | |
| 691 return s.get_lang_sys_tags (start_offset, language_count, language_tags); | |
| 692 } | |
| 693 | |
| 694 | |
| 695 #ifndef HB_DISABLE_DEPRECATED | |
| 696 /** | |
| 697 * hb_ot_layout_script_find_language: | |
| 698 * @face: #hb_face_t to work upon | |
| 699 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 700 * @script_index: The index of the requested script tag | |
| 701 * @language_tag: The #hb_tag_t of the requested language | |
| 702 * @language_index: The index of the requested language | |
| 703 * | |
| 704 * Fetches the index of a given language tag in the specified face's GSUB table | |
| 705 * or GPOS table, underneath the specified script tag. | |
| 706 * | |
| 707 * Return value: `true` if the language tag is found, `false` otherwise | |
| 708 * | |
| 709 * Since: 0.6.0 | |
| 710 * Deprecated: 2.0.0 | |
| 711 **/ | |
| 712 hb_bool_t | |
| 713 hb_ot_layout_script_find_language (hb_face_t *face, | |
| 714 hb_tag_t table_tag, | |
| 715 unsigned int script_index, | |
| 716 hb_tag_t language_tag, | |
| 717 unsigned int *language_index) | |
| 718 { | |
| 719 return hb_ot_layout_script_select_language (face, | |
| 720 table_tag, | |
| 721 script_index, | |
| 722 1, | |
| 723 &language_tag, | |
| 724 language_index); | |
| 725 } | |
| 726 #endif | |
| 727 | |
| 728 | |
| 729 /** | |
| 730 * hb_ot_layout_script_select_language: | |
| 731 * @face: #hb_face_t to work upon | |
| 732 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 733 * @script_index: The index of the requested script tag | |
| 734 * @language_count: The number of languages in the specified script | |
| 735 * @language_tags: The array of language tags | |
| 736 * @language_index: (out): The index of the requested language | |
| 737 * | |
| 738 * Fetches the index of the first language tag fom @language_tags that is present | |
| 739 * in the specified face's GSUB or GPOS table, underneath the specified script | |
| 740 * index. | |
| 741 * | |
| 742 * If none of the given language tags is found, `false` is returned and | |
| 743 * @language_index is set to the default language index. | |
| 744 * | |
| 745 * Return value: `true` if one of the given language tags is found, `false` otherwise | |
| 746 * | |
| 747 * Since: 2.0.0 | |
| 748 **/ | |
| 749 hb_bool_t | |
| 750 hb_ot_layout_script_select_language (hb_face_t *face, | |
| 751 hb_tag_t table_tag, | |
| 752 unsigned int script_index, | |
| 753 unsigned int language_count, | |
| 754 const hb_tag_t *language_tags, | |
| 755 unsigned int *language_index /* OUT */) | |
| 756 { | |
| 757 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX), ""); | |
| 758 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index); | |
| 759 unsigned int i; | |
| 760 | |
| 761 for (i = 0; i < language_count; i++) | |
| 762 { | |
| 763 if (s.find_lang_sys_index (language_tags[i], language_index)) | |
| 764 return true; | |
| 765 } | |
| 766 | |
| 767 /* try finding 'dflt' */ | |
| 768 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index)) | |
| 769 return false; | |
| 770 | |
| 771 if (language_index) | |
| 772 *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX; | |
| 773 return false; | |
| 774 } | |
| 775 | |
| 776 | |
| 777 /** | |
| 778 * hb_ot_layout_language_get_required_feature_index: | |
| 779 * @face: #hb_face_t to work upon | |
| 780 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 781 * @script_index: The index of the requested script tag | |
| 782 * @language_index: The index of the requested language tag | |
| 783 * @feature_index: (out): The index of the requested feature | |
| 784 * | |
| 785 * Fetches the index of a requested feature in the given face's GSUB or GPOS table, | |
| 786 * underneath the specified script and language. | |
| 787 * | |
| 788 * Return value: `true` if the feature is found, `false` otherwise | |
| 789 * | |
| 790 * Since: 0.6.0 | |
| 791 * | |
| 792 **/ | |
| 793 hb_bool_t | |
| 794 hb_ot_layout_language_get_required_feature_index (hb_face_t *face, | |
| 795 hb_tag_t table_tag, | |
| 796 unsigned int script_index, | |
| 797 unsigned int language_index, | |
| 798 unsigned int *feature_index /* OUT */) | |
| 799 { | |
| 800 return hb_ot_layout_language_get_required_feature (face, | |
| 801 table_tag, | |
| 802 script_index, | |
| 803 language_index, | |
| 804 feature_index, | |
| 805 nullptr); | |
| 806 } | |
| 807 | |
| 808 | |
| 809 /** | |
| 810 * hb_ot_layout_language_get_required_feature: | |
| 811 * @face: #hb_face_t to work upon | |
| 812 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 813 * @script_index: The index of the requested script tag | |
| 814 * @language_index: The index of the requested language tag | |
| 815 * @feature_index: (out): The index of the requested feature | |
| 816 * @feature_tag: (out): The #hb_tag_t of the requested feature | |
| 817 * | |
| 818 * Fetches the tag of a requested feature index in the given face's GSUB or GPOS table, | |
| 819 * underneath the specified script and language. | |
| 820 * | |
| 821 * Return value: `true` if the feature is found, `false` otherwise | |
| 822 * | |
| 823 * Since: 0.9.30 | |
| 824 **/ | |
| 825 hb_bool_t | |
| 826 hb_ot_layout_language_get_required_feature (hb_face_t *face, | |
| 827 hb_tag_t table_tag, | |
| 828 unsigned int script_index, | |
| 829 unsigned int language_index, | |
| 830 unsigned int *feature_index /* OUT */, | |
| 831 hb_tag_t *feature_tag /* OUT */) | |
| 832 { | |
| 833 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 834 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); | |
| 835 | |
| 836 unsigned int index = l.get_required_feature_index (); | |
| 837 if (feature_index) *feature_index = index; | |
| 838 if (feature_tag) *feature_tag = g.get_feature_tag (index); | |
| 839 | |
| 840 return l.has_required_feature (); | |
| 841 } | |
| 842 | |
| 843 | |
| 844 /** | |
| 845 * hb_ot_layout_language_get_feature_indexes: | |
| 846 * @face: #hb_face_t to work upon | |
| 847 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 848 * @script_index: The index of the requested script tag | |
| 849 * @language_index: The index of the requested language tag | |
| 850 * @start_offset: offset of the first feature tag to retrieve | |
| 851 * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return; | |
| 852 * Output: the actual number of feature tags returned (may be zero) | |
| 853 * @feature_indexes: (out) (array length=feature_count): The array of feature indexes found for the query | |
| 854 * | |
| 855 * Fetches a list of all features in the specified face's GSUB table | |
| 856 * or GPOS table, underneath the specified script and language. The list | |
| 857 * returned will begin at the offset provided. | |
| 858 * | |
| 859 * Return value: Total number of features. | |
| 860 * | |
| 861 * Since: 0.6.0 | |
| 862 * | |
| 863 **/ | |
| 864 unsigned int | |
| 865 hb_ot_layout_language_get_feature_indexes (hb_face_t *face, | |
| 866 hb_tag_t table_tag, | |
| 867 unsigned int script_index, | |
| 868 unsigned int language_index, | |
| 869 unsigned int start_offset, | |
| 870 unsigned int *feature_count /* IN/OUT */, | |
| 871 unsigned int *feature_indexes /* OUT */) | |
| 872 { | |
| 873 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 874 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); | |
| 875 | |
| 876 return l.get_feature_indexes (start_offset, feature_count, feature_indexes); | |
| 877 } | |
| 878 | |
| 879 | |
| 880 /** | |
| 881 * hb_ot_layout_language_get_feature_tags: | |
| 882 * @face: #hb_face_t to work upon | |
| 883 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 884 * @script_index: The index of the requested script tag | |
| 885 * @language_index: The index of the requested language tag | |
| 886 * @start_offset: offset of the first feature tag to retrieve | |
| 887 * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return; | |
| 888 * Output = the actual number of feature tags returned (may be zero) | |
| 889 * @feature_tags: (out) (array length=feature_count): The array of #hb_tag_t feature tags found for the query | |
| 890 * | |
| 891 * Fetches a list of all features in the specified face's GSUB table | |
| 892 * or GPOS table, underneath the specified script and language. The list | |
| 893 * returned will begin at the offset provided. | |
| 894 * | |
| 895 * Return value: Total number of feature tags. | |
| 896 * | |
| 897 * Since: 0.6.0 | |
| 898 * | |
| 899 **/ | |
| 900 unsigned int | |
| 901 hb_ot_layout_language_get_feature_tags (hb_face_t *face, | |
| 902 hb_tag_t table_tag, | |
| 903 unsigned int script_index, | |
| 904 unsigned int language_index, | |
| 905 unsigned int start_offset, | |
| 906 unsigned int *feature_count /* IN/OUT */, | |
| 907 hb_tag_t *feature_tags /* OUT */) | |
| 908 { | |
| 909 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 910 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); | |
| 911 | |
| 912 static_assert ((sizeof (unsigned int) == sizeof (hb_tag_t)), ""); | |
| 913 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags); | |
| 914 | |
| 915 if (feature_tags) { | |
| 916 unsigned int count = *feature_count; | |
| 917 for (unsigned int i = 0; i < count; i++) | |
| 918 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]); | |
| 919 } | |
| 920 | |
| 921 return ret; | |
| 922 } | |
| 923 | |
| 924 | |
| 925 /** | |
| 926 * hb_ot_layout_language_find_feature: | |
| 927 * @face: #hb_face_t to work upon | |
| 928 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 929 * @script_index: The index of the requested script tag | |
| 930 * @language_index: The index of the requested language tag | |
| 931 * @feature_tag: #hb_tag_t of the feature tag requested | |
| 932 * @feature_index: (out): The index of the requested feature | |
| 933 * | |
| 934 * Fetches the index of a given feature tag in the specified face's GSUB table | |
| 935 * or GPOS table, underneath the specified script and language. | |
| 936 * | |
| 937 * Return value: `true` if the feature is found, `false` otherwise | |
| 938 * | |
| 939 * Since: 0.6.0 | |
| 940 * | |
| 941 **/ | |
| 942 hb_bool_t | |
| 943 hb_ot_layout_language_find_feature (hb_face_t *face, | |
| 944 hb_tag_t table_tag, | |
| 945 unsigned int script_index, | |
| 946 unsigned int language_index, | |
| 947 hb_tag_t feature_tag, | |
| 948 unsigned int *feature_index /* OUT */) | |
| 949 { | |
| 950 static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), ""); | |
| 951 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 952 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); | |
| 953 | |
| 954 unsigned int num_features = l.get_feature_count (); | |
| 955 for (unsigned int i = 0; i < num_features; i++) { | |
| 956 unsigned int f_index = l.get_feature_index (i); | |
| 957 | |
| 958 if (feature_tag == g.get_feature_tag (f_index)) { | |
| 959 if (feature_index) *feature_index = f_index; | |
| 960 return true; | |
| 961 } | |
| 962 } | |
| 963 | |
| 964 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; | |
| 965 return false; | |
| 966 } | |
| 967 | |
| 968 | |
| 969 /** | |
| 970 * hb_ot_layout_feature_get_lookups: | |
| 971 * @face: #hb_face_t to work upon | |
| 972 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 973 * @feature_index: The index of the requested feature | |
| 974 * @start_offset: offset of the first lookup to retrieve | |
| 975 * @lookup_count: (inout) (optional): Input = the maximum number of lookups to return; | |
| 976 * Output = the actual number of lookups returned (may be zero) | |
| 977 * @lookup_indexes: (out) (array length=lookup_count): The array of lookup indexes found for the query | |
| 978 * | |
| 979 * Fetches a list of all lookups enumerated for the specified feature, in | |
| 980 * the specified face's GSUB table or GPOS table. The list returned will | |
| 981 * begin at the offset provided. | |
| 982 * | |
| 983 * Return value: Total number of lookups. | |
| 984 * | |
| 985 * Since: 0.9.7 | |
| 986 **/ | |
| 987 unsigned int | |
| 988 hb_ot_layout_feature_get_lookups (hb_face_t *face, | |
| 989 hb_tag_t table_tag, | |
| 990 unsigned int feature_index, | |
| 991 unsigned int start_offset, | |
| 992 unsigned int *lookup_count /* IN/OUT */, | |
| 993 unsigned int *lookup_indexes /* OUT */) | |
| 994 { | |
| 995 return hb_ot_layout_feature_with_variations_get_lookups (face, | |
| 996 table_tag, | |
| 997 feature_index, | |
| 998 HB_OT_LAYOUT_NO_VARIATIONS_INDEX, | |
| 999 start_offset, | |
| 1000 lookup_count, | |
| 1001 lookup_indexes); | |
| 1002 } | |
| 1003 | |
| 1004 | |
| 1005 /** | |
| 1006 * hb_ot_layout_table_get_lookup_count: | |
| 1007 * @face: #hb_face_t to work upon | |
| 1008 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 1009 * | |
| 1010 * Fetches the total number of lookups enumerated in the specified | |
| 1011 * face's GSUB table or GPOS table. | |
| 1012 * | |
| 1013 * Return value: Total number of lookups. | |
| 1014 * | |
| 1015 * Since: 0.9.22 | |
| 1016 **/ | |
| 1017 unsigned int | |
| 1018 hb_ot_layout_table_get_lookup_count (hb_face_t *face, | |
| 1019 hb_tag_t table_tag) | |
| 1020 { | |
| 1021 return get_gsubgpos_table (face, table_tag).get_lookup_count (); | |
| 1022 } | |
| 1023 | |
| 1024 | |
| 1025 struct hb_collect_features_context_t | |
| 1026 { | |
| 1027 hb_collect_features_context_t (hb_face_t *face, | |
| 1028 hb_tag_t table_tag, | |
| 1029 hb_set_t *feature_indices_, | |
| 1030 const hb_tag_t *features) | |
| 1031 | |
| 1032 : g (get_gsubgpos_table (face, table_tag)), | |
| 1033 feature_indices (feature_indices_), | |
| 1034 has_feature_filter (false), | |
| 1035 script_count (0),langsys_count (0), feature_index_count (0) | |
| 1036 { | |
| 1037 compute_feature_filter (features); | |
| 1038 } | |
| 1039 | |
| 1040 void compute_feature_filter (const hb_tag_t *features) | |
| 1041 { | |
| 1042 if (features == nullptr) | |
| 1043 { | |
| 1044 has_feature_filter = false; | |
| 1045 return; | |
| 1046 } | |
| 1047 | |
| 1048 has_feature_filter = true; | |
| 1049 hb_set_t features_set; | |
| 1050 for (; *features; features++) | |
| 1051 features_set.add (*features); | |
| 1052 | |
| 1053 for (unsigned i = 0; i < g.get_feature_count (); i++) | |
| 1054 { | |
| 1055 hb_tag_t tag = g.get_feature_tag (i); | |
| 1056 if (features_set.has (tag)) | |
| 1057 feature_indices_filter.add(i); | |
| 1058 } | |
| 1059 } | |
| 1060 | |
| 1061 bool visited (const OT::Script &s) | |
| 1062 { | |
| 1063 /* We might have Null() object here. Don't want to involve | |
| 1064 * that in the memoize. So, detect empty objects and return. */ | |
| 1065 if (unlikely (!s.has_default_lang_sys () && | |
| 1066 !s.get_lang_sys_count ())) | |
| 1067 return true; | |
| 1068 | |
| 1069 if (script_count++ > HB_MAX_SCRIPTS) | |
| 1070 return true; | |
| 1071 | |
| 1072 return visited (s, visited_script); | |
| 1073 } | |
| 1074 bool visited (const OT::LangSys &l) | |
| 1075 { | |
| 1076 /* We might have Null() object here. Don't want to involve | |
| 1077 * that in the memoize. So, detect empty objects and return. */ | |
| 1078 if (unlikely (!l.has_required_feature () && | |
| 1079 !l.get_feature_count ())) | |
| 1080 return true; | |
| 1081 | |
| 1082 if (langsys_count++ > HB_MAX_LANGSYS) | |
| 1083 return true; | |
| 1084 | |
| 1085 return visited (l, visited_langsys); | |
| 1086 } | |
| 1087 | |
| 1088 bool visited_feature_indices (unsigned count) | |
| 1089 { | |
| 1090 feature_index_count += count; | |
| 1091 return feature_index_count > HB_MAX_FEATURE_INDICES; | |
| 1092 } | |
| 1093 | |
| 1094 private: | |
| 1095 template <typename T> | |
| 1096 bool visited (const T &p, hb_set_t &visited_set) | |
| 1097 { | |
| 1098 hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) &p - (uintptr_t) &g); | |
| 1099 if (visited_set.has (delta)) | |
| 1100 return true; | |
| 1101 | |
| 1102 visited_set.add (delta); | |
| 1103 return false; | |
| 1104 } | |
| 1105 | |
| 1106 public: | |
| 1107 const OT::GSUBGPOS &g; | |
| 1108 hb_set_t *feature_indices; | |
| 1109 hb_set_t feature_indices_filter; | |
| 1110 bool has_feature_filter; | |
| 1111 | |
| 1112 private: | |
| 1113 hb_set_t visited_script; | |
| 1114 hb_set_t visited_langsys; | |
| 1115 unsigned int script_count; | |
| 1116 unsigned int langsys_count; | |
| 1117 unsigned int feature_index_count; | |
| 1118 }; | |
| 1119 | |
| 1120 static void | |
| 1121 langsys_collect_features (hb_collect_features_context_t *c, | |
| 1122 const OT::LangSys &l) | |
| 1123 { | |
| 1124 if (c->visited (l)) return; | |
| 1125 | |
| 1126 if (!c->has_feature_filter) | |
| 1127 { | |
| 1128 /* All features. */ | |
| 1129 if (l.has_required_feature () && !c->visited_feature_indices (1)) | |
| 1130 c->feature_indices->add (l.get_required_feature_index ()); | |
| 1131 | |
| 1132 // TODO(garretrieger): filter out indices >= feature count? | |
| 1133 if (!c->visited_feature_indices (l.featureIndex.len)) | |
| 1134 l.add_feature_indexes_to (c->feature_indices); | |
| 1135 } | |
| 1136 else | |
| 1137 { | |
| 1138 if (c->feature_indices_filter.is_empty()) return; | |
| 1139 unsigned int num_features = l.get_feature_count (); | |
| 1140 for (unsigned int i = 0; i < num_features; i++) | |
| 1141 { | |
| 1142 unsigned int feature_index = l.get_feature_index (i); | |
| 1143 if (!c->feature_indices_filter.has (feature_index)) continue; | |
| 1144 | |
| 1145 c->feature_indices->add (feature_index); | |
| 1146 c->feature_indices_filter.del (feature_index); | |
| 1147 } | |
| 1148 } | |
| 1149 } | |
| 1150 | |
| 1151 static void | |
| 1152 script_collect_features (hb_collect_features_context_t *c, | |
| 1153 const OT::Script &s, | |
| 1154 const hb_tag_t *languages) | |
| 1155 { | |
| 1156 if (c->visited (s)) return; | |
| 1157 | |
| 1158 if (!languages) | |
| 1159 { | |
| 1160 /* All languages. */ | |
| 1161 if (s.has_default_lang_sys ()) | |
| 1162 langsys_collect_features (c, | |
| 1163 s.get_default_lang_sys ()); | |
| 1164 | |
| 1165 | |
| 1166 unsigned int count = s.get_lang_sys_count (); | |
| 1167 for (unsigned int language_index = 0; language_index < count; language_index++) | |
| 1168 langsys_collect_features (c, | |
| 1169 s.get_lang_sys (language_index)); | |
| 1170 } | |
| 1171 else | |
| 1172 { | |
| 1173 for (; *languages; languages++) | |
| 1174 { | |
| 1175 unsigned int language_index; | |
| 1176 if (s.find_lang_sys_index (*languages, &language_index)) | |
| 1177 langsys_collect_features (c, | |
| 1178 s.get_lang_sys (language_index)); | |
| 1179 | |
| 1180 } | |
| 1181 } | |
| 1182 } | |
| 1183 | |
| 1184 | |
| 1185 /** | |
| 1186 * hb_ot_layout_collect_features: | |
| 1187 * @face: #hb_face_t to work upon | |
| 1188 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 1189 * @scripts: (nullable) (array zero-terminated=1): The array of scripts to collect features for, | |
| 1190 * terminated by %HB_TAG_NONE | |
| 1191 * @languages: (nullable) (array zero-terminated=1): The array of languages to collect features for, | |
| 1192 * terminated by %HB_TAG_NONE | |
| 1193 * @features: (nullable) (array zero-terminated=1): The array of features to collect, | |
| 1194 * terminated by %HB_TAG_NONE | |
| 1195 * @feature_indexes: (out): The array of feature indexes found for the query | |
| 1196 * | |
| 1197 * Fetches a list of all feature indexes in the specified face's GSUB table | |
| 1198 * or GPOS table, underneath the specified scripts, languages, and features. | |
| 1199 * If no list of scripts is provided, all scripts will be queried. If no list | |
| 1200 * of languages is provided, all languages will be queried. If no list of | |
| 1201 * features is provided, all features will be queried. | |
| 1202 * | |
| 1203 * Since: 1.8.5 | |
| 1204 **/ | |
| 1205 void | |
| 1206 hb_ot_layout_collect_features (hb_face_t *face, | |
| 1207 hb_tag_t table_tag, | |
| 1208 const hb_tag_t *scripts, | |
| 1209 const hb_tag_t *languages, | |
| 1210 const hb_tag_t *features, | |
| 1211 hb_set_t *feature_indexes /* OUT */) | |
| 1212 { | |
| 1213 hb_collect_features_context_t c (face, table_tag, feature_indexes, features); | |
| 1214 if (!scripts) | |
| 1215 { | |
| 1216 /* All scripts. */ | |
| 1217 unsigned int count = c.g.get_script_count (); | |
| 1218 for (unsigned int script_index = 0; script_index < count; script_index++) | |
| 1219 script_collect_features (&c, | |
| 1220 c.g.get_script (script_index), | |
| 1221 languages); | |
| 1222 } | |
| 1223 else | |
| 1224 { | |
| 1225 for (; *scripts; scripts++) | |
| 1226 { | |
| 1227 unsigned int script_index; | |
| 1228 if (c.g.find_script_index (*scripts, &script_index)) | |
| 1229 script_collect_features (&c, | |
| 1230 c.g.get_script (script_index), | |
| 1231 languages); | |
| 1232 } | |
| 1233 } | |
| 1234 } | |
| 1235 | |
| 1236 | |
| 1237 /** | |
| 1238 * hb_ot_layout_collect_lookups: | |
| 1239 * @face: #hb_face_t to work upon | |
| 1240 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 1241 * @scripts: (nullable) (array zero-terminated=1): The array of scripts to collect lookups for, | |
| 1242 * terminated by %HB_TAG_NONE | |
| 1243 * @languages: (nullable) (array zero-terminated=1): The array of languages to collect lookups for, | |
| 1244 * terminated by %HB_TAG_NONE | |
| 1245 * @features: (nullable) (array zero-terminated=1): The array of features to collect lookups for, | |
| 1246 * terminated by %HB_TAG_NONE | |
| 1247 * @lookup_indexes: (out): The array of lookup indexes found for the query | |
| 1248 * | |
| 1249 * Fetches a list of all feature-lookup indexes in the specified face's GSUB | |
| 1250 * table or GPOS table, underneath the specified scripts, languages, and | |
| 1251 * features. If no list of scripts is provided, all scripts will be queried. | |
| 1252 * If no list of languages is provided, all languages will be queried. If no | |
| 1253 * list of features is provided, all features will be queried. | |
| 1254 * | |
| 1255 * Since: 0.9.8 | |
| 1256 **/ | |
| 1257 void | |
| 1258 hb_ot_layout_collect_lookups (hb_face_t *face, | |
| 1259 hb_tag_t table_tag, | |
| 1260 const hb_tag_t *scripts, | |
| 1261 const hb_tag_t *languages, | |
| 1262 const hb_tag_t *features, | |
| 1263 hb_set_t *lookup_indexes /* OUT */) | |
| 1264 { | |
| 1265 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 1266 | |
| 1267 hb_set_t feature_indexes; | |
| 1268 hb_ot_layout_collect_features (face, table_tag, scripts, languages, features, &feature_indexes); | |
| 1269 | |
| 1270 for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID; | |
| 1271 hb_set_next (&feature_indexes, &feature_index);) | |
| 1272 g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes); | |
| 1273 | |
| 1274 g.feature_variation_collect_lookups (&feature_indexes, nullptr, lookup_indexes); | |
| 1275 } | |
| 1276 | |
| 1277 | |
| 1278 #ifndef HB_NO_LAYOUT_COLLECT_GLYPHS | |
| 1279 /** | |
| 1280 * hb_ot_layout_lookup_collect_glyphs: | |
| 1281 * @face: #hb_face_t to work upon | |
| 1282 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 1283 * @lookup_index: The index of the feature lookup to query | |
| 1284 * @glyphs_before: (out): Array of glyphs preceding the substitution range | |
| 1285 * @glyphs_input: (out): Array of input glyphs that would be substituted by the lookup | |
| 1286 * @glyphs_after: (out): Array of glyphs following the substitution range | |
| 1287 * @glyphs_output: (out): Array of glyphs that would be the substituted output of the lookup | |
| 1288 * | |
| 1289 * Fetches a list of all glyphs affected by the specified lookup in the | |
| 1290 * specified face's GSUB table or GPOS table. | |
| 1291 * | |
| 1292 * Since: 0.9.7 | |
| 1293 **/ | |
| 1294 void | |
| 1295 hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, | |
| 1296 hb_tag_t table_tag, | |
| 1297 unsigned int lookup_index, | |
| 1298 hb_set_t *glyphs_before, /* OUT. May be NULL */ | |
| 1299 hb_set_t *glyphs_input, /* OUT. May be NULL */ | |
| 1300 hb_set_t *glyphs_after, /* OUT. May be NULL */ | |
| 1301 hb_set_t *glyphs_output /* OUT. May be NULL */) | |
| 1302 { | |
| 1303 OT::hb_collect_glyphs_context_t c (face, | |
| 1304 glyphs_before, | |
| 1305 glyphs_input, | |
| 1306 glyphs_after, | |
| 1307 glyphs_output); | |
| 1308 | |
| 1309 switch (table_tag) | |
| 1310 { | |
| 1311 case HB_OT_TAG_GSUB: | |
| 1312 { | |
| 1313 const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index); | |
| 1314 l.collect_glyphs (&c); | |
| 1315 return; | |
| 1316 } | |
| 1317 case HB_OT_TAG_GPOS: | |
| 1318 { | |
| 1319 const OT::PosLookup& l = face->table.GPOS->table->get_lookup (lookup_index); | |
| 1320 l.collect_glyphs (&c); | |
| 1321 return; | |
| 1322 } | |
| 1323 } | |
| 1324 } | |
| 1325 #endif | |
| 1326 | |
| 1327 | |
| 1328 /* Variations support */ | |
| 1329 | |
| 1330 | |
| 1331 /** | |
| 1332 * hb_ot_layout_table_find_feature_variations: | |
| 1333 * @face: #hb_face_t to work upon | |
| 1334 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 1335 * @coords: The variation coordinates to query | |
| 1336 * @num_coords: The number of variation coordinates | |
| 1337 * @variations_index: (out): The array of feature variations found for the query | |
| 1338 * | |
| 1339 * Fetches a list of feature variations in the specified face's GSUB table | |
| 1340 * or GPOS table, at the specified variation coordinates. | |
| 1341 * | |
| 1342 * Return value: `true` if feature variations were found, `false` otherwise. | |
| 1343 * | |
| 1344 * Since: 1.4.0 | |
| 1345 * | |
| 1346 **/ | |
| 1347 hb_bool_t | |
| 1348 hb_ot_layout_table_find_feature_variations (hb_face_t *face, | |
| 1349 hb_tag_t table_tag, | |
| 1350 const int *coords, | |
| 1351 unsigned int num_coords, | |
| 1352 unsigned int *variations_index /* out */) | |
| 1353 { | |
| 1354 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 1355 | |
| 1356 return g.find_variations_index (coords, num_coords, variations_index); | |
| 1357 } | |
| 1358 | |
| 1359 | |
| 1360 /** | |
| 1361 * hb_ot_layout_feature_with_variations_get_lookups: | |
| 1362 * @face: #hb_face_t to work upon | |
| 1363 * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS | |
| 1364 * @feature_index: The index of the feature to query | |
| 1365 * @variations_index: The index of the feature variation to query | |
| 1366 * @start_offset: offset of the first lookup to retrieve | |
| 1367 * @lookup_count: (inout) (optional): Input = the maximum number of lookups to return; | |
| 1368 * Output = the actual number of lookups returned (may be zero) | |
| 1369 * @lookup_indexes: (out) (array length=lookup_count): The array of lookups found for the query | |
| 1370 * | |
| 1371 * Fetches a list of all lookups enumerated for the specified feature, in | |
| 1372 * the specified face's GSUB table or GPOS table, enabled at the specified | |
| 1373 * variations index. The list returned will begin at the offset provided. | |
| 1374 * | |
| 1375 * Return value: Total number of lookups. | |
| 1376 * | |
| 1377 * Since: 1.4.0 | |
| 1378 * | |
| 1379 **/ | |
| 1380 unsigned int | |
| 1381 hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face, | |
| 1382 hb_tag_t table_tag, | |
| 1383 unsigned int feature_index, | |
| 1384 unsigned int variations_index, | |
| 1385 unsigned int start_offset, | |
| 1386 unsigned int *lookup_count /* IN/OUT */, | |
| 1387 unsigned int *lookup_indexes /* OUT */) | |
| 1388 { | |
| 1389 static_assert ((OT::FeatureVariations::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_VARIATIONS_INDEX), ""); | |
| 1390 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 1391 | |
| 1392 const OT::Feature &f = g.get_feature_variation (feature_index, variations_index); | |
| 1393 | |
| 1394 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes); | |
| 1395 } | |
| 1396 | |
| 1397 | |
| 1398 /* | |
| 1399 * OT::GSUB | |
| 1400 */ | |
| 1401 | |
| 1402 | |
| 1403 /** | |
| 1404 * hb_ot_layout_has_substitution: | |
| 1405 * @face: #hb_face_t to work upon | |
| 1406 * | |
| 1407 * Tests whether the specified face includes any GSUB substitutions. | |
| 1408 * | |
| 1409 * Return value: `true` if data found, `false` otherwise | |
| 1410 * | |
| 1411 * Since: 0.6.0 | |
| 1412 * | |
| 1413 **/ | |
| 1414 hb_bool_t | |
| 1415 hb_ot_layout_has_substitution (hb_face_t *face) | |
| 1416 { | |
| 1417 return face->table.GSUB->table->has_data (); | |
| 1418 } | |
| 1419 | |
| 1420 | |
| 1421 /** | |
| 1422 * hb_ot_layout_lookup_would_substitute: | |
| 1423 * @face: #hb_face_t to work upon | |
| 1424 * @lookup_index: The index of the lookup to query | |
| 1425 * @glyphs: The sequence of glyphs to query for substitution | |
| 1426 * @glyphs_length: The length of the glyph sequence | |
| 1427 * @zero_context: #hb_bool_t indicating whether pre-/post-context are disallowed | |
| 1428 * in substitutions | |
| 1429 * | |
| 1430 * Tests whether a specified lookup in the specified face would | |
| 1431 * trigger a substitution on the given glyph sequence. | |
| 1432 * | |
| 1433 * Return value: `true` if a substitution would be triggered, `false` otherwise | |
| 1434 * | |
| 1435 * Since: 0.9.7 | |
| 1436 **/ | |
| 1437 hb_bool_t | |
| 1438 hb_ot_layout_lookup_would_substitute (hb_face_t *face, | |
| 1439 unsigned int lookup_index, | |
| 1440 const hb_codepoint_t *glyphs, | |
| 1441 unsigned int glyphs_length, | |
| 1442 hb_bool_t zero_context) | |
| 1443 { | |
| 1444 if (unlikely (lookup_index >= face->table.GSUB->lookup_count)) return false; | |
| 1445 OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context); | |
| 1446 | |
| 1447 const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index); | |
| 1448 return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]); | |
| 1449 } | |
| 1450 | |
| 1451 | |
| 1452 /** | |
| 1453 * hb_ot_layout_substitute_start: | |
| 1454 * @font: #hb_font_t to use | |
| 1455 * @buffer: #hb_buffer_t buffer to work upon | |
| 1456 * | |
| 1457 * Called before substitution lookups are performed, to ensure that glyph | |
| 1458 * class and other properties are set on the glyphs in the buffer. | |
| 1459 * | |
| 1460 **/ | |
| 1461 void | |
| 1462 hb_ot_layout_substitute_start (hb_font_t *font, | |
| 1463 hb_buffer_t *buffer) | |
| 1464 { | |
| 1465 _hb_ot_layout_set_glyph_props (font, buffer); | |
| 1466 } | |
| 1467 | |
| 1468 /** | |
| 1469 * hb_ot_layout_lookup_substitute_closure: | |
| 1470 * @face: #hb_face_t to work upon | |
| 1471 * @lookup_index: index of the feature lookup to query | |
| 1472 * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookup | |
| 1473 * | |
| 1474 * Compute the transitive closure of glyphs needed for a | |
| 1475 * specified lookup. | |
| 1476 * | |
| 1477 * Since: 0.9.7 | |
| 1478 **/ | |
| 1479 void | |
| 1480 hb_ot_layout_lookup_substitute_closure (hb_face_t *face, | |
| 1481 unsigned int lookup_index, | |
| 1482 hb_set_t *glyphs /* OUT */) | |
| 1483 { | |
| 1484 hb_map_t done_lookups_glyph_count; | |
| 1485 hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> done_lookups_glyph_set; | |
| 1486 OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); | |
| 1487 | |
| 1488 const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index); | |
| 1489 | |
| 1490 l.closure (&c, lookup_index); | |
| 1491 } | |
| 1492 | |
| 1493 /** | |
| 1494 * hb_ot_layout_lookups_substitute_closure: | |
| 1495 * @face: #hb_face_t to work upon | |
| 1496 * @lookups: The set of lookups to query | |
| 1497 * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookups | |
| 1498 * | |
| 1499 * Compute the transitive closure of glyphs needed for all of the | |
| 1500 * provided lookups. | |
| 1501 * | |
| 1502 * Since: 1.8.1 | |
| 1503 **/ | |
| 1504 void | |
| 1505 hb_ot_layout_lookups_substitute_closure (hb_face_t *face, | |
| 1506 const hb_set_t *lookups, | |
| 1507 hb_set_t *glyphs /* OUT */) | |
| 1508 { | |
| 1509 hb_map_t done_lookups_glyph_count; | |
| 1510 hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> done_lookups_glyph_set; | |
| 1511 OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); | |
| 1512 const GSUB& gsub = *face->table.GSUB->table; | |
| 1513 | |
| 1514 unsigned int iteration_count = 0; | |
| 1515 unsigned int glyphs_length; | |
| 1516 do | |
| 1517 { | |
| 1518 c.reset_lookup_visit_count (); | |
| 1519 glyphs_length = glyphs->get_population (); | |
| 1520 if (lookups) | |
| 1521 { | |
| 1522 for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);) | |
| 1523 gsub.get_lookup (lookup_index).closure (&c, lookup_index); | |
| 1524 } | |
| 1525 else | |
| 1526 { | |
| 1527 for (unsigned int i = 0; i < gsub.get_lookup_count (); i++) | |
| 1528 gsub.get_lookup (i).closure (&c, i); | |
| 1529 } | |
| 1530 } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES && | |
| 1531 glyphs_length != glyphs->get_population ()); | |
| 1532 } | |
| 1533 | |
| 1534 /* | |
| 1535 * GPOS | |
| 1536 */ | |
| 1537 | |
| 1538 | |
| 1539 /** | |
| 1540 * hb_ot_layout_has_positioning: | |
| 1541 * @face: #hb_face_t to work upon | |
| 1542 * | |
| 1543 * Tests whether the specified face includes any GPOS positioning. | |
| 1544 * | |
| 1545 * Return value: `true` if the face has GPOS data, `false` otherwise | |
| 1546 * | |
| 1547 **/ | |
| 1548 hb_bool_t | |
| 1549 hb_ot_layout_has_positioning (hb_face_t *face) | |
| 1550 { | |
| 1551 return face->table.GPOS->table->has_data (); | |
| 1552 } | |
| 1553 | |
| 1554 /** | |
| 1555 * hb_ot_layout_position_start: | |
| 1556 * @font: #hb_font_t to use | |
| 1557 * @buffer: #hb_buffer_t buffer to work upon | |
| 1558 * | |
| 1559 * Called before positioning lookups are performed, to ensure that glyph | |
| 1560 * attachment types and glyph-attachment chains are set for the glyphs in the buffer. | |
| 1561 * | |
| 1562 **/ | |
| 1563 void | |
| 1564 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer) | |
| 1565 { | |
| 1566 GPOS::position_start (font, buffer); | |
| 1567 } | |
| 1568 | |
| 1569 | |
| 1570 /** | |
| 1571 * hb_ot_layout_position_finish_advances: | |
| 1572 * @font: #hb_font_t to use | |
| 1573 * @buffer: #hb_buffer_t buffer to work upon | |
| 1574 * | |
| 1575 * Called after positioning lookups are performed, to finish glyph advances. | |
| 1576 * | |
| 1577 **/ | |
| 1578 void | |
| 1579 hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer) | |
| 1580 { | |
| 1581 GPOS::position_finish_advances (font, buffer); | |
| 1582 } | |
| 1583 | |
| 1584 /** | |
| 1585 * hb_ot_layout_position_finish_offsets: | |
| 1586 * @font: #hb_font_t to use | |
| 1587 * @buffer: #hb_buffer_t buffer to work upon | |
| 1588 * | |
| 1589 * Called after positioning lookups are performed, to finish glyph offsets. | |
| 1590 * | |
| 1591 **/ | |
| 1592 void | |
| 1593 hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) | |
| 1594 { | |
| 1595 GPOS::position_finish_offsets (font, buffer); | |
| 1596 } | |
| 1597 | |
| 1598 | |
| 1599 #ifndef HB_NO_LAYOUT_FEATURE_PARAMS | |
| 1600 /** | |
| 1601 * hb_ot_layout_get_size_params: | |
| 1602 * @face: #hb_face_t to work upon | |
| 1603 * @design_size: (out): The design size of the face | |
| 1604 * @subfamily_id: (out): The identifier of the face within the font subfamily | |
| 1605 * @subfamily_name_id: (out): The ‘name’ table name ID of the face within the font subfamily | |
| 1606 * @range_start: (out): The minimum size of the recommended size range for the face | |
| 1607 * @range_end: (out): The maximum size of the recommended size range for the face | |
| 1608 * | |
| 1609 * Fetches optical-size feature data (i.e., the `size` feature from GPOS). Note that | |
| 1610 * the subfamily_id and the subfamily name string (accessible via the subfamily_name_id) | |
| 1611 * as used here are defined as pertaining only to fonts within a font family that differ | |
| 1612 * specifically in their respective size ranges; other ways to differentiate fonts within | |
| 1613 * a subfamily are not covered by the `size` feature. | |
| 1614 * | |
| 1615 * For more information on this distinction, see the [`size` feature documentation]( | |
| 1616 * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size). | |
| 1617 * | |
| 1618 * Return value: `true` if data found, `false` otherwise | |
| 1619 * | |
| 1620 * Since: 0.9.10 | |
| 1621 **/ | |
| 1622 hb_bool_t | |
| 1623 hb_ot_layout_get_size_params (hb_face_t *face, | |
| 1624 unsigned int *design_size, /* OUT. May be NULL */ | |
| 1625 unsigned int *subfamily_id, /* OUT. May be NULL */ | |
| 1626 hb_ot_name_id_t *subfamily_name_id, /* OUT. May be NULL */ | |
| 1627 unsigned int *range_start, /* OUT. May be NULL */ | |
| 1628 unsigned int *range_end /* OUT. May be NULL */) | |
| 1629 { | |
| 1630 const GPOS &gpos = *face->table.GPOS->table; | |
| 1631 const hb_tag_t tag = HB_TAG ('s','i','z','e'); | |
| 1632 | |
| 1633 unsigned int num_features = gpos.get_feature_count (); | |
| 1634 for (unsigned int i = 0; i < num_features; i++) | |
| 1635 { | |
| 1636 if (tag == gpos.get_feature_tag (i)) | |
| 1637 { | |
| 1638 const OT::Feature &f = gpos.get_feature (i); | |
| 1639 const OT::FeatureParamsSize ¶ms = f.get_feature_params ().get_size_params (tag); | |
| 1640 | |
| 1641 if (params.designSize) | |
| 1642 { | |
| 1643 if (design_size) *design_size = params.designSize; | |
| 1644 if (subfamily_id) *subfamily_id = params.subfamilyID; | |
| 1645 if (subfamily_name_id) *subfamily_name_id = params.subfamilyNameID; | |
| 1646 if (range_start) *range_start = params.rangeStart; | |
| 1647 if (range_end) *range_end = params.rangeEnd; | |
| 1648 | |
| 1649 return true; | |
| 1650 } | |
| 1651 } | |
| 1652 } | |
| 1653 | |
| 1654 if (design_size) *design_size = 0; | |
| 1655 if (subfamily_id) *subfamily_id = 0; | |
| 1656 if (subfamily_name_id) *subfamily_name_id = HB_OT_NAME_ID_INVALID; | |
| 1657 if (range_start) *range_start = 0; | |
| 1658 if (range_end) *range_end = 0; | |
| 1659 | |
| 1660 return false; | |
| 1661 } | |
| 1662 | |
| 1663 | |
| 1664 /** | |
| 1665 * hb_ot_layout_feature_get_name_ids: | |
| 1666 * @face: #hb_face_t to work upon | |
| 1667 * @table_tag: table tag to query, "GSUB" or "GPOS". | |
| 1668 * @feature_index: index of feature to query. | |
| 1669 * @label_id: (out) (optional): The ‘name’ table name ID that specifies a string | |
| 1670 * for a user-interface label for this feature. (May be NULL.) | |
| 1671 * @tooltip_id: (out) (optional): The ‘name’ table name ID that specifies a string | |
| 1672 * that an application can use for tooltip text for this | |
| 1673 * feature. (May be NULL.) | |
| 1674 * @sample_id: (out) (optional): The ‘name’ table name ID that specifies sample text | |
| 1675 * that illustrates the effect of this feature. (May be NULL.) | |
| 1676 * @num_named_parameters: (out) (optional): Number of named parameters. (May be zero.) | |
| 1677 * @first_param_id: (out) (optional): The first ‘name’ table name ID used to specify | |
| 1678 * strings for user-interface labels for the feature | |
| 1679 * parameters. (Must be zero if numParameters is zero.) | |
| 1680 * | |
| 1681 * Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or | |
| 1682 * "Character Variant" ('cvXX') features. | |
| 1683 * | |
| 1684 * Return value: `true` if data found, `false` otherwise | |
| 1685 * | |
| 1686 * Since: 2.0.0 | |
| 1687 **/ | |
| 1688 hb_bool_t | |
| 1689 hb_ot_layout_feature_get_name_ids (hb_face_t *face, | |
| 1690 hb_tag_t table_tag, | |
| 1691 unsigned int feature_index, | |
| 1692 hb_ot_name_id_t *label_id, /* OUT. May be NULL */ | |
| 1693 hb_ot_name_id_t *tooltip_id, /* OUT. May be NULL */ | |
| 1694 hb_ot_name_id_t *sample_id, /* OUT. May be NULL */ | |
| 1695 unsigned int *num_named_parameters, /* OUT. May be NULL */ | |
| 1696 hb_ot_name_id_t *first_param_id /* OUT. May be NULL */) | |
| 1697 { | |
| 1698 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 1699 | |
| 1700 hb_tag_t feature_tag = g.get_feature_tag (feature_index); | |
| 1701 const OT::Feature &f = g.get_feature (feature_index); | |
| 1702 | |
| 1703 const OT::FeatureParams &feature_params = f.get_feature_params (); | |
| 1704 if (&feature_params != &Null (OT::FeatureParams)) | |
| 1705 { | |
| 1706 const OT::FeatureParamsStylisticSet& ss_params = | |
| 1707 feature_params.get_stylistic_set_params (feature_tag); | |
| 1708 if (&ss_params != &Null (OT::FeatureParamsStylisticSet)) /* ssXX */ | |
| 1709 { | |
| 1710 if (label_id) *label_id = ss_params.uiNameID; | |
| 1711 // ssXX features don't have the rest | |
| 1712 if (tooltip_id) *tooltip_id = HB_OT_NAME_ID_INVALID; | |
| 1713 if (sample_id) *sample_id = HB_OT_NAME_ID_INVALID; | |
| 1714 if (num_named_parameters) *num_named_parameters = 0; | |
| 1715 if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID; | |
| 1716 return true; | |
| 1717 } | |
| 1718 const OT::FeatureParamsCharacterVariants& cv_params = | |
| 1719 feature_params.get_character_variants_params (feature_tag); | |
| 1720 if (&cv_params != &Null (OT::FeatureParamsCharacterVariants)) /* cvXX */ | |
| 1721 { | |
| 1722 if (label_id) *label_id = cv_params.featUILableNameID; | |
| 1723 if (tooltip_id) *tooltip_id = cv_params.featUITooltipTextNameID; | |
| 1724 if (sample_id) *sample_id = cv_params.sampleTextNameID; | |
| 1725 if (num_named_parameters) *num_named_parameters = cv_params.numNamedParameters; | |
| 1726 if (first_param_id) *first_param_id = cv_params.firstParamUILabelNameID; | |
| 1727 return true; | |
| 1728 } | |
| 1729 } | |
| 1730 | |
| 1731 if (label_id) *label_id = HB_OT_NAME_ID_INVALID; | |
| 1732 if (tooltip_id) *tooltip_id = HB_OT_NAME_ID_INVALID; | |
| 1733 if (sample_id) *sample_id = HB_OT_NAME_ID_INVALID; | |
| 1734 if (num_named_parameters) *num_named_parameters = 0; | |
| 1735 if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID; | |
| 1736 return false; | |
| 1737 } | |
| 1738 /** | |
| 1739 * hb_ot_layout_feature_get_characters: | |
| 1740 * @face: #hb_face_t to work upon | |
| 1741 * @table_tag: table tag to query, "GSUB" or "GPOS". | |
| 1742 * @feature_index: index of feature to query. | |
| 1743 * @start_offset: offset of the first character to retrieve | |
| 1744 * @char_count: (inout) (optional): Input = the maximum number of characters to return; | |
| 1745 * Output = the actual number of characters returned (may be zero) | |
| 1746 * @characters: (out caller-allocates) (array length=char_count): A buffer pointer. | |
| 1747 * The Unicode codepoints of the characters for which this feature provides | |
| 1748 * glyph variants. | |
| 1749 * | |
| 1750 * Fetches a list of the characters defined as having a variant under the specified | |
| 1751 * "Character Variant" ("cvXX") feature tag. | |
| 1752 * | |
| 1753 * Return value: Number of total sample characters in the cvXX feature. | |
| 1754 * | |
| 1755 * Since: 2.0.0 | |
| 1756 **/ | |
| 1757 unsigned int | |
| 1758 hb_ot_layout_feature_get_characters (hb_face_t *face, | |
| 1759 hb_tag_t table_tag, | |
| 1760 unsigned int feature_index, | |
| 1761 unsigned int start_offset, | |
| 1762 unsigned int *char_count, /* IN/OUT. May be NULL */ | |
| 1763 hb_codepoint_t *characters /* OUT. May be NULL */) | |
| 1764 { | |
| 1765 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); | |
| 1766 return g.get_feature (feature_index) | |
| 1767 .get_feature_params () | |
| 1768 .get_character_variants_params(g.get_feature_tag (feature_index)) | |
| 1769 .get_characters (start_offset, char_count, characters); | |
| 1770 } | |
| 1771 #endif | |
| 1772 | |
| 1773 | |
| 1774 /* | |
| 1775 * Parts of different types are implemented here such that they have direct | |
| 1776 * access to GSUB/GPOS lookups. | |
| 1777 */ | |
| 1778 | |
| 1779 | |
| 1780 struct GSUBProxy | |
| 1781 { | |
| 1782 static constexpr unsigned table_index = 0u; | |
| 1783 static constexpr bool always_inplace = false; | |
| 1784 typedef OT::SubstLookup Lookup; | |
| 1785 | |
| 1786 GSUBProxy (hb_face_t *face) : | |
| 1787 table (*face->table.GSUB->table), | |
| 1788 accels (face->table.GSUB->accels) {} | |
| 1789 | |
| 1790 const GSUB &table; | |
| 1791 const OT::hb_ot_layout_lookup_accelerator_t *accels; | |
| 1792 }; | |
| 1793 | |
| 1794 struct GPOSProxy | |
| 1795 { | |
| 1796 static constexpr unsigned table_index = 1u; | |
| 1797 static constexpr bool always_inplace = true; | |
| 1798 typedef OT::PosLookup Lookup; | |
| 1799 | |
| 1800 GPOSProxy (hb_face_t *face) : | |
| 1801 table (*face->table.GPOS->table), | |
| 1802 accels (face->table.GPOS->accels) {} | |
| 1803 | |
| 1804 const GPOS &table; | |
| 1805 const OT::hb_ot_layout_lookup_accelerator_t *accels; | |
| 1806 }; | |
| 1807 | |
| 1808 | |
| 1809 static inline bool | |
| 1810 apply_forward (OT::hb_ot_apply_context_t *c, | |
| 1811 const OT::hb_ot_layout_lookup_accelerator_t &accel) | |
| 1812 { | |
| 1813 bool use_cache = accel.cache_enter (c); | |
| 1814 | |
| 1815 bool ret = false; | |
| 1816 hb_buffer_t *buffer = c->buffer; | |
| 1817 while (buffer->idx < buffer->len && buffer->successful) | |
| 1818 { | |
| 1819 bool applied = false; | |
| 1820 if (accel.digest.may_have (buffer->cur().codepoint) && | |
| 1821 (buffer->cur().mask & c->lookup_mask) && | |
| 1822 c->check_glyph_property (&buffer->cur(), c->lookup_props)) | |
| 1823 { | |
| 1824 applied = accel.apply (c, use_cache); | |
| 1825 } | |
| 1826 | |
| 1827 if (applied) | |
| 1828 ret = true; | |
| 1829 else | |
| 1830 (void) buffer->next_glyph (); | |
| 1831 } | |
| 1832 | |
| 1833 if (use_cache) | |
| 1834 accel.cache_leave (c); | |
| 1835 | |
| 1836 return ret; | |
| 1837 } | |
| 1838 | |
| 1839 static inline bool | |
| 1840 apply_backward (OT::hb_ot_apply_context_t *c, | |
| 1841 const OT::hb_ot_layout_lookup_accelerator_t &accel) | |
| 1842 { | |
| 1843 bool ret = false; | |
| 1844 hb_buffer_t *buffer = c->buffer; | |
| 1845 do | |
| 1846 { | |
| 1847 if (accel.digest.may_have (buffer->cur().codepoint) && | |
| 1848 (buffer->cur().mask & c->lookup_mask) && | |
| 1849 c->check_glyph_property (&buffer->cur(), c->lookup_props)) | |
| 1850 ret |= accel.apply (c, false); | |
| 1851 | |
| 1852 /* The reverse lookup doesn't "advance" cursor (for good reason). */ | |
| 1853 buffer->idx--; | |
| 1854 | |
| 1855 } | |
| 1856 while ((int) buffer->idx >= 0); | |
| 1857 return ret; | |
| 1858 } | |
| 1859 | |
| 1860 template <typename Proxy> | |
| 1861 static inline bool | |
| 1862 apply_string (OT::hb_ot_apply_context_t *c, | |
| 1863 const typename Proxy::Lookup &lookup, | |
| 1864 const OT::hb_ot_layout_lookup_accelerator_t &accel) | |
| 1865 { | |
| 1866 bool ret = false; | |
| 1867 hb_buffer_t *buffer = c->buffer; | |
| 1868 | |
| 1869 if (unlikely (!buffer->len || !c->lookup_mask)) | |
| 1870 return ret; | |
| 1871 | |
| 1872 c->set_lookup_props (lookup.get_props ()); | |
| 1873 | |
| 1874 if (likely (!lookup.is_reverse ())) | |
| 1875 { | |
| 1876 /* in/out forward substitution/positioning */ | |
| 1877 if (!Proxy::always_inplace) | |
| 1878 buffer->clear_output (); | |
| 1879 | |
| 1880 buffer->idx = 0; | |
| 1881 ret = apply_forward (c, accel); | |
| 1882 | |
| 1883 if (!Proxy::always_inplace) | |
| 1884 buffer->sync (); | |
| 1885 } | |
| 1886 else | |
| 1887 { | |
| 1888 /* in-place backward substitution/positioning */ | |
| 1889 assert (!buffer->have_output); | |
| 1890 buffer->idx = buffer->len - 1; | |
| 1891 ret = apply_backward (c, accel); | |
| 1892 } | |
| 1893 | |
| 1894 return ret; | |
| 1895 } | |
| 1896 | |
| 1897 template <typename Proxy> | |
| 1898 inline void hb_ot_map_t::apply (const Proxy &proxy, | |
| 1899 const hb_ot_shape_plan_t *plan, | |
| 1900 hb_font_t *font, | |
| 1901 hb_buffer_t *buffer) const | |
| 1902 { | |
| 1903 const unsigned int table_index = proxy.table_index; | |
| 1904 unsigned int i = 0; | |
| 1905 OT::hb_ot_apply_context_t c (table_index, font, buffer); | |
| 1906 c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func<OT::hb_ot_apply_context_t>); | |
| 1907 | |
| 1908 for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++) | |
| 1909 { | |
| 1910 const stage_map_t *stage = &stages[table_index][stage_index]; | |
| 1911 for (; i < stage->last_lookup; i++) | |
| 1912 { | |
| 1913 auto &lookup = lookups[table_index][i]; | |
| 1914 | |
| 1915 unsigned int lookup_index = lookup.index; | |
| 1916 if (!buffer->message (font, "start lookup %d feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag))) continue; | |
| 1917 | |
| 1918 /* c.digest is a digest of all the current glyphs in the buffer | |
| 1919 * (plus some past glyphs). | |
| 1920 * | |
| 1921 * Only try applying the lookup if there is any overlap. */ | |
| 1922 if (proxy.accels[lookup_index].digest.may_have (c.digest)) | |
| 1923 { | |
| 1924 c.set_lookup_index (lookup_index); | |
| 1925 c.set_lookup_mask (lookup.mask); | |
| 1926 c.set_auto_zwj (lookup.auto_zwj); | |
| 1927 c.set_auto_zwnj (lookup.auto_zwnj); | |
| 1928 c.set_random (lookup.random); | |
| 1929 c.set_per_syllable (lookup.per_syllable); | |
| 1930 | |
| 1931 apply_string<Proxy> (&c, | |
| 1932 proxy.table.get_lookup (lookup_index), | |
| 1933 proxy.accels[lookup_index]); | |
| 1934 } | |
| 1935 else | |
| 1936 (void) buffer->message (font, "skipped lookup %d feature '%c%c%c%c' because no glyph matches", lookup_index, HB_UNTAG (lookup.feature_tag)); | |
| 1937 | |
| 1938 (void) buffer->message (font, "end lookup %d feature '%c%c%c%c'", lookup_index, HB_UNTAG (lookup.feature_tag)); | |
| 1939 } | |
| 1940 | |
| 1941 if (stage->pause_func) | |
| 1942 { | |
| 1943 if (stage->pause_func (plan, font, buffer)) | |
| 1944 { | |
| 1945 /* Refresh working buffer digest since buffer changed. */ | |
| 1946 c.digest = buffer->digest (); | |
| 1947 } | |
| 1948 } | |
| 1949 } | |
| 1950 } | |
| 1951 | |
| 1952 void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const | |
| 1953 { | |
| 1954 GSUBProxy proxy (font->face); | |
| 1955 if (!buffer->message (font, "start table GSUB")) return; | |
| 1956 apply (proxy, plan, font, buffer); | |
| 1957 (void) buffer->message (font, "end table GSUB"); | |
| 1958 } | |
| 1959 | |
| 1960 void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const | |
| 1961 { | |
| 1962 GPOSProxy proxy (font->face); | |
| 1963 if (!buffer->message (font, "start table GPOS")) return; | |
| 1964 apply (proxy, plan, font, buffer); | |
| 1965 (void) buffer->message (font, "end table GPOS"); | |
| 1966 } | |
| 1967 | |
| 1968 void | |
| 1969 hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c, | |
| 1970 const OT::SubstLookup &lookup, | |
| 1971 const OT::hb_ot_layout_lookup_accelerator_t &accel) | |
| 1972 { | |
| 1973 apply_string<GSUBProxy> (c, lookup, accel); | |
| 1974 } | |
| 1975 | |
| 1976 #ifndef HB_NO_BASE | |
| 1977 /** | |
| 1978 * hb_ot_layout_get_horizontal_baseline_tag_for_script: | |
| 1979 * @script: a script tag. | |
| 1980 * | |
| 1981 * Fetches the dominant horizontal baseline tag used by @script. | |
| 1982 * | |
| 1983 * Return value: dominant baseline tag for the @script. | |
| 1984 * | |
| 1985 * Since: 4.0.0 | |
| 1986 **/ | |
| 1987 hb_ot_layout_baseline_tag_t | |
| 1988 hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script) | |
| 1989 { | |
| 1990 /* Keep in sync with hb_ot_layout_get_baseline_with_fallback */ | |
| 1991 switch ((int) script) | |
| 1992 { | |
| 1993 /* Unicode-1.1 additions */ | |
| 1994 case HB_SCRIPT_BENGALI: | |
| 1995 case HB_SCRIPT_DEVANAGARI: | |
| 1996 case HB_SCRIPT_GUJARATI: | |
| 1997 case HB_SCRIPT_GURMUKHI: | |
| 1998 /* Unicode-2.0 additions */ | |
| 1999 case HB_SCRIPT_TIBETAN: | |
| 2000 /* Unicode-4.0 additions */ | |
| 2001 case HB_SCRIPT_LIMBU: | |
| 2002 /* Unicode-4.1 additions */ | |
| 2003 case HB_SCRIPT_SYLOTI_NAGRI: | |
| 2004 /* Unicode-5.0 additions */ | |
| 2005 case HB_SCRIPT_PHAGS_PA: | |
| 2006 /* Unicode-5.2 additions */ | |
| 2007 case HB_SCRIPT_MEETEI_MAYEK: | |
| 2008 /* Unicode-6.1 additions */ | |
| 2009 case HB_SCRIPT_SHARADA: | |
| 2010 case HB_SCRIPT_TAKRI: | |
| 2011 /* Unicode-7.0 additions */ | |
| 2012 case HB_SCRIPT_MODI: | |
| 2013 case HB_SCRIPT_SIDDHAM: | |
| 2014 case HB_SCRIPT_TIRHUTA: | |
| 2015 /* Unicode-9.0 additions */ | |
| 2016 case HB_SCRIPT_MARCHEN: | |
| 2017 case HB_SCRIPT_NEWA: | |
| 2018 /* Unicode-10.0 additions */ | |
| 2019 case HB_SCRIPT_SOYOMBO: | |
| 2020 case HB_SCRIPT_ZANABAZAR_SQUARE: | |
| 2021 /* Unicode-11.0 additions */ | |
| 2022 case HB_SCRIPT_DOGRA: | |
| 2023 case HB_SCRIPT_GUNJALA_GONDI: | |
| 2024 /* Unicode-12.0 additions */ | |
| 2025 case HB_SCRIPT_NANDINAGARI: | |
| 2026 return HB_OT_LAYOUT_BASELINE_TAG_HANGING; | |
| 2027 | |
| 2028 /* Unicode-1.1 additions */ | |
| 2029 case HB_SCRIPT_HANGUL: | |
| 2030 case HB_SCRIPT_HAN: | |
| 2031 case HB_SCRIPT_HIRAGANA: | |
| 2032 case HB_SCRIPT_KATAKANA: | |
| 2033 /* Unicode-3.0 additions */ | |
| 2034 case HB_SCRIPT_BOPOMOFO: | |
| 2035 /* Unicode-9.0 additions */ | |
| 2036 case HB_SCRIPT_TANGUT: | |
| 2037 /* Unicode-10.0 additions */ | |
| 2038 case HB_SCRIPT_NUSHU: | |
| 2039 /* Unicode-13.0 additions */ | |
| 2040 case HB_SCRIPT_KHITAN_SMALL_SCRIPT: | |
| 2041 return HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT; | |
| 2042 | |
| 2043 default: | |
| 2044 return HB_OT_LAYOUT_BASELINE_TAG_ROMAN; | |
| 2045 } | |
| 2046 } | |
| 2047 | |
| 2048 /** | |
| 2049 * hb_ot_layout_get_baseline: | |
| 2050 * @font: a font | |
| 2051 * @baseline_tag: a baseline tag | |
| 2052 * @direction: text direction. | |
| 2053 * @script_tag: script tag. | |
| 2054 * @language_tag: language tag, currently unused. | |
| 2055 * @coord: (out) (nullable): baseline value if found. | |
| 2056 * | |
| 2057 * Fetches a baseline value from the face. | |
| 2058 * | |
| 2059 * Return value: `true` if found baseline value in the font. | |
| 2060 * | |
| 2061 * Since: 2.6.0 | |
| 2062 **/ | |
| 2063 hb_bool_t | |
| 2064 hb_ot_layout_get_baseline (hb_font_t *font, | |
| 2065 hb_ot_layout_baseline_tag_t baseline_tag, | |
| 2066 hb_direction_t direction, | |
| 2067 hb_tag_t script_tag, | |
| 2068 hb_tag_t language_tag, | |
| 2069 hb_position_t *coord /* OUT. May be NULL. */) | |
| 2070 { | |
| 2071 return font->face->table.BASE->get_baseline (font, baseline_tag, direction, script_tag, language_tag, coord); | |
| 2072 } | |
| 2073 | |
| 2074 /** | |
| 2075 * hb_ot_layout_get_baseline_with_fallback: | |
| 2076 * @font: a font | |
| 2077 * @baseline_tag: a baseline tag | |
| 2078 * @direction: text direction. | |
| 2079 * @script_tag: script tag. | |
| 2080 * @language_tag: language tag, currently unused. | |
| 2081 * @coord: (out): baseline value if found. | |
| 2082 * | |
| 2083 * Fetches a baseline value from the face, and synthesizes | |
| 2084 * it if the font does not have it. | |
| 2085 * | |
| 2086 * Since: 4.0.0 | |
| 2087 **/ | |
| 2088 void | |
| 2089 hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, | |
| 2090 hb_ot_layout_baseline_tag_t baseline_tag, | |
| 2091 hb_direction_t direction, | |
| 2092 hb_tag_t script_tag, | |
| 2093 hb_tag_t language_tag, | |
| 2094 hb_position_t *coord /* OUT */) | |
| 2095 { | |
| 2096 if (hb_ot_layout_get_baseline (font, | |
| 2097 baseline_tag, | |
| 2098 direction, | |
| 2099 script_tag, | |
| 2100 language_tag, | |
| 2101 coord)) | |
| 2102 return; | |
| 2103 | |
| 2104 /* Synthesize missing baselines. | |
| 2105 * See https://www.w3.org/TR/css-inline-3/#baseline-synthesis-fonts | |
| 2106 */ | |
| 2107 switch (baseline_tag) | |
| 2108 { | |
| 2109 case HB_OT_LAYOUT_BASELINE_TAG_ROMAN: | |
| 2110 *coord = 0; // FIXME origin ? | |
| 2111 break; | |
| 2112 | |
| 2113 case HB_OT_LAYOUT_BASELINE_TAG_MATH: | |
| 2114 { | |
| 2115 hb_codepoint_t glyph; | |
| 2116 hb_glyph_extents_t extents; | |
| 2117 if (HB_DIRECTION_IS_HORIZONTAL (direction) && | |
| 2118 (hb_font_get_nominal_glyph (font, 0x2212u, &glyph) || | |
| 2119 hb_font_get_nominal_glyph (font, '-', &glyph)) && | |
| 2120 hb_font_get_glyph_extents (font, glyph, &extents)) | |
| 2121 { | |
| 2122 *coord = extents.y_bearing + extents.height / 2; | |
| 2123 } | |
| 2124 else | |
| 2125 { | |
| 2126 hb_position_t x_height = font->y_scale / 2; | |
| 2127 #ifndef HB_NO_METRICS | |
| 2128 hb_ot_metrics_get_position_with_fallback (font, HB_OT_METRICS_TAG_X_HEIGHT, &x_height); | |
| 2129 #endif | |
| 2130 *coord = x_height / 2; | |
| 2131 } | |
| 2132 } | |
| 2133 break; | |
| 2134 | |
| 2135 case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT: | |
| 2136 case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT: | |
| 2137 { | |
| 2138 hb_position_t embox_top, embox_bottom; | |
| 2139 | |
| 2140 hb_ot_layout_get_baseline_with_fallback (font, | |
| 2141 HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, | |
| 2142 direction, | |
| 2143 script_tag, | |
| 2144 language_tag, | |
| 2145 &embox_top); | |
| 2146 hb_ot_layout_get_baseline_with_fallback (font, | |
| 2147 HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT, | |
| 2148 direction, | |
| 2149 script_tag, | |
| 2150 language_tag, | |
| 2151 &embox_bottom); | |
| 2152 | |
| 2153 if (baseline_tag == HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT) | |
| 2154 *coord = embox_top + (embox_bottom - embox_top) / 10; | |
| 2155 else | |
| 2156 *coord = embox_bottom + (embox_top - embox_bottom) / 10; | |
| 2157 } | |
| 2158 break; | |
| 2159 | |
| 2160 case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT: | |
| 2161 if (hb_ot_layout_get_baseline (font, | |
| 2162 HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT, | |
| 2163 direction, | |
| 2164 script_tag, | |
| 2165 language_tag, | |
| 2166 coord)) | |
| 2167 *coord += HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale; | |
| 2168 else | |
| 2169 { | |
| 2170 hb_font_extents_t font_extents; | |
| 2171 hb_font_get_extents_for_direction (font, direction, &font_extents); | |
| 2172 *coord = font_extents.ascender; | |
| 2173 } | |
| 2174 break; | |
| 2175 | |
| 2176 case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT: | |
| 2177 if (hb_ot_layout_get_baseline (font, | |
| 2178 HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, | |
| 2179 direction, | |
| 2180 script_tag, | |
| 2181 language_tag, | |
| 2182 coord)) | |
| 2183 *coord -= HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale; | |
| 2184 else | |
| 2185 { | |
| 2186 hb_font_extents_t font_extents; | |
| 2187 hb_font_get_extents_for_direction (font, direction, &font_extents); | |
| 2188 *coord = font_extents.descender; | |
| 2189 } | |
| 2190 break; | |
| 2191 | |
| 2192 case HB_OT_LAYOUT_BASELINE_TAG_HANGING: | |
| 2193 if (HB_DIRECTION_IS_HORIZONTAL (direction)) | |
| 2194 { | |
| 2195 hb_codepoint_t ch; | |
| 2196 hb_codepoint_t glyph; | |
| 2197 hb_glyph_extents_t extents; | |
| 2198 | |
| 2199 /* Keep in sync with hb_ot_layout_get_horizontal_baseline_for_script */ | |
| 2200 switch ((int) script_tag) | |
| 2201 { | |
| 2202 /* Unicode-1.1 additions */ | |
| 2203 case HB_SCRIPT_BENGALI: ch = 0x0995u; break; | |
| 2204 case HB_SCRIPT_DEVANAGARI: ch = 0x0915u; break; | |
| 2205 case HB_SCRIPT_GUJARATI: ch = 0x0a95u; break; | |
| 2206 case HB_SCRIPT_GURMUKHI: ch = 0x0a15u; break; | |
| 2207 /* Unicode-2.0 additions */ | |
| 2208 case HB_SCRIPT_TIBETAN: ch = 0x0f40u; break; | |
| 2209 /* Unicode-4.0 additions */ | |
| 2210 case HB_SCRIPT_LIMBU: ch = 0x1901u; break; | |
| 2211 /* Unicode-4.1 additions */ | |
| 2212 case HB_SCRIPT_SYLOTI_NAGRI: ch = 0xa807u; break; | |
| 2213 /* Unicode-5.0 additions */ | |
| 2214 case HB_SCRIPT_PHAGS_PA: ch = 0xa840u; break; | |
| 2215 /* Unicode-5.2 additions */ | |
| 2216 case HB_SCRIPT_MEETEI_MAYEK: ch = 0xabc0u; break; | |
| 2217 /* Unicode-6.1 additions */ | |
| 2218 case HB_SCRIPT_SHARADA: ch = 0x11191u; break; | |
| 2219 case HB_SCRIPT_TAKRI: ch = 0x1168cu; break; | |
| 2220 /* Unicode-7.0 additions */ | |
| 2221 case HB_SCRIPT_MODI: ch = 0x1160eu;break; | |
| 2222 case HB_SCRIPT_SIDDHAM: ch = 0x11590u; break; | |
| 2223 case HB_SCRIPT_TIRHUTA: ch = 0x1148fu; break; | |
| 2224 /* Unicode-9.0 additions */ | |
| 2225 case HB_SCRIPT_MARCHEN: ch = 0x11c72u; break; | |
| 2226 case HB_SCRIPT_NEWA: ch = 0x1140eu; break; | |
| 2227 /* Unicode-10.0 additions */ | |
| 2228 case HB_SCRIPT_SOYOMBO: ch = 0x11a5cu; break; | |
| 2229 case HB_SCRIPT_ZANABAZAR_SQUARE: ch = 0x11a0bu; break; | |
| 2230 /* Unicode-11.0 additions */ | |
| 2231 case HB_SCRIPT_DOGRA: ch = 0x1180au; break; | |
| 2232 case HB_SCRIPT_GUNJALA_GONDI: ch = 0x11d6cu; break; | |
| 2233 /* Unicode-12.0 additions */ | |
| 2234 case HB_SCRIPT_NANDINAGARI: ch = 0x119b0u; break; | |
| 2235 default: ch = 0; break; | |
| 2236 } | |
| 2237 | |
| 2238 if (ch && | |
| 2239 hb_font_get_nominal_glyph (font, ch, &glyph) && | |
| 2240 hb_font_get_glyph_extents (font, glyph, &extents)) | |
| 2241 *coord = extents.y_bearing; | |
| 2242 else | |
| 2243 *coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin | |
| 2244 } | |
| 2245 else | |
| 2246 *coord = font->x_scale * 6 / 10; // FIXME makes assumptions about origin | |
| 2247 break; | |
| 2248 | |
| 2249 case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL: | |
| 2250 { | |
| 2251 hb_position_t top, bottom; | |
| 2252 hb_ot_layout_get_baseline_with_fallback (font, | |
| 2253 HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, | |
| 2254 direction, | |
| 2255 script_tag, | |
| 2256 language_tag, | |
| 2257 &top); | |
| 2258 hb_ot_layout_get_baseline_with_fallback (font, | |
| 2259 HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT, | |
| 2260 direction, | |
| 2261 script_tag, | |
| 2262 language_tag, | |
| 2263 &bottom); | |
| 2264 *coord = (top + bottom) / 2; | |
| 2265 | |
| 2266 } | |
| 2267 break; | |
| 2268 | |
| 2269 case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL: | |
| 2270 { | |
| 2271 hb_position_t top, bottom; | |
| 2272 hb_ot_layout_get_baseline_with_fallback (font, | |
| 2273 HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT, | |
| 2274 direction, | |
| 2275 script_tag, | |
| 2276 language_tag, | |
| 2277 &top); | |
| 2278 hb_ot_layout_get_baseline_with_fallback (font, | |
| 2279 HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT, | |
| 2280 direction, | |
| 2281 script_tag, | |
| 2282 language_tag, | |
| 2283 &bottom); | |
| 2284 *coord = (top + bottom) / 2; | |
| 2285 | |
| 2286 } | |
| 2287 break; | |
| 2288 | |
| 2289 case _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE: | |
| 2290 default: | |
| 2291 *coord = 0; | |
| 2292 break; | |
| 2293 } | |
| 2294 } | |
| 2295 | |
| 2296 #endif | |
| 2297 | |
| 2298 | |
| 2299 struct hb_get_glyph_alternates_dispatch_t : | |
| 2300 hb_dispatch_context_t<hb_get_glyph_alternates_dispatch_t, unsigned> | |
| 2301 { | |
| 2302 static return_t default_return_value () { return 0; } | |
| 2303 bool stop_sublookup_iteration (return_t r) const { return r; } | |
| 2304 | |
| 2305 private: | |
| 2306 template <typename T, typename ...Ts> auto | |
| 2307 _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN | |
| 2308 ( obj.get_glyph_alternates (std::forward<Ts> (ds)...) ) | |
| 2309 template <typename T, typename ...Ts> auto | |
| 2310 _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN | |
| 2311 ( default_return_value () ) | |
| 2312 public: | |
| 2313 template <typename T, typename ...Ts> auto | |
| 2314 dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN | |
| 2315 ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) ) | |
| 2316 }; | |
| 2317 | |
| 2318 #ifndef HB_NO_LAYOUT_RARELY_USED | |
| 2319 /** | |
| 2320 * hb_ot_layout_lookup_get_glyph_alternates: | |
| 2321 * @face: a face. | |
| 2322 * @lookup_index: index of the feature lookup to query. | |
| 2323 * @glyph: a glyph id. | |
| 2324 * @start_offset: starting offset. | |
| 2325 * @alternate_count: (inout) (optional): Input = the maximum number of alternate glyphs to return; | |
| 2326 * Output = the actual number of alternate glyphs returned (may be zero). | |
| 2327 * @alternate_glyphs: (out caller-allocates) (array length=alternate_count): A glyphs buffer. | |
| 2328 * Alternate glyphs associated with the glyph id. | |
| 2329 * | |
| 2330 * Fetches alternates of a glyph from a given GSUB lookup index. | |
| 2331 * | |
| 2332 * Return value: Total number of alternates found in the specific lookup index for the given glyph id. | |
| 2333 * | |
| 2334 * Since: 2.6.8 | |
| 2335 **/ | |
| 2336 HB_EXTERN unsigned | |
| 2337 hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face, | |
| 2338 unsigned lookup_index, | |
| 2339 hb_codepoint_t glyph, | |
| 2340 unsigned start_offset, | |
| 2341 unsigned *alternate_count /* IN/OUT. May be NULL. */, | |
| 2342 hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) | |
| 2343 { | |
| 2344 hb_get_glyph_alternates_dispatch_t c; | |
| 2345 const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index); | |
| 2346 auto ret = lookup.dispatch (&c, glyph, start_offset, alternate_count, alternate_glyphs); | |
| 2347 if (!ret && alternate_count) *alternate_count = 0; | |
| 2348 return ret; | |
| 2349 } | |
| 2350 | |
| 2351 | |
| 2352 struct hb_position_single_dispatch_t : | |
| 2353 hb_dispatch_context_t<hb_position_single_dispatch_t, bool> | |
| 2354 { | |
| 2355 static return_t default_return_value () { return false; } | |
| 2356 bool stop_sublookup_iteration (return_t r) const { return r; } | |
| 2357 | |
| 2358 private: | |
| 2359 template <typename T, typename ...Ts> auto | |
| 2360 _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN | |
| 2361 ( obj.position_single (std::forward<Ts> (ds)...) ) | |
| 2362 template <typename T, typename ...Ts> auto | |
| 2363 _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN | |
| 2364 ( default_return_value () ) | |
| 2365 public: | |
| 2366 template <typename T, typename ...Ts> auto | |
| 2367 dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN | |
| 2368 ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) ) | |
| 2369 }; | |
| 2370 | |
| 2371 /** | |
| 2372 * hb_ot_layout_lookup_get_optical_bound: | |
| 2373 * @font: a font. | |
| 2374 * @lookup_index: index of the feature lookup to query. | |
| 2375 * @direction: edge of the glyph to query. | |
| 2376 * @glyph: a glyph id. | |
| 2377 * | |
| 2378 * Fetches the optical bound of a glyph positioned at the margin of text. | |
| 2379 * The direction identifies which edge of the glyph to query. | |
| 2380 * | |
| 2381 * Return value: Adjustment value. Negative values mean the glyph will stick out of the margin. | |
| 2382 * | |
| 2383 * Since: 5.3.0 | |
| 2384 **/ | |
| 2385 hb_position_t | |
| 2386 hb_ot_layout_lookup_get_optical_bound (hb_font_t *font, | |
| 2387 unsigned lookup_index, | |
| 2388 hb_direction_t direction, | |
| 2389 hb_codepoint_t glyph) | |
| 2390 { | |
| 2391 const OT::PosLookup &lookup = font->face->table.GPOS->table->get_lookup (lookup_index); | |
| 2392 hb_glyph_position_t pos = {0}; | |
| 2393 hb_position_single_dispatch_t c; | |
| 2394 lookup.dispatch (&c, font, direction, glyph, pos); | |
| 2395 hb_position_t ret = 0; | |
| 2396 switch (direction) | |
| 2397 { | |
| 2398 case HB_DIRECTION_LTR: | |
| 2399 ret = pos.x_offset; | |
| 2400 break; | |
| 2401 case HB_DIRECTION_RTL: | |
| 2402 ret = pos.x_advance - pos.x_offset; | |
| 2403 break; | |
| 2404 case HB_DIRECTION_TTB: | |
| 2405 ret = pos.y_offset; | |
| 2406 break; | |
| 2407 case HB_DIRECTION_BTT: | |
| 2408 ret = pos.y_advance - pos.y_offset; | |
| 2409 break; | |
| 2410 case HB_DIRECTION_INVALID: | |
| 2411 default: | |
| 2412 break; | |
| 2413 } | |
| 2414 return ret; | |
| 2415 } | |
| 2416 #endif | |
| 2417 | |
| 2418 | |
| 2419 #endif |
