- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / harfbuzz-ng / 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  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
37 #include <stdlib.h>
38 #include <string.h>
39
40
41 HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
42
43 hb_ot_layout_t *
44 _hb_ot_layout_create (hb_face_t *face)
45 {
46   hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
47   if (unlikely (!layout))
48     return NULL;
49
50   layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
51   layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
52
53   layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
54   layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
55
56   layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
57   layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
58
59   layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
60   layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
61
62   layout->gsub_digests = (hb_set_digest_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_set_digest_t));
63   layout->gpos_digests = (hb_set_digest_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_set_digest_t));
64
65   if (unlikely ((layout->gsub_lookup_count && !layout->gsub_digests) ||
66                 (layout->gpos_lookup_count && !layout->gpos_digests)))
67   {
68     _hb_ot_layout_destroy (layout);
69     return NULL;
70   }
71
72   for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
73   {
74     layout->gsub_digests[i].init ();
75     layout->gsub->get_lookup (i).add_coverage (&layout->gsub_digests[i]);
76   }
77   for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
78   {
79     layout->gpos_digests[i].init ();
80     layout->gpos->get_lookup (i).add_coverage (&layout->gpos_digests[i]);
81   }
82
83   return layout;
84 }
85
86 void
87 _hb_ot_layout_destroy (hb_ot_layout_t *layout)
88 {
89   hb_blob_destroy (layout->gdef_blob);
90   hb_blob_destroy (layout->gsub_blob);
91   hb_blob_destroy (layout->gpos_blob);
92
93   free (layout->gsub_digests);
94   free (layout->gpos_digests);
95
96   free (layout);
97 }
98
99 static inline const OT::GDEF&
100 _get_gdef (hb_face_t *face)
101 {
102   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
103   return *hb_ot_layout_from_face (face)->gdef;
104 }
105 static inline const OT::GSUB&
106 _get_gsub (hb_face_t *face)
107 {
108   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
109   return *hb_ot_layout_from_face (face)->gsub;
110 }
111 static inline const OT::GPOS&
112 _get_gpos (hb_face_t *face)
113 {
114   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
115   return *hb_ot_layout_from_face (face)->gpos;
116 }
117
118
119 /*
120  * GDEF
121  */
122
123 hb_bool_t
124 hb_ot_layout_has_glyph_classes (hb_face_t *face)
125 {
126   return _get_gdef (face).has_glyph_classes ();
127 }
128
129 hb_ot_layout_glyph_class_t
130 hb_ot_layout_get_glyph_class (hb_face_t      *face,
131                               hb_codepoint_t  glyph)
132 {
133   return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
134 }
135
136 void
137 hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
138                                   hb_ot_layout_glyph_class_t  klass,
139                                   hb_set_t                   *glyphs /* OUT */)
140 {
141   return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
142 }
143
144 unsigned int
145 hb_ot_layout_get_attach_points (hb_face_t      *face,
146                                 hb_codepoint_t  glyph,
147                                 unsigned int    start_offset,
148                                 unsigned int   *point_count /* IN/OUT */,
149                                 unsigned int   *point_array /* OUT */)
150 {
151   return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
152 }
153
154 unsigned int
155 hb_ot_layout_get_ligature_carets (hb_font_t      *font,
156                                   hb_direction_t  direction,
157                                   hb_codepoint_t  glyph,
158                                   unsigned int    start_offset,
159                                   unsigned int   *caret_count /* IN/OUT */,
160                                   int            *caret_array /* OUT */)
161 {
162   return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
163 }
164
165
166 /*
167  * GSUB/GPOS
168  */
169
170 static const OT::GSUBGPOS&
171 get_gsubgpos_table (hb_face_t *face,
172                     hb_tag_t   table_tag)
173 {
174   switch (table_tag) {
175     case HB_OT_TAG_GSUB: return _get_gsub (face);
176     case HB_OT_TAG_GPOS: return _get_gpos (face);
177     default:             return OT::Null(OT::GSUBGPOS);
178   }
179 }
180
181
182 unsigned int
183 hb_ot_layout_table_get_script_tags (hb_face_t    *face,
184                                     hb_tag_t      table_tag,
185                                     unsigned int  start_offset,
186                                     unsigned int *script_count /* IN/OUT */,
187                                     hb_tag_t     *script_tags /* OUT */)
188 {
189   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
190
191   return g.get_script_tags (start_offset, script_count, script_tags);
192 }
193
194 #define HB_OT_TAG_LATIN_SCRIPT          HB_TAG ('l', 'a', 't', 'n')
195
196 hb_bool_t
197 hb_ot_layout_table_find_script (hb_face_t    *face,
198                                 hb_tag_t      table_tag,
199                                 hb_tag_t      script_tag,
200                                 unsigned int *script_index)
201 {
202   ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
203   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
204
205   if (g.find_script_index (script_tag, script_index))
206     return true;
207
208   /* try finding 'DFLT' */
209   if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
210     return false;
211
212   /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
213    * including many versions of DejaVu Sans Mono! */
214   if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
215     return false;
216
217   /* try with 'latn'; some old fonts put their features there even though
218      they're really trying to support Thai, for example :( */
219   if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
220     return false;
221
222   if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
223   return false;
224 }
225
226 hb_bool_t
227 hb_ot_layout_table_choose_script (hb_face_t      *face,
228                                   hb_tag_t        table_tag,
229                                   const hb_tag_t *script_tags,
230                                   unsigned int   *script_index,
231                                   hb_tag_t       *chosen_script)
232 {
233   ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
234   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
235
236   while (*script_tags)
237   {
238     if (g.find_script_index (*script_tags, script_index)) {
239       if (chosen_script)
240         *chosen_script = *script_tags;
241       return true;
242     }
243     script_tags++;
244   }
245
246   /* try finding 'DFLT' */
247   if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
248     if (chosen_script)
249       *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
250     return false;
251   }
252
253   /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
254   if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
255     if (chosen_script)
256       *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
257     return false;
258   }
259
260   /* try with 'latn'; some old fonts put their features there even though
261      they're really trying to support Thai, for example :( */
262   if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
263     if (chosen_script)
264       *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
265     return false;
266   }
267
268   if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
269   if (chosen_script)
270     *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
271   return false;
272 }
273
274 unsigned int
275 hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
276                                      hb_tag_t      table_tag,
277                                      unsigned int  start_offset,
278                                      unsigned int *feature_count /* IN/OUT */,
279                                      hb_tag_t     *feature_tags /* OUT */)
280 {
281   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
282
283   return g.get_feature_tags (start_offset, feature_count, feature_tags);
284 }
285
286
287 unsigned int
288 hb_ot_layout_script_get_language_tags (hb_face_t    *face,
289                                        hb_tag_t      table_tag,
290                                        unsigned int  script_index,
291                                        unsigned int  start_offset,
292                                        unsigned int *language_count /* IN/OUT */,
293                                        hb_tag_t     *language_tags /* OUT */)
294 {
295   const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
296
297   return s.get_lang_sys_tags (start_offset, language_count, language_tags);
298 }
299
300 hb_bool_t
301 hb_ot_layout_script_find_language (hb_face_t    *face,
302                                    hb_tag_t      table_tag,
303                                    unsigned int  script_index,
304                                    hb_tag_t      language_tag,
305                                    unsigned int *language_index)
306 {
307   ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
308   const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
309
310   if (s.find_lang_sys_index (language_tag, language_index))
311     return true;
312
313   /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
314   if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
315     return false;
316
317   if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
318   return false;
319 }
320
321 hb_bool_t
322 hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
323                                                   hb_tag_t      table_tag,
324                                                   unsigned int  script_index,
325                                                   unsigned int  language_index,
326                                                   unsigned int *feature_index)
327 {
328   const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
329
330   if (feature_index) *feature_index = l.get_required_feature_index ();
331
332   return l.has_required_feature ();
333 }
334
335 unsigned int
336 hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
337                                            hb_tag_t      table_tag,
338                                            unsigned int  script_index,
339                                            unsigned int  language_index,
340                                            unsigned int  start_offset,
341                                            unsigned int *feature_count /* IN/OUT */,
342                                            unsigned int *feature_indexes /* OUT */)
343 {
344   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
345   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
346
347   return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
348 }
349
350 unsigned int
351 hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
352                                         hb_tag_t      table_tag,
353                                         unsigned int  script_index,
354                                         unsigned int  language_index,
355                                         unsigned int  start_offset,
356                                         unsigned int *feature_count /* IN/OUT */,
357                                         hb_tag_t     *feature_tags /* OUT */)
358 {
359   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
360   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
361
362   ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
363   unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
364
365   if (feature_tags) {
366     unsigned int count = *feature_count;
367     for (unsigned int i = 0; i < count; i++)
368       feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
369   }
370
371   return ret;
372 }
373
374
375 hb_bool_t
376 hb_ot_layout_language_find_feature (hb_face_t    *face,
377                                     hb_tag_t      table_tag,
378                                     unsigned int  script_index,
379                                     unsigned int  language_index,
380                                     hb_tag_t      feature_tag,
381                                     unsigned int *feature_index)
382 {
383   ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
384   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
385   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
386
387   unsigned int num_features = l.get_feature_count ();
388   for (unsigned int i = 0; i < num_features; i++) {
389     unsigned int f_index = l.get_feature_index (i);
390
391     if (feature_tag == g.get_feature_tag (f_index)) {
392       if (feature_index) *feature_index = f_index;
393       return true;
394     }
395   }
396
397   if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
398   return false;
399 }
400
401 unsigned int
402 hb_ot_layout_feature_get_lookups (hb_face_t    *face,
403                                   hb_tag_t      table_tag,
404                                   unsigned int  feature_index,
405                                   unsigned int  start_offset,
406                                   unsigned int *lookup_count /* IN/OUT */,
407                                   unsigned int *lookup_indexes /* OUT */)
408 {
409   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
410   const OT::Feature &f = g.get_feature (feature_index);
411
412   return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
413 }
414
415 static void
416 _hb_ot_layout_collect_lookups_lookups (hb_face_t      *face,
417                                        hb_tag_t        table_tag,
418                                        unsigned int    feature_index,
419                                        hb_set_t       *lookup_indexes /* OUT */)
420 {
421   unsigned int lookup_indices[32];
422   unsigned int offset, len;
423
424   offset = 0;
425   do {
426     len = ARRAY_LENGTH (lookup_indices);
427     hb_ot_layout_feature_get_lookups (face,
428                                       table_tag,
429                                       feature_index,
430                                       offset, &len,
431                                       lookup_indices);
432
433     for (unsigned int i = 0; i < len; i++)
434       lookup_indexes->add (lookup_indices[i]);
435
436     offset += len;
437   } while (len == ARRAY_LENGTH (lookup_indices));
438 }
439
440 static void
441 _hb_ot_layout_collect_lookups_features (hb_face_t      *face,
442                                         hb_tag_t        table_tag,
443                                         unsigned int    script_index,
444                                         unsigned int    language_index,
445                                         const hb_tag_t *features,
446                                         hb_set_t       *lookup_indexes /* OUT */)
447 {
448   unsigned int required_feature_index;
449   if (hb_ot_layout_language_get_required_feature_index (face,
450                                                         table_tag,
451                                                         script_index,
452                                                         language_index,
453                                                         &required_feature_index))
454     _hb_ot_layout_collect_lookups_lookups (face,
455                                            table_tag,
456                                            required_feature_index,
457                                            lookup_indexes);
458
459   if (!features)
460   {
461     /* All features */
462     unsigned int feature_indices[32];
463     unsigned int offset, len;
464
465     offset = 0;
466     do {
467       len = ARRAY_LENGTH (feature_indices);
468       hb_ot_layout_language_get_feature_indexes (face,
469                                                  table_tag,
470                                                  script_index,
471                                                  language_index,
472                                                  offset, &len,
473                                                  feature_indices);
474
475       for (unsigned int i = 0; i < len; i++)
476         _hb_ot_layout_collect_lookups_lookups (face,
477                                                table_tag,
478                                                feature_indices[i],
479                                                lookup_indexes);
480
481       offset += len;
482     } while (len == ARRAY_LENGTH (feature_indices));
483   }
484   else
485   {
486     for (; *features; features++)
487     {
488       unsigned int feature_index;
489       if (hb_ot_layout_language_find_feature (face,
490                                               table_tag,
491                                               script_index,
492                                               language_index,
493                                               *features,
494                                               &feature_index))
495         _hb_ot_layout_collect_lookups_lookups (face,
496                                                table_tag,
497                                                feature_index,
498                                                lookup_indexes);
499     }
500   }
501 }
502
503 static void
504 _hb_ot_layout_collect_lookups_languages (hb_face_t      *face,
505                                          hb_tag_t        table_tag,
506                                          unsigned int    script_index,
507                                          const hb_tag_t *languages,
508                                          const hb_tag_t *features,
509                                          hb_set_t       *lookup_indexes /* OUT */)
510 {
511   _hb_ot_layout_collect_lookups_features (face,
512                                           table_tag,
513                                           script_index,
514                                           HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
515                                           features,
516                                           lookup_indexes);
517
518   if (!languages)
519   {
520     /* All languages */
521     unsigned int count = hb_ot_layout_script_get_language_tags (face,
522                                                                 table_tag,
523                                                                 script_index,
524                                                                 0, NULL, NULL);
525     for (unsigned int language_index = 0; language_index < count; language_index++)
526       _hb_ot_layout_collect_lookups_features (face,
527                                               table_tag,
528                                               script_index,
529                                               language_index,
530                                               features,
531                                               lookup_indexes);
532   }
533   else
534   {
535     for (; *languages; languages++)
536     {
537       unsigned int language_index;
538       if (hb_ot_layout_script_find_language (face,
539                                              table_tag,
540                                              script_index,
541                                              *languages,
542                                              &language_index))
543         _hb_ot_layout_collect_lookups_features (face,
544                                                 table_tag,
545                                                 script_index,
546                                                 language_index,
547                                                 features,
548                                                 lookup_indexes);
549     }
550   }
551 }
552
553 void
554 hb_ot_layout_collect_lookups (hb_face_t      *face,
555                               hb_tag_t        table_tag,
556                               const hb_tag_t *scripts,
557                               const hb_tag_t *languages,
558                               const hb_tag_t *features,
559                               hb_set_t       *lookup_indexes /* OUT */)
560 {
561   if (!scripts)
562   {
563     /* All scripts */
564     unsigned int count = hb_ot_layout_table_get_script_tags (face,
565                                                              table_tag,
566                                                              0, NULL, NULL);
567     for (unsigned int script_index = 0; script_index < count; script_index++)
568       _hb_ot_layout_collect_lookups_languages (face,
569                                                table_tag,
570                                                script_index,
571                                                languages,
572                                                features,
573                                                lookup_indexes);
574   }
575   else
576   {
577     for (; *scripts; scripts++)
578     {
579       unsigned int script_index;
580       if (hb_ot_layout_table_find_script (face,
581                                           table_tag,
582                                           *scripts,
583                                           &script_index))
584         _hb_ot_layout_collect_lookups_languages (face,
585                                                  table_tag,
586                                                  script_index,
587                                                  languages,
588                                                  features,
589                                                  lookup_indexes);
590     }
591   }
592 }
593
594 void
595 hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
596                                     hb_tag_t      table_tag,
597                                     unsigned int  lookup_index,
598                                     hb_set_t     *glyphs_before, /* OUT. May be NULL */
599                                     hb_set_t     *glyphs_input,  /* OUT. May be NULL */
600                                     hb_set_t     *glyphs_after,  /* OUT. May be NULL */
601                                     hb_set_t     *glyphs_output  /* OUT. May be NULL */)
602 {
603   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
604
605   OT::hb_collect_glyphs_context_t c (face,
606                                      glyphs_before,
607                                      glyphs_input,
608                                      glyphs_after,
609                                      glyphs_output);
610
611   switch (table_tag)
612   {
613     case HB_OT_TAG_GSUB:
614     {
615       const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
616       l.collect_glyphs_lookup (&c);
617       return;
618     }
619     case HB_OT_TAG_GPOS:
620     {
621       const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
622       l.collect_glyphs_lookup (&c);
623       return;
624     }
625   }
626 }
627
628
629 /*
630  * OT::GSUB
631  */
632
633 hb_bool_t
634 hb_ot_layout_has_substitution (hb_face_t *face)
635 {
636   return &_get_gsub (face) != &OT::Null(OT::GSUB);
637 }
638
639 hb_bool_t
640 hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
641                                       unsigned int          lookup_index,
642                                       const hb_codepoint_t *glyphs,
643                                       unsigned int          glyphs_length,
644                                       hb_bool_t             zero_context)
645 {
646   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
647   return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
648 }
649
650 hb_bool_t
651 hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
652                                            unsigned int          lookup_index,
653                                            const hb_codepoint_t *glyphs,
654                                            unsigned int          glyphs_length,
655                                            hb_bool_t             zero_context)
656 {
657   if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
658   OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
659
660   const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
661
662   return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_digests[lookup_index]);
663 }
664
665 void
666 hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
667 {
668   OT::GSUB::substitute_start (font, buffer);
669 }
670
671 hb_bool_t
672 hb_ot_layout_substitute_lookup (hb_font_t    *font,
673                                 hb_buffer_t  *buffer,
674                                 unsigned int  lookup_index,
675                                 hb_mask_t     mask,
676                                 hb_bool_t     auto_zwj)
677 {
678   if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false;
679
680   OT::hb_apply_context_t c (0, font, buffer, mask, auto_zwj);
681
682   const OT::SubstLookup& l = hb_ot_layout_from_face (font->face)->gsub->get_lookup (lookup_index);
683
684   return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gsub_digests[lookup_index]);
685 }
686
687 void
688 hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
689 {
690   OT::GSUB::substitute_finish (font, buffer);
691 }
692
693 void
694 hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
695                                         unsigned int  lookup_index,
696                                         hb_set_t     *glyphs)
697 {
698   OT::hb_closure_context_t c (face, glyphs);
699
700   const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
701
702   l.closure (&c);
703 }
704
705 /*
706  * OT::GPOS
707  */
708
709 hb_bool_t
710 hb_ot_layout_has_positioning (hb_face_t *face)
711 {
712   return &_get_gpos (face) != &OT::Null(OT::GPOS);
713 }
714
715 void
716 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
717 {
718   OT::GPOS::position_start (font, buffer);
719 }
720
721 hb_bool_t
722 hb_ot_layout_position_lookup (hb_font_t    *font,
723                               hb_buffer_t  *buffer,
724                               unsigned int  lookup_index,
725                               hb_mask_t     mask,
726                               hb_bool_t     auto_zwj)
727 {
728   if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false;
729
730   OT::hb_apply_context_t c (1, font, buffer, mask, auto_zwj);
731
732   const OT::PosLookup& l = hb_ot_layout_from_face (font->face)->gpos->get_lookup (lookup_index);
733
734   return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gpos_digests[lookup_index]);
735 }
736
737 void
738 hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
739 {
740   OT::GPOS::position_finish (font, buffer);
741 }
742
743 hb_bool_t
744 hb_ot_layout_get_size_params (hb_face_t    *face,
745                               unsigned int *design_size,       /* OUT.  May be NULL */
746                               unsigned int *subfamily_id,      /* OUT.  May be NULL */
747                               unsigned int *subfamily_name_id, /* OUT.  May be NULL */
748                               unsigned int *range_start,       /* OUT.  May be NULL */
749                               unsigned int *range_end          /* OUT.  May be NULL */)
750 {
751   const OT::GPOS &gpos = _get_gpos (face);
752   const hb_tag_t tag = HB_TAG ('s','i','z','e');
753
754   unsigned int num_features = gpos.get_feature_count ();
755   for (unsigned int i = 0; i < num_features; i++)
756   {
757     if (tag == gpos.get_feature_tag (i))
758     {
759       const OT::Feature &f = gpos.get_feature (i);
760       const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
761
762       if (params.designSize)
763       {
764 #define PARAM(a, A) if (a) *a = params.A
765         PARAM (design_size, designSize);
766         PARAM (subfamily_id, subfamilyID);
767         PARAM (subfamily_name_id, subfamilyNameID);
768         PARAM (range_start, rangeStart);
769         PARAM (range_end, rangeEnd);
770 #undef PARAM
771
772         return true;
773       }
774     }
775   }
776
777 #define PARAM(a, A) if (a) *a = 0
778   PARAM (design_size, designSize);
779   PARAM (subfamily_id, subfamilyID);
780   PARAM (subfamily_name_id, subfamilyNameID);
781   PARAM (range_start, rangeStart);
782   PARAM (range_end, rangeEnd);
783 #undef PARAM
784
785   return false;
786 }