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