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