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