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