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