gfx/harfbuzz/src/hb-ot-layout.cc

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 /*
michael@0 2 * Copyright © 1998-2004 David Turner and Werner Lemberg
michael@0 3 * Copyright © 2006 Behdad Esfahbod
michael@0 4 * Copyright © 2007,2008,2009 Red Hat, Inc.
michael@0 5 * Copyright © 2012,2013 Google, Inc.
michael@0 6 *
michael@0 7 * This is part of HarfBuzz, a text shaping library.
michael@0 8 *
michael@0 9 * Permission is hereby granted, without written agreement and without
michael@0 10 * license or royalty fees, to use, copy, modify, and distribute this
michael@0 11 * software and its documentation for any purpose, provided that the
michael@0 12 * above copyright notice and the following two paragraphs appear in
michael@0 13 * all copies of this software.
michael@0 14 *
michael@0 15 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
michael@0 16 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
michael@0 17 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
michael@0 18 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
michael@0 19 * DAMAGE.
michael@0 20 *
michael@0 21 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
michael@0 22 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
michael@0 23 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
michael@0 24 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
michael@0 25 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
michael@0 26 *
michael@0 27 * Red Hat Author(s): Behdad Esfahbod
michael@0 28 * Google Author(s): Behdad Esfahbod
michael@0 29 */
michael@0 30
michael@0 31 #include "hb-ot-layout-private.hh"
michael@0 32
michael@0 33 #include "hb-ot-layout-gdef-table.hh"
michael@0 34 #include "hb-ot-layout-gsub-table.hh"
michael@0 35 #include "hb-ot-layout-gpos-table.hh"
michael@0 36 #include "hb-ot-layout-jstf-table.hh"
michael@0 37
michael@0 38 #include "hb-ot-map-private.hh"
michael@0 39
michael@0 40 #include <stdlib.h>
michael@0 41 #include <string.h>
michael@0 42
michael@0 43
michael@0 44 HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
michael@0 45
michael@0 46 hb_ot_layout_t *
michael@0 47 _hb_ot_layout_create (hb_face_t *face)
michael@0 48 {
michael@0 49 hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
michael@0 50 if (unlikely (!layout))
michael@0 51 return NULL;
michael@0 52
michael@0 53 layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
michael@0 54 layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
michael@0 55
michael@0 56 layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
michael@0 57 layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
michael@0 58
michael@0 59 layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
michael@0 60 layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
michael@0 61
michael@0 62 layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
michael@0 63 layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
michael@0 64
michael@0 65 layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
michael@0 66 layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
michael@0 67
michael@0 68 if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
michael@0 69 (layout->gpos_lookup_count && !layout->gpos_accels)))
michael@0 70 {
michael@0 71 _hb_ot_layout_destroy (layout);
michael@0 72 return NULL;
michael@0 73 }
michael@0 74
michael@0 75 for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
michael@0 76 layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
michael@0 77 for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
michael@0 78 layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
michael@0 79
michael@0 80 return layout;
michael@0 81 }
michael@0 82
michael@0 83 void
michael@0 84 _hb_ot_layout_destroy (hb_ot_layout_t *layout)
michael@0 85 {
michael@0 86 for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
michael@0 87 layout->gsub_accels[i].fini (layout->gsub->get_lookup (i));
michael@0 88 for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
michael@0 89 layout->gpos_accels[i].fini (layout->gpos->get_lookup (i));
michael@0 90
michael@0 91 free (layout->gsub_accels);
michael@0 92 free (layout->gpos_accels);
michael@0 93
michael@0 94 hb_blob_destroy (layout->gdef_blob);
michael@0 95 hb_blob_destroy (layout->gsub_blob);
michael@0 96 hb_blob_destroy (layout->gpos_blob);
michael@0 97
michael@0 98 free (layout);
michael@0 99 }
michael@0 100
michael@0 101 static inline const OT::GDEF&
michael@0 102 _get_gdef (hb_face_t *face)
michael@0 103 {
michael@0 104 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
michael@0 105 return *hb_ot_layout_from_face (face)->gdef;
michael@0 106 }
michael@0 107 static inline const OT::GSUB&
michael@0 108 _get_gsub (hb_face_t *face)
michael@0 109 {
michael@0 110 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
michael@0 111 return *hb_ot_layout_from_face (face)->gsub;
michael@0 112 }
michael@0 113 static inline const OT::GPOS&
michael@0 114 _get_gpos (hb_face_t *face)
michael@0 115 {
michael@0 116 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
michael@0 117 return *hb_ot_layout_from_face (face)->gpos;
michael@0 118 }
michael@0 119
michael@0 120
michael@0 121 /*
michael@0 122 * GDEF
michael@0 123 */
michael@0 124
michael@0 125 hb_bool_t
michael@0 126 hb_ot_layout_has_glyph_classes (hb_face_t *face)
michael@0 127 {
michael@0 128 return _get_gdef (face).has_glyph_classes ();
michael@0 129 }
michael@0 130
michael@0 131 hb_ot_layout_glyph_class_t
michael@0 132 hb_ot_layout_get_glyph_class (hb_face_t *face,
michael@0 133 hb_codepoint_t glyph)
michael@0 134 {
michael@0 135 return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
michael@0 136 }
michael@0 137
michael@0 138 void
michael@0 139 hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
michael@0 140 hb_ot_layout_glyph_class_t klass,
michael@0 141 hb_set_t *glyphs /* OUT */)
michael@0 142 {
michael@0 143 return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
michael@0 144 }
michael@0 145
michael@0 146 unsigned int
michael@0 147 hb_ot_layout_get_attach_points (hb_face_t *face,
michael@0 148 hb_codepoint_t glyph,
michael@0 149 unsigned int start_offset,
michael@0 150 unsigned int *point_count /* IN/OUT */,
michael@0 151 unsigned int *point_array /* OUT */)
michael@0 152 {
michael@0 153 return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
michael@0 154 }
michael@0 155
michael@0 156 unsigned int
michael@0 157 hb_ot_layout_get_ligature_carets (hb_font_t *font,
michael@0 158 hb_direction_t direction,
michael@0 159 hb_codepoint_t glyph,
michael@0 160 unsigned int start_offset,
michael@0 161 unsigned int *caret_count /* IN/OUT */,
michael@0 162 int *caret_array /* OUT */)
michael@0 163 {
michael@0 164 return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
michael@0 165 }
michael@0 166
michael@0 167
michael@0 168 /*
michael@0 169 * GSUB/GPOS
michael@0 170 */
michael@0 171
michael@0 172 static const OT::GSUBGPOS&
michael@0 173 get_gsubgpos_table (hb_face_t *face,
michael@0 174 hb_tag_t table_tag)
michael@0 175 {
michael@0 176 switch (table_tag) {
michael@0 177 case HB_OT_TAG_GSUB: return _get_gsub (face);
michael@0 178 case HB_OT_TAG_GPOS: return _get_gpos (face);
michael@0 179 default: return OT::Null(OT::GSUBGPOS);
michael@0 180 }
michael@0 181 }
michael@0 182
michael@0 183
michael@0 184 unsigned int
michael@0 185 hb_ot_layout_table_get_script_tags (hb_face_t *face,
michael@0 186 hb_tag_t table_tag,
michael@0 187 unsigned int start_offset,
michael@0 188 unsigned int *script_count /* IN/OUT */,
michael@0 189 hb_tag_t *script_tags /* OUT */)
michael@0 190 {
michael@0 191 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
michael@0 192
michael@0 193 return g.get_script_tags (start_offset, script_count, script_tags);
michael@0 194 }
michael@0 195
michael@0 196 #define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n')
michael@0 197
michael@0 198 hb_bool_t
michael@0 199 hb_ot_layout_table_find_script (hb_face_t *face,
michael@0 200 hb_tag_t table_tag,
michael@0 201 hb_tag_t script_tag,
michael@0 202 unsigned int *script_index)
michael@0 203 {
michael@0 204 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
michael@0 205 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
michael@0 206
michael@0 207 if (g.find_script_index (script_tag, script_index))
michael@0 208 return true;
michael@0 209
michael@0 210 /* try finding 'DFLT' */
michael@0 211 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
michael@0 212 return false;
michael@0 213
michael@0 214 /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
michael@0 215 * including many versions of DejaVu Sans Mono! */
michael@0 216 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
michael@0 217 return false;
michael@0 218
michael@0 219 /* try with 'latn'; some old fonts put their features there even though
michael@0 220 they're really trying to support Thai, for example :( */
michael@0 221 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
michael@0 222 return false;
michael@0 223
michael@0 224 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
michael@0 225 return false;
michael@0 226 }
michael@0 227
michael@0 228 hb_bool_t
michael@0 229 hb_ot_layout_table_choose_script (hb_face_t *face,
michael@0 230 hb_tag_t table_tag,
michael@0 231 const hb_tag_t *script_tags,
michael@0 232 unsigned int *script_index,
michael@0 233 hb_tag_t *chosen_script)
michael@0 234 {
michael@0 235 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
michael@0 236 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
michael@0 237
michael@0 238 while (*script_tags)
michael@0 239 {
michael@0 240 if (g.find_script_index (*script_tags, script_index)) {
michael@0 241 if (chosen_script)
michael@0 242 *chosen_script = *script_tags;
michael@0 243 return true;
michael@0 244 }
michael@0 245 script_tags++;
michael@0 246 }
michael@0 247
michael@0 248 /* try finding 'DFLT' */
michael@0 249 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
michael@0 250 if (chosen_script)
michael@0 251 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
michael@0 252 return false;
michael@0 253 }
michael@0 254
michael@0 255 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
michael@0 256 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
michael@0 257 if (chosen_script)
michael@0 258 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
michael@0 259 return false;
michael@0 260 }
michael@0 261
michael@0 262 /* try with 'latn'; some old fonts put their features there even though
michael@0 263 they're really trying to support Thai, for example :( */
michael@0 264 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
michael@0 265 if (chosen_script)
michael@0 266 *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
michael@0 267 return false;
michael@0 268 }
michael@0 269
michael@0 270 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
michael@0 271 if (chosen_script)
michael@0 272 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
michael@0 273 return false;
michael@0 274 }
michael@0 275
michael@0 276 unsigned int
michael@0 277 hb_ot_layout_table_get_feature_tags (hb_face_t *face,
michael@0 278 hb_tag_t table_tag,
michael@0 279 unsigned int start_offset,
michael@0 280 unsigned int *feature_count /* IN/OUT */,
michael@0 281 hb_tag_t *feature_tags /* OUT */)
michael@0 282 {
michael@0 283 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
michael@0 284
michael@0 285 return g.get_feature_tags (start_offset, feature_count, feature_tags);
michael@0 286 }
michael@0 287
michael@0 288
michael@0 289 unsigned int
michael@0 290 hb_ot_layout_script_get_language_tags (hb_face_t *face,
michael@0 291 hb_tag_t table_tag,
michael@0 292 unsigned int script_index,
michael@0 293 unsigned int start_offset,
michael@0 294 unsigned int *language_count /* IN/OUT */,
michael@0 295 hb_tag_t *language_tags /* OUT */)
michael@0 296 {
michael@0 297 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
michael@0 298
michael@0 299 return s.get_lang_sys_tags (start_offset, language_count, language_tags);
michael@0 300 }
michael@0 301
michael@0 302 hb_bool_t
michael@0 303 hb_ot_layout_script_find_language (hb_face_t *face,
michael@0 304 hb_tag_t table_tag,
michael@0 305 unsigned int script_index,
michael@0 306 hb_tag_t language_tag,
michael@0 307 unsigned int *language_index)
michael@0 308 {
michael@0 309 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
michael@0 310 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
michael@0 311
michael@0 312 if (s.find_lang_sys_index (language_tag, language_index))
michael@0 313 return true;
michael@0 314
michael@0 315 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
michael@0 316 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
michael@0 317 return false;
michael@0 318
michael@0 319 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
michael@0 320 return false;
michael@0 321 }
michael@0 322
michael@0 323 hb_bool_t
michael@0 324 hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
michael@0 325 hb_tag_t table_tag,
michael@0 326 unsigned int script_index,
michael@0 327 unsigned int language_index,
michael@0 328 unsigned int *feature_index)
michael@0 329 {
michael@0 330 const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
michael@0 331
michael@0 332 if (feature_index) *feature_index = l.get_required_feature_index ();
michael@0 333
michael@0 334 return l.has_required_feature ();
michael@0 335 }
michael@0 336
michael@0 337 unsigned int
michael@0 338 hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
michael@0 339 hb_tag_t table_tag,
michael@0 340 unsigned int script_index,
michael@0 341 unsigned int language_index,
michael@0 342 unsigned int start_offset,
michael@0 343 unsigned int *feature_count /* IN/OUT */,
michael@0 344 unsigned int *feature_indexes /* OUT */)
michael@0 345 {
michael@0 346 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
michael@0 347 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
michael@0 348
michael@0 349 return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
michael@0 350 }
michael@0 351
michael@0 352 unsigned int
michael@0 353 hb_ot_layout_language_get_feature_tags (hb_face_t *face,
michael@0 354 hb_tag_t table_tag,
michael@0 355 unsigned int script_index,
michael@0 356 unsigned int language_index,
michael@0 357 unsigned int start_offset,
michael@0 358 unsigned int *feature_count /* IN/OUT */,
michael@0 359 hb_tag_t *feature_tags /* OUT */)
michael@0 360 {
michael@0 361 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
michael@0 362 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
michael@0 363
michael@0 364 ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
michael@0 365 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
michael@0 366
michael@0 367 if (feature_tags) {
michael@0 368 unsigned int count = *feature_count;
michael@0 369 for (unsigned int i = 0; i < count; i++)
michael@0 370 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
michael@0 371 }
michael@0 372
michael@0 373 return ret;
michael@0 374 }
michael@0 375
michael@0 376
michael@0 377 hb_bool_t
michael@0 378 hb_ot_layout_language_find_feature (hb_face_t *face,
michael@0 379 hb_tag_t table_tag,
michael@0 380 unsigned int script_index,
michael@0 381 unsigned int language_index,
michael@0 382 hb_tag_t feature_tag,
michael@0 383 unsigned int *feature_index)
michael@0 384 {
michael@0 385 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
michael@0 386 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
michael@0 387 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
michael@0 388
michael@0 389 unsigned int num_features = l.get_feature_count ();
michael@0 390 for (unsigned int i = 0; i < num_features; i++) {
michael@0 391 unsigned int f_index = l.get_feature_index (i);
michael@0 392
michael@0 393 if (feature_tag == g.get_feature_tag (f_index)) {
michael@0 394 if (feature_index) *feature_index = f_index;
michael@0 395 return true;
michael@0 396 }
michael@0 397 }
michael@0 398
michael@0 399 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
michael@0 400 return false;
michael@0 401 }
michael@0 402
michael@0 403 unsigned int
michael@0 404 hb_ot_layout_feature_get_lookups (hb_face_t *face,
michael@0 405 hb_tag_t table_tag,
michael@0 406 unsigned int feature_index,
michael@0 407 unsigned int start_offset,
michael@0 408 unsigned int *lookup_count /* IN/OUT */,
michael@0 409 unsigned int *lookup_indexes /* OUT */)
michael@0 410 {
michael@0 411 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
michael@0 412 const OT::Feature &f = g.get_feature (feature_index);
michael@0 413
michael@0 414 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
michael@0 415 }
michael@0 416
michael@0 417 unsigned int
michael@0 418 hb_ot_layout_table_get_lookup_count (hb_face_t *face,
michael@0 419 hb_tag_t table_tag)
michael@0 420 {
michael@0 421 switch (table_tag)
michael@0 422 {
michael@0 423 case HB_OT_TAG_GSUB:
michael@0 424 {
michael@0 425 return hb_ot_layout_from_face (face)->gsub_lookup_count;
michael@0 426 }
michael@0 427 case HB_OT_TAG_GPOS:
michael@0 428 {
michael@0 429 return hb_ot_layout_from_face (face)->gpos_lookup_count;
michael@0 430 }
michael@0 431 }
michael@0 432 return 0;
michael@0 433 }
michael@0 434
michael@0 435 static void
michael@0 436 _hb_ot_layout_collect_lookups_lookups (hb_face_t *face,
michael@0 437 hb_tag_t table_tag,
michael@0 438 unsigned int feature_index,
michael@0 439 hb_set_t *lookup_indexes /* OUT */)
michael@0 440 {
michael@0 441 unsigned int lookup_indices[32];
michael@0 442 unsigned int offset, len;
michael@0 443
michael@0 444 offset = 0;
michael@0 445 do {
michael@0 446 len = ARRAY_LENGTH (lookup_indices);
michael@0 447 hb_ot_layout_feature_get_lookups (face,
michael@0 448 table_tag,
michael@0 449 feature_index,
michael@0 450 offset, &len,
michael@0 451 lookup_indices);
michael@0 452
michael@0 453 for (unsigned int i = 0; i < len; i++)
michael@0 454 lookup_indexes->add (lookup_indices[i]);
michael@0 455
michael@0 456 offset += len;
michael@0 457 } while (len == ARRAY_LENGTH (lookup_indices));
michael@0 458 }
michael@0 459
michael@0 460 static void
michael@0 461 _hb_ot_layout_collect_lookups_features (hb_face_t *face,
michael@0 462 hb_tag_t table_tag,
michael@0 463 unsigned int script_index,
michael@0 464 unsigned int language_index,
michael@0 465 const hb_tag_t *features,
michael@0 466 hb_set_t *lookup_indexes /* OUT */)
michael@0 467 {
michael@0 468 if (!features)
michael@0 469 {
michael@0 470 unsigned int required_feature_index;
michael@0 471 if (hb_ot_layout_language_get_required_feature_index (face,
michael@0 472 table_tag,
michael@0 473 script_index,
michael@0 474 language_index,
michael@0 475 &required_feature_index))
michael@0 476 _hb_ot_layout_collect_lookups_lookups (face,
michael@0 477 table_tag,
michael@0 478 required_feature_index,
michael@0 479 lookup_indexes);
michael@0 480
michael@0 481 /* All features */
michael@0 482 unsigned int feature_indices[32];
michael@0 483 unsigned int offset, len;
michael@0 484
michael@0 485 offset = 0;
michael@0 486 do {
michael@0 487 len = ARRAY_LENGTH (feature_indices);
michael@0 488 hb_ot_layout_language_get_feature_indexes (face,
michael@0 489 table_tag,
michael@0 490 script_index,
michael@0 491 language_index,
michael@0 492 offset, &len,
michael@0 493 feature_indices);
michael@0 494
michael@0 495 for (unsigned int i = 0; i < len; i++)
michael@0 496 _hb_ot_layout_collect_lookups_lookups (face,
michael@0 497 table_tag,
michael@0 498 feature_indices[i],
michael@0 499 lookup_indexes);
michael@0 500
michael@0 501 offset += len;
michael@0 502 } while (len == ARRAY_LENGTH (feature_indices));
michael@0 503 }
michael@0 504 else
michael@0 505 {
michael@0 506 for (; *features; features++)
michael@0 507 {
michael@0 508 unsigned int feature_index;
michael@0 509 if (hb_ot_layout_language_find_feature (face,
michael@0 510 table_tag,
michael@0 511 script_index,
michael@0 512 language_index,
michael@0 513 *features,
michael@0 514 &feature_index))
michael@0 515 _hb_ot_layout_collect_lookups_lookups (face,
michael@0 516 table_tag,
michael@0 517 feature_index,
michael@0 518 lookup_indexes);
michael@0 519 }
michael@0 520 }
michael@0 521 }
michael@0 522
michael@0 523 static void
michael@0 524 _hb_ot_layout_collect_lookups_languages (hb_face_t *face,
michael@0 525 hb_tag_t table_tag,
michael@0 526 unsigned int script_index,
michael@0 527 const hb_tag_t *languages,
michael@0 528 const hb_tag_t *features,
michael@0 529 hb_set_t *lookup_indexes /* OUT */)
michael@0 530 {
michael@0 531 _hb_ot_layout_collect_lookups_features (face,
michael@0 532 table_tag,
michael@0 533 script_index,
michael@0 534 HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
michael@0 535 features,
michael@0 536 lookup_indexes);
michael@0 537
michael@0 538 if (!languages)
michael@0 539 {
michael@0 540 /* All languages */
michael@0 541 unsigned int count = hb_ot_layout_script_get_language_tags (face,
michael@0 542 table_tag,
michael@0 543 script_index,
michael@0 544 0, NULL, NULL);
michael@0 545 for (unsigned int language_index = 0; language_index < count; language_index++)
michael@0 546 _hb_ot_layout_collect_lookups_features (face,
michael@0 547 table_tag,
michael@0 548 script_index,
michael@0 549 language_index,
michael@0 550 features,
michael@0 551 lookup_indexes);
michael@0 552 }
michael@0 553 else
michael@0 554 {
michael@0 555 for (; *languages; languages++)
michael@0 556 {
michael@0 557 unsigned int language_index;
michael@0 558 if (hb_ot_layout_script_find_language (face,
michael@0 559 table_tag,
michael@0 560 script_index,
michael@0 561 *languages,
michael@0 562 &language_index))
michael@0 563 _hb_ot_layout_collect_lookups_features (face,
michael@0 564 table_tag,
michael@0 565 script_index,
michael@0 566 language_index,
michael@0 567 features,
michael@0 568 lookup_indexes);
michael@0 569 }
michael@0 570 }
michael@0 571 }
michael@0 572
michael@0 573 void
michael@0 574 hb_ot_layout_collect_lookups (hb_face_t *face,
michael@0 575 hb_tag_t table_tag,
michael@0 576 const hb_tag_t *scripts,
michael@0 577 const hb_tag_t *languages,
michael@0 578 const hb_tag_t *features,
michael@0 579 hb_set_t *lookup_indexes /* OUT */)
michael@0 580 {
michael@0 581 if (!scripts)
michael@0 582 {
michael@0 583 /* All scripts */
michael@0 584 unsigned int count = hb_ot_layout_table_get_script_tags (face,
michael@0 585 table_tag,
michael@0 586 0, NULL, NULL);
michael@0 587 for (unsigned int script_index = 0; script_index < count; script_index++)
michael@0 588 _hb_ot_layout_collect_lookups_languages (face,
michael@0 589 table_tag,
michael@0 590 script_index,
michael@0 591 languages,
michael@0 592 features,
michael@0 593 lookup_indexes);
michael@0 594 }
michael@0 595 else
michael@0 596 {
michael@0 597 for (; *scripts; scripts++)
michael@0 598 {
michael@0 599 unsigned int script_index;
michael@0 600 if (hb_ot_layout_table_find_script (face,
michael@0 601 table_tag,
michael@0 602 *scripts,
michael@0 603 &script_index))
michael@0 604 _hb_ot_layout_collect_lookups_languages (face,
michael@0 605 table_tag,
michael@0 606 script_index,
michael@0 607 languages,
michael@0 608 features,
michael@0 609 lookup_indexes);
michael@0 610 }
michael@0 611 }
michael@0 612 }
michael@0 613
michael@0 614 void
michael@0 615 hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
michael@0 616 hb_tag_t table_tag,
michael@0 617 unsigned int lookup_index,
michael@0 618 hb_set_t *glyphs_before, /* OUT. May be NULL */
michael@0 619 hb_set_t *glyphs_input, /* OUT. May be NULL */
michael@0 620 hb_set_t *glyphs_after, /* OUT. May be NULL */
michael@0 621 hb_set_t *glyphs_output /* OUT. May be NULL */)
michael@0 622 {
michael@0 623 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
michael@0 624
michael@0 625 OT::hb_collect_glyphs_context_t c (face,
michael@0 626 glyphs_before,
michael@0 627 glyphs_input,
michael@0 628 glyphs_after,
michael@0 629 glyphs_output);
michael@0 630
michael@0 631 switch (table_tag)
michael@0 632 {
michael@0 633 case HB_OT_TAG_GSUB:
michael@0 634 {
michael@0 635 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
michael@0 636 l.collect_glyphs (&c);
michael@0 637 return;
michael@0 638 }
michael@0 639 case HB_OT_TAG_GPOS:
michael@0 640 {
michael@0 641 const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
michael@0 642 l.collect_glyphs (&c);
michael@0 643 return;
michael@0 644 }
michael@0 645 }
michael@0 646 }
michael@0 647
michael@0 648
michael@0 649 /*
michael@0 650 * OT::GSUB
michael@0 651 */
michael@0 652
michael@0 653 hb_bool_t
michael@0 654 hb_ot_layout_has_substitution (hb_face_t *face)
michael@0 655 {
michael@0 656 return &_get_gsub (face) != &OT::Null(OT::GSUB);
michael@0 657 }
michael@0 658
michael@0 659 hb_bool_t
michael@0 660 hb_ot_layout_lookup_would_substitute (hb_face_t *face,
michael@0 661 unsigned int lookup_index,
michael@0 662 const hb_codepoint_t *glyphs,
michael@0 663 unsigned int glyphs_length,
michael@0 664 hb_bool_t zero_context)
michael@0 665 {
michael@0 666 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
michael@0 667 return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
michael@0 668 }
michael@0 669
michael@0 670 hb_bool_t
michael@0 671 hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
michael@0 672 unsigned int lookup_index,
michael@0 673 const hb_codepoint_t *glyphs,
michael@0 674 unsigned int glyphs_length,
michael@0 675 hb_bool_t zero_context)
michael@0 676 {
michael@0 677 if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
michael@0 678 OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
michael@0 679
michael@0 680 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
michael@0 681
michael@0 682 return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index].digest);
michael@0 683 }
michael@0 684
michael@0 685 void
michael@0 686 hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
michael@0 687 {
michael@0 688 OT::GSUB::substitute_start (font, buffer);
michael@0 689 }
michael@0 690
michael@0 691 void
michael@0 692 hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
michael@0 693 {
michael@0 694 OT::GSUB::substitute_finish (font, buffer);
michael@0 695 }
michael@0 696
michael@0 697 void
michael@0 698 hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
michael@0 699 unsigned int lookup_index,
michael@0 700 hb_set_t *glyphs)
michael@0 701 {
michael@0 702 OT::hb_closure_context_t c (face, glyphs);
michael@0 703
michael@0 704 const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
michael@0 705
michael@0 706 l.closure (&c);
michael@0 707 }
michael@0 708
michael@0 709 /*
michael@0 710 * OT::GPOS
michael@0 711 */
michael@0 712
michael@0 713 hb_bool_t
michael@0 714 hb_ot_layout_has_positioning (hb_face_t *face)
michael@0 715 {
michael@0 716 return &_get_gpos (face) != &OT::Null(OT::GPOS);
michael@0 717 }
michael@0 718
michael@0 719 void
michael@0 720 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
michael@0 721 {
michael@0 722 OT::GPOS::position_start (font, buffer);
michael@0 723 }
michael@0 724
michael@0 725 void
michael@0 726 hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
michael@0 727 {
michael@0 728 OT::GPOS::position_finish (font, buffer);
michael@0 729 }
michael@0 730
michael@0 731 hb_bool_t
michael@0 732 hb_ot_layout_get_size_params (hb_face_t *face,
michael@0 733 unsigned int *design_size, /* OUT. May be NULL */
michael@0 734 unsigned int *subfamily_id, /* OUT. May be NULL */
michael@0 735 unsigned int *subfamily_name_id, /* OUT. May be NULL */
michael@0 736 unsigned int *range_start, /* OUT. May be NULL */
michael@0 737 unsigned int *range_end /* OUT. May be NULL */)
michael@0 738 {
michael@0 739 const OT::GPOS &gpos = _get_gpos (face);
michael@0 740 const hb_tag_t tag = HB_TAG ('s','i','z','e');
michael@0 741
michael@0 742 unsigned int num_features = gpos.get_feature_count ();
michael@0 743 for (unsigned int i = 0; i < num_features; i++)
michael@0 744 {
michael@0 745 if (tag == gpos.get_feature_tag (i))
michael@0 746 {
michael@0 747 const OT::Feature &f = gpos.get_feature (i);
michael@0 748 const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
michael@0 749
michael@0 750 if (params.designSize)
michael@0 751 {
michael@0 752 #define PARAM(a, A) if (a) *a = params.A
michael@0 753 PARAM (design_size, designSize);
michael@0 754 PARAM (subfamily_id, subfamilyID);
michael@0 755 PARAM (subfamily_name_id, subfamilyNameID);
michael@0 756 PARAM (range_start, rangeStart);
michael@0 757 PARAM (range_end, rangeEnd);
michael@0 758 #undef PARAM
michael@0 759
michael@0 760 return true;
michael@0 761 }
michael@0 762 }
michael@0 763 }
michael@0 764
michael@0 765 #define PARAM(a, A) if (a) *a = 0
michael@0 766 PARAM (design_size, designSize);
michael@0 767 PARAM (subfamily_id, subfamilyID);
michael@0 768 PARAM (subfamily_name_id, subfamilyNameID);
michael@0 769 PARAM (range_start, rangeStart);
michael@0 770 PARAM (range_end, rangeEnd);
michael@0 771 #undef PARAM
michael@0 772
michael@0 773 return false;
michael@0 774 }
michael@0 775
michael@0 776
michael@0 777 /*
michael@0 778 * Parts of different types are implemented here such that they have direct
michael@0 779 * access to GSUB/GPOS lookups.
michael@0 780 */
michael@0 781
michael@0 782
michael@0 783 struct GSUBProxy
michael@0 784 {
michael@0 785 static const unsigned int table_index = 0;
michael@0 786 static const bool inplace = false;
michael@0 787 typedef OT::SubstLookup Lookup;
michael@0 788
michael@0 789 GSUBProxy (hb_face_t *face) :
michael@0 790 table (*hb_ot_layout_from_face (face)->gsub),
michael@0 791 accels (hb_ot_layout_from_face (face)->gsub_accels) {}
michael@0 792
michael@0 793 const OT::GSUB &table;
michael@0 794 const hb_ot_layout_lookup_accelerator_t *accels;
michael@0 795 };
michael@0 796
michael@0 797 struct GPOSProxy
michael@0 798 {
michael@0 799 static const unsigned int table_index = 1;
michael@0 800 static const bool inplace = true;
michael@0 801 typedef OT::PosLookup Lookup;
michael@0 802
michael@0 803 GPOSProxy (hb_face_t *face) :
michael@0 804 table (*hb_ot_layout_from_face (face)->gpos),
michael@0 805 accels (hb_ot_layout_from_face (face)->gpos_accels) {}
michael@0 806
michael@0 807 const OT::GPOS &table;
michael@0 808 const hb_ot_layout_lookup_accelerator_t *accels;
michael@0 809 };
michael@0 810
michael@0 811
michael@0 812 template <typename Lookup>
michael@0 813 static inline bool apply_once (OT::hb_apply_context_t *c,
michael@0 814 const Lookup &lookup)
michael@0 815 {
michael@0 816 if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
michael@0 817 return false;
michael@0 818 return lookup.dispatch (c);
michael@0 819 }
michael@0 820
michael@0 821 template <typename Proxy>
michael@0 822 static inline bool
michael@0 823 apply_string (OT::hb_apply_context_t *c,
michael@0 824 const typename Proxy::Lookup &lookup,
michael@0 825 const hb_ot_layout_lookup_accelerator_t &accel)
michael@0 826 {
michael@0 827 bool ret = false;
michael@0 828 hb_buffer_t *buffer = c->buffer;
michael@0 829
michael@0 830 if (unlikely (!buffer->len || !c->lookup_mask))
michael@0 831 return false;
michael@0 832
michael@0 833 c->set_lookup (lookup);
michael@0 834
michael@0 835 if (likely (!lookup.is_reverse ()))
michael@0 836 {
michael@0 837 /* in/out forward substitution/positioning */
michael@0 838 if (Proxy::table_index == 0)
michael@0 839 buffer->clear_output ();
michael@0 840 buffer->idx = 0;
michael@0 841
michael@0 842 while (buffer->idx < buffer->len)
michael@0 843 {
michael@0 844 if (accel.digest.may_have (buffer->cur().codepoint) &&
michael@0 845 (buffer->cur().mask & c->lookup_mask) &&
michael@0 846 apply_once (c, lookup))
michael@0 847 ret = true;
michael@0 848 else
michael@0 849 buffer->next_glyph ();
michael@0 850 }
michael@0 851 if (ret)
michael@0 852 {
michael@0 853 if (!Proxy::inplace)
michael@0 854 buffer->swap_buffers ();
michael@0 855 else
michael@0 856 assert (!buffer->has_separate_output ());
michael@0 857 }
michael@0 858 }
michael@0 859 else
michael@0 860 {
michael@0 861 /* in-place backward substitution/positioning */
michael@0 862 if (Proxy::table_index == 0)
michael@0 863 buffer->remove_output ();
michael@0 864 buffer->idx = buffer->len - 1;
michael@0 865 do
michael@0 866 {
michael@0 867 if (accel.digest.may_have (buffer->cur().codepoint) &&
michael@0 868 (buffer->cur().mask & c->lookup_mask) &&
michael@0 869 apply_once (c, lookup))
michael@0 870 ret = true;
michael@0 871 /* The reverse lookup doesn't "advance" cursor (for good reason). */
michael@0 872 buffer->idx--;
michael@0 873
michael@0 874 }
michael@0 875 while ((int) buffer->idx >= 0);
michael@0 876 }
michael@0 877
michael@0 878 return ret;
michael@0 879 }
michael@0 880
michael@0 881 template <typename Proxy>
michael@0 882 inline void hb_ot_map_t::apply (const Proxy &proxy,
michael@0 883 const hb_ot_shape_plan_t *plan,
michael@0 884 hb_font_t *font,
michael@0 885 hb_buffer_t *buffer) const
michael@0 886 {
michael@0 887 const unsigned int table_index = proxy.table_index;
michael@0 888 unsigned int i = 0;
michael@0 889 OT::hb_apply_context_t c (table_index, font, buffer);
michael@0 890 c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
michael@0 891
michael@0 892 for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
michael@0 893 const stage_map_t *stage = &stages[table_index][stage_index];
michael@0 894 for (; i < stage->last_lookup; i++)
michael@0 895 {
michael@0 896 unsigned int lookup_index = lookups[table_index][i].index;
michael@0 897 c.set_lookup_mask (lookups[table_index][i].mask);
michael@0 898 c.set_auto_zwj (lookups[table_index][i].auto_zwj);
michael@0 899 apply_string<Proxy> (&c,
michael@0 900 proxy.table.get_lookup (lookup_index),
michael@0 901 proxy.accels[lookup_index]);
michael@0 902 }
michael@0 903
michael@0 904 if (stage->pause_func)
michael@0 905 {
michael@0 906 buffer->clear_output ();
michael@0 907 stage->pause_func (plan, font, buffer);
michael@0 908 }
michael@0 909 }
michael@0 910 }
michael@0 911
michael@0 912 void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
michael@0 913 {
michael@0 914 GSUBProxy proxy (font->face);
michael@0 915 apply (proxy, plan, font, buffer);
michael@0 916 }
michael@0 917
michael@0 918 void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
michael@0 919 {
michael@0 920 GPOSProxy proxy (font->face);
michael@0 921 apply (proxy, plan, font, buffer);
michael@0 922 }
michael@0 923
michael@0 924 HB_INTERNAL void
michael@0 925 hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
michael@0 926 const OT::SubstLookup &lookup,
michael@0 927 const hb_ot_layout_lookup_accelerator_t &accel)
michael@0 928 {
michael@0 929 apply_string<GSUBProxy> (c, lookup, accel);
michael@0 930 }

mercurial