(match_ids): New arg "direction". Callers changed.
[m17n/libotf.git] / src / otfdrive.c
1 /* otfdrive.c -- OpenType font driver.
2
3 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
4   National Institute of Advanced Industrial Science and Technology (AIST)
5   Registration Number H15PRO167
6
7 This file is part of libotf.
8
9 Libotf is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 Libotf is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17 License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library, in a file named COPYING; if not,
21 write to the Free Software Foundation, Inc., 59 Temple Place, Suite
22 330, Boston, MA 02111-1307, USA.  */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <config.h>
28
29 #include "otf.h"
30 #include "otferror.h"
31
32 extern int debug_flag;
33
34 /* Return nonzero (-1 if ID is zero, 1 otherwise) if OTF_Glyph *G
35    should be ignored according to LookupFlag FLAG.  */
36 #define IGNORED_GLYPH(g, flag)                          \
37   ((g)->glyph_id == 0 ? -1                              \
38    : (((flag) & (1 << (g)->GlyphClass))                 \
39       || (((flag) & OTF_MarkAttachmentType)             \
40           && (g)->GlyphClass == OTF_GlyphClassMark      \
41           && ((flag) >> 8) != (g)->MarkAttachClass)))
42
43 #define GSTRING_DELETE(gstring, from, len)                              \
44   do {                                                                  \
45     memmove (gstring->glyphs + from, gstring->glyphs + from + len,      \
46              sizeof (OTF_Glyph) * (gstring->used - from - len));        \
47     gstring->used -= len;                                               \
48   } while (0)
49
50
51 #define GSTRING_INSERT(gstring, pos, len)                               \
52   do {                                                                  \
53     if (gstring->used + len > gstring->size)                            \
54       {                                                                 \
55         char *errfmt = "GSTRING%s";                                     \
56                                                                         \
57         gstring->size = gstring->used + len;                            \
58         gstring->glyphs                                                 \
59           = (OTF_Glyph *) realloc (gstring->glyphs,                     \
60                                    sizeof (OTF_Glyph) * gstring->size); \
61         if (! gstring->glyphs)                                          \
62           OTF_ERROR (OTF_ERROR_MEMORY, "");                             \
63       }                                                                 \
64     memmove (gstring->glyphs + pos + len, gstring->glyphs + pos,        \
65              sizeof (OTF_Glyph) * (gstring->used - pos));               \
66     gstring->used += len;                                               \
67   } while (0)
68
69
70 static unsigned get_class_def (OTF_ClassDef *, OTF_GlyphID);
71
72 static int
73 gstring_subst (OTF *otf, OTF_GlyphString *gstring, int from, int to, int flag,
74                OTF_GlyphID *ids, int num)
75 {
76   int errret = -1;
77   int len = to - from;
78   int i;
79   int from_idx = gstring->glyphs[from].f.index.from;
80   int to_idx = gstring->glyphs[to - 1].f.index.to;
81   int non_ignored_idx;
82
83   for (i = non_ignored_idx = to - 1; i >= from; i--)
84     {
85       OTF_Glyph *g = gstring->glyphs + i;
86
87       if (IGNORED_GLYPH (g, flag) == 1)
88         {
89           /* Move this glyph to the next of the current target of
90              substitution.  */
91           OTF_Glyph temp = *g;
92
93           memmove (g, g + 1, sizeof (OTF_Glyph) * (non_ignored_idx - i));
94           temp.f.index.from = from_idx;
95           temp.f.index.to = to_idx;
96           gstring->glyphs[non_ignored_idx--] = temp;
97           len--;
98         }
99     }
100
101   if (len < num)
102     GSTRING_INSERT (gstring, from, (num - len));
103   else if (len > num)
104     GSTRING_DELETE (gstring, from, (len - num));
105   for (i = 0; i < num; i++)
106     {
107       if (gstring->glyphs[from + i].glyph_id != ids[i])
108         {
109           gstring->glyphs[from + i].c = 0;
110           if (otf->gdef)
111             gstring->glyphs[from + i].GlyphClass
112               = get_class_def (&otf->gdef->glyph_class_def, ids[i]);
113           else
114             gstring->glyphs[from + i].GlyphClass = 0;
115         }
116       gstring->glyphs[from + i].glyph_id = ids[i];
117       gstring->glyphs[from + i].positioning_type = 0;
118       gstring->glyphs[from + i].f.index.from = from_idx;
119       gstring->glyphs[from + i].f.index.to = to_idx;
120     }
121   return 0;
122 }
123
124 \f
125 static int
126 get_coverage_index (OTF_Coverage *coverage, OTF_GlyphID id)
127 {
128   int i;
129
130   if (coverage->CoverageFormat == 1)
131     {
132       for (i = 0; i < coverage->Count; i++)
133         if (coverage->table.GlyphArray[i] == id)
134           return i;
135     }
136   else
137     {
138       for (i = 0; i < coverage->Count; i++)
139         if (coverage->table.RangeRecord[i].Start <= id
140             && coverage->table.RangeRecord[i].End >= id)
141           return (coverage->table.RangeRecord[i].StartCoverageIndex
142                   + (id - coverage->table.RangeRecord[i].Start));
143     }
144   return -1;
145 }
146
147 static unsigned
148 get_class_def (OTF_ClassDef *class_def, OTF_GlyphID glyph_id)
149 {
150   if (class_def->ClassFormat == 1)
151     {
152       int idx = (int) glyph_id - (int) class_def->f.f1.StartGlyph;
153
154       if (idx >= 0 && idx < class_def->f.f1.GlyphCount)
155         return class_def->f.f1.ClassValueArray[idx];
156     }
157   else
158     {
159       int i;
160
161       for (i = 0; i < class_def->f.f2.ClassRangeCount; i++)
162         if (glyph_id >= class_def->f.f2.ClassRangeRecord[i].Start
163             && glyph_id <= class_def->f.f2.ClassRangeRecord[i].End)
164           return class_def->f.f2.ClassRangeRecord[i].Class;
165     }
166   return 0;
167 }
168
169 static OTF_LangSys *
170 get_langsys (OTF_ScriptList *script_list,
171              const char *script, const char *language)
172 {
173
174   OTF_Tag script_tag = OTF_tag (script);
175   OTF_Tag langsys_tag = OTF_tag (language);
176   int i, j;
177   OTF_Tag dflt_tag = OTF_tag ("DFLT");
178   OTF_Script *dflt = NULL;
179
180   for (i = 0; i < script_list->ScriptCount; i++)
181     {
182       OTF_Script *script = script_list->Script + i;
183
184       if (script_list->Script[i].ScriptTag == dflt_tag)
185         dflt = script;
186       if (script_list->Script[i].ScriptTag == script_tag)
187         {
188           if (! langsys_tag)
189             return &script->DefaultLangSys;
190           for (j = 0; j < script->LangSysCount; j++)
191             if (script->LangSysRecord[j].LangSysTag == langsys_tag)
192               return script->LangSys + j;
193           return &script->DefaultLangSys;
194         }
195     }
196
197   if (! dflt)
198     dflt = script_list->Script;
199   if (! langsys_tag)
200     return &dflt->DefaultLangSys;
201   for (j = 0; j < dflt->LangSysCount; j++)
202     if (dflt->LangSysRecord[j].LangSysTag == langsys_tag)
203       return dflt->LangSys + j;
204   return &dflt->DefaultLangSys;
205 }
206
207 static int
208 setup_lookup_flags (OTF_LookupList *LookupList, OTF_FeatureList *FeatureList,
209                     OTF_LangSys *LangSys,
210                     const char *features, char *lookup_flags)
211 {
212   int i, j, n = 0;
213   OTF_Feature *feature;
214   int *feature_table = alloca (sizeof (int) * FeatureList->FeatureCount);
215
216   if (! feature_table)
217     return -1;
218   for (i = 0; i < FeatureList->FeatureCount; i++)
219     feature_table[i] = 0;
220   memset (lookup_flags, 0, LookupList->LookupCount);
221
222   while (*features)
223     {
224       char tagname[4];
225       OTF_Tag tag;
226       int use_it = 1;
227
228       if (*features == '*')
229         {
230           /* Consume all remaining features.  */
231           for (i = 0; i < LangSys->FeatureCount; i++)
232             {
233               int index = LangSys->FeatureIndex[i];
234
235               if (! feature_table[index])
236                 {
237                   feature = FeatureList->Feature + index;
238                   for (j = 0; j < feature->LookupCount; j++)
239                     lookup_flags[feature->LookupListIndex[j]] = 1;
240                 }
241             }
242           break;
243         }
244
245       if (*features == '~')
246         use_it = -1, features++;
247       for (i = 0; *features && *features != ','; i++, features++)
248         tagname[i] = *features;
249       if (*features)
250         /* Skip ',' */
251         features++;
252       for (; i < 4; i++)
253         tagname[i] = '\0';
254       tag = OTF_tag (tagname);
255       for (i = 0; i < LangSys->FeatureCount; i++)
256         {
257           feature = FeatureList->Feature + LangSys->FeatureIndex[i];
258           if (tag == feature->FeatureTag)
259             {
260               if (feature_table[i])
261                 break;
262               if (use_it > 0)
263                 for (j = 0; j < feature->LookupCount; j++)
264                   lookup_flags[feature->LookupListIndex[j]] = 1;
265               feature_table[i] = use_it;
266               break;
267             }
268         }
269     }
270   return 0;
271 }
272
273 static int
274 match_ids (OTF_GlyphString *gstring, int gidx, int flag,
275            int count, OTF_GlyphID *ids, int direction)
276 {
277   OTF_Glyph *g = gstring->glyphs + gidx;
278   OTF_Glyph *gend = gstring->glyphs + (direction > 0 ? gstring->used : -1);
279   int i, j;
280
281   for (i = j = 0; i < count && g != gend; g += direction)
282     if (! IGNORED_GLYPH (g, flag)
283         && g->glyph_id != ids[i++])
284       return -1;
285   return (i < count ? -1 : j);
286 }
287
288 static int
289 match_chain_ids (OTF_GlyphString *gstring, int gidx, int flag,
290                  OTF_ChainRule *rule)
291 {
292   int i = rule->BacktrackGlyphCount;
293
294   if (i > 0
295       && (gidx < i
296           || match_ids (gstring, gidx - 1, flag, i, rule->Backtrack, -1) < 0))
297     return -1;
298   gidx++;
299   i = match_ids (gstring, gidx, flag,
300                  rule->InputGlyphCount - 1, rule->Input, 1);
301   if (i < 0)
302     return -1;
303   gidx += i;
304   i = match_ids (gstring, gidx, flag,
305                  rule->LookaheadGlyphCount, rule->LookAhead, 1);
306   if (i < 0)
307     return -1;
308   return 0;
309 }
310
311 static int
312 match_classes (OTF_ClassDef *class_def, OTF_GlyphString *gstring, int gidx,
313                int flag, int count, unsigned *classes, int direction)
314 {
315   OTF_Glyph *g = gstring->glyphs + gidx;
316   OTF_Glyph *gend = gstring->glyphs + (direction > 0 ? gstring->used : -1);
317   int i, j;
318
319   for (i = j = 0; i < count && g != gend; g += direction)
320     if (! IGNORED_GLYPH (g, flag)
321         && get_class_def (class_def, g->glyph_id) != classes[i++])
322       return -1;
323   return (i < count ? -1 : j);
324 }
325
326 static int
327 match_chain_classes (OTF_GlyphString *gstring, int gidx, int flag,
328                      OTF_ClassDef *BacktrackClassDef,
329                      OTF_ClassDef *InputClassDef,
330                      OTF_ClassDef *LookaheadClassDef,
331                      OTF_ChainClassRule *rule)
332 {
333   int i = rule->BacktrackGlyphCount;
334
335   if (i > 0
336       && (gidx < i
337           || match_classes (BacktrackClassDef, gstring, gidx - 1, flag, i,
338                             rule->Backtrack, -1) < 0))
339     return -1;
340   gidx++;
341   i = match_classes (InputClassDef, gstring, gidx, flag,
342                      rule->InputGlyphCount - 1, rule->Input, 1);
343   if (i < 0)
344     return -1;
345   gidx += i;
346   i = match_classes (LookaheadClassDef, gstring, gidx, flag,
347                      rule->LookaheadGlyphCount, rule->LookAhead, 1);
348   if (i < 0)
349     return -1;
350   return 0;
351 }
352
353
354 static int
355 match_coverages (OTF_GlyphString *gstring, int gidx, int flag, int count,
356                  OTF_Coverage *coverages, int direction)
357 {
358   OTF_Glyph *g = gstring->glyphs + gidx;
359   OTF_Glyph *gend = gstring->glyphs + (direction > 0 ? gstring->used : - 1);
360   int i, j;
361
362   for (i = j = 0; i < count && g != gend; g += direction, j++)
363     if (! IGNORED_GLYPH (g, flag)
364         && get_coverage_index (coverages + i++, g->glyph_id) < 0)
365       return -1;
366   return (i < count ? -1 : j);
367 }
368
369 static int
370 match_chain_coverages (OTF_GlyphString *gstring, int gidx, int flag,
371                        OTF_GSUB_ChainContext3 *context3)
372 {
373   int i = context3->BacktrackGlyphCount;
374
375   if (i > 0
376       && (gidx < i
377           || match_coverages (gstring, gidx - 1, flag, i,
378                               context3->Backtrack, -1) < 0))
379     return -1;
380   gidx++;
381   if (context3->InputGlyphCount > 1)
382     {
383       i = match_coverages (gstring, gidx, flag, context3->InputGlyphCount - 1,
384                            context3->Input + 1, 1);
385       if (i < 0)
386         return -1;
387       gidx += i;
388     }
389   if (match_coverages (gstring, gidx, flag, context3->LookaheadGlyphCount,
390                        context3->LookAhead, 1) < 0)
391     return -1;
392   return 0;
393 }
394
395 static int
396 lookup_gsub (OTF *otf, OTF_LookupList *lookup_list, unsigned lookup_list_index,
397              OTF_GlyphString *gstring, int gidx, int alternate_subst)
398 {
399   char *errfmt = "GSUB Looking up%s";
400   int errret = -1;
401   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
402   unsigned int flag = (lookup->LookupFlag
403                        & (OTF_LookupFlagIgnoreMask | OTF_MarkAttachmentType));
404   int orig_gidx = gidx;
405   OTF_Glyph *g = gstring->glyphs + gidx;
406   int i;
407
408   if (IGNORED_GLYPH (g, flag))
409     return (gidx + 1);
410
411   /* Try all subtables until one of them handles the current glyph.  */
412   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
413     {
414       unsigned lookup_type = lookup->LookupType;
415       OTF_LookupSubTableGSUB *subtable = lookup->SubTable.gsub + i;
416       int coverage_idx;
417
418       if (lookup_type == 7)
419         {
420           OTF_GSUB_Extension1 *extension1 = &subtable->u.extension1;
421
422           lookup_type = extension1->ExtensionLookupType;
423           subtable = extension1->ExtensionSubtable;
424         }
425
426       if (alternate_subst
427           ? (lookup_type != 3 && lookup_type != 5 && lookup_type != 6)
428           : (lookup_type == 3))
429         continue;
430
431       if (subtable->Coverage.offset)
432         {
433           coverage_idx = get_coverage_index (&subtable->Coverage,
434                                              g->glyph_id);
435           if (coverage_idx < 0)
436             continue;
437         }
438
439       switch (lookup_type)
440         {
441         case 1:
442           if (subtable->Format == 1)
443             g->glyph_id += subtable->u.single1.DeltaGlyphID;
444           else
445             g->glyph_id = subtable->u.single2.Substitute[coverage_idx];
446           gidx++;
447           break;
448
449         case 2:
450           if (subtable->Format == 1)
451             {
452               OTF_GSUB_Multiple1 *multiple1 = &subtable->u.multiple1;
453               OTF_Sequence *seq = multiple1->Sequence + coverage_idx;
454
455               gstring_subst (otf, gstring, gidx, gidx + 1, flag,
456                              seq->Substitute, seq->GlyphCount);
457               gidx += seq->GlyphCount;
458             }
459           else
460             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
461           break;
462
463         case 3:
464           if (subtable->Format == 1)
465             {
466               OTF_GSUB_Alternate1 *alt1 = &subtable->u.alternate1;
467               OTF_AlternateSet *altset = alt1->AlternateSet + coverage_idx;
468
469               gstring_subst (otf, gstring, gidx, gidx + 1, flag,
470                              altset->Alternate, altset->GlyphCount);
471               gidx += altset->GlyphCount;;
472             }
473           else
474             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
475           break;
476
477         case 4:
478           if (subtable->Format == 1)
479             {
480               OTF_GSUB_Ligature1 *lig1 = &subtable->u.ligature1;
481               OTF_LigatureSet *ligset = lig1->LigatureSet + coverage_idx;
482               OTF_Ligature *lig;
483               int j;
484
485               for (j = 0; j < ligset->LigatureCount; j++)
486                 {
487                   int n;
488
489                   lig = ligset->Ligature + j;
490                   n = match_ids (gstring, gidx + 1, flag,
491                                  lig->CompCount - 1, lig->Component, 1);
492                   if (n < 0)
493                     continue;
494                   gstring_subst (otf, gstring, gidx, gidx + 1 + n, flag,
495                                  &lig->LigGlyph, 1);
496                   gidx++;
497                   break;
498                 }
499             }
500           else
501             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
502           break;
503
504         case 5:
505           if (subtable->Format == 1)
506             {
507               OTF_GSUB_Context1 *context1 = &subtable->u.context1;
508               OTF_RuleSet *set = context1->RuleSet + coverage_idx;
509               OTF_Rule *rule;
510               int orig_used;
511               int j, k;
512
513               for (j = 0; j < set->RuleCount; j++)
514                 {
515                   rule = set->Rule + j;
516                   if (match_ids (gstring, gidx + 1, flag,
517                                  rule->GlyphCount - 1, rule->Input, 1) < 0)
518                     continue;
519                   orig_used = gstring->used;
520                   for (k = 0; k < rule->LookupCount; k++)
521                     lookup_gsub (otf, lookup_list,
522                                  rule->LookupRecord[k].LookupListIndex,
523                                  gstring,
524                                  gidx + rule->LookupRecord[k].SequenceIndex,
525                                  alternate_subst);
526                   gidx += rule->GlyphCount + (gstring->used - orig_used);
527                   break;
528                 }
529             }
530           else if (subtable->Format == 2)
531             {
532               OTF_GSUB_Context2 *context2 = &subtable->u.context2;
533               OTF_ClassSet *set;
534               OTF_ClassRule *rule;
535               unsigned class;
536               int orig_used;
537               int j, k;
538
539               class = get_class_def (&context2->ClassDef, g->glyph_id);
540               set = context2->ClassSet + class;
541               if (set)
542                 for (j = 0; j < set->ClassRuleCnt; j++)
543                   {
544                     rule = set->ClassRule + j;
545                     if (match_classes (&context2->ClassDef,
546                                        gstring, gidx + 1, flag,
547                                        rule->GlyphCount - 1, rule->Class, 1)
548                         < 0)
549                       continue;
550                     orig_used = gstring->used;
551                     for (k = 0; k < rule->LookupCount; k++)
552                       lookup_gsub (otf, lookup_list,
553                                    rule->LookupRecord[k].LookupListIndex,
554                                    gstring,
555                                    gidx + rule->LookupRecord[k].SequenceIndex,
556                                    alternate_subst);
557                     gidx += rule->GlyphCount + (gstring->used - orig_used);
558                     break;
559                   }
560             }
561           else                  /* subtable->Format == 3 */
562             {
563               OTF_GSUB_Context3 *context3 = &subtable->u.context3;
564               int orig_used;
565               int j;
566
567               if (match_coverages (gstring, gidx + 1, flag,
568                                    context3->GlyphCount - 1,
569                                    context3->Coverage + 1, 1) < 0)
570                 continue;
571               orig_used = gstring->used;
572               for (j = 0; j < context3->LookupCount; j++)
573                 lookup_gsub (otf, lookup_list,
574                              context3->LookupRecord[j].LookupListIndex,
575                              gstring,
576                              gidx + context3->LookupRecord[j].SequenceIndex,
577                              alternate_subst);
578               gidx += context3->GlyphCount + (gstring->used - orig_used);
579             }
580           break;
581
582         case 6:
583           if (subtable->Format == 1)
584             {
585               OTF_GSUB_ChainContext1 *context1 = &subtable->u.chain_context1;
586               OTF_ChainRuleSet *set = context1->ChainRuleSet + coverage_idx;
587               int orig_used;
588               int j, k;
589
590               for (j = 0; j < set->ChainRuleCount; j++)
591                 {
592                   OTF_ChainRule *rule = set->ChainRule + j;
593
594                   if (gidx < rule->BacktrackGlyphCount
595                       || (gidx + rule->InputGlyphCount
596                           + rule->LookaheadGlyphCount) > gstring->used)
597                     continue;
598                   if (match_chain_ids (gstring, gidx, flag, rule) < 0)
599                     continue;
600                   orig_used = gstring->used;
601                   for (k = 0; k < rule->LookupCount; k++)
602                     lookup_gsub (otf, lookup_list,
603                                  rule->LookupRecord[k].LookupListIndex,
604                                  gstring,
605                                  gidx + rule->LookupRecord[k].SequenceIndex,
606                                  alternate_subst);
607                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
608                   break;
609                 }
610             }
611           else if (subtable->Format == 2)
612             {
613               OTF_GSUB_ChainContext2 *context2 = &subtable->u.chain_context2;
614               OTF_ChainClassSet *set;
615               unsigned class;
616               int j;
617               int orig_used;
618
619               class = get_class_def (&context2->InputClassDef, g->glyph_id);
620               set = context2->ChainClassSet + class;
621               for (j = 0; j < set->ChainClassRuleCnt; j++)
622                 {
623                   OTF_ChainClassRule *rule = set->ChainClassRule + j;
624                   int k;
625
626                   if (gidx < rule->BacktrackGlyphCount
627                       || (gidx + rule->InputGlyphCount
628                           + rule->LookaheadGlyphCount) > gstring->used)
629                     continue;
630                   if (match_chain_classes (gstring, gidx, flag,
631                                            &context2->BacktrackClassDef,
632                                            &context2->InputClassDef,
633                                            &context2->LookaheadClassDef,
634                                            rule) < 0)
635                     continue;
636                   orig_used = gstring->used;
637                   for (k = 0; k < rule->LookupCount; k++)
638                     lookup_gsub (otf, lookup_list,
639                                  rule->LookupRecord[k].LookupListIndex,
640                                  gstring,
641                                  gidx + rule->LookupRecord[k].SequenceIndex,
642                                  alternate_subst);
643                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
644                   break;
645                 }
646             }
647           else
648             {
649               OTF_GSUB_ChainContext3 *context3 = &subtable->u.chain_context3;
650               int orig_used;
651               int j;
652
653               if (gidx < context3->BacktrackGlyphCount
654                   || (gidx + context3->InputGlyphCount
655                       + context3->LookaheadGlyphCount) > gstring->used)
656                 continue;
657               if (match_chain_coverages (gstring, gidx, flag, context3) < 0)
658                 continue;
659               orig_used = gstring->used;
660               for (j = 0; j < context3->LookupCount; j++)
661                 lookup_gsub (otf, lookup_list,
662                              context3->LookupRecord[j].LookupListIndex,
663                              gstring,
664                              gidx + context3->LookupRecord[j].SequenceIndex,
665                              alternate_subst);
666               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
667             }
668           break;
669
670         case 8:
671           {
672             OTF_GSUB_ReverseChain1 *reverse = &subtable->u.reverse_chain1;
673             int back_gidx = gidx + 1 + reverse->BacktrackGlyphCount;
674             int ahead_gidx = gidx - reverse->LookaheadGlyphCount;
675             int j;
676
677             if (back_gidx > gstring->used || ahead_gidx < 0)
678               break;
679
680             for (j = 0; j < reverse->BacktrackGlyphCount; j++)
681               if (get_coverage_index (reverse->Backtrack + j,
682                                       gstring->glyphs[gidx + 1 + j].glyph_id)
683                   < 0)
684                 break;
685             if (j < reverse->BacktrackGlyphCount)
686               continue;
687             for (j = 0; j < reverse->LookaheadGlyphCount; j++)
688               if (get_coverage_index (reverse->LookAhead + j,
689                                       gstring->glyphs[gidx - 1 - j].glyph_id)
690                   < 0)
691                 break;
692             if (j < reverse->LookaheadGlyphCount)
693               continue;
694             g->glyph_id = reverse->Substitute[coverage_idx];
695             gidx--;
696           }
697
698         default:
699           continue;
700         }
701     }
702   if (gidx == orig_gidx)
703     gidx++;
704   return gidx;
705 }
706
707 \f
708
709 /* GPOS */
710
711 static int
712 gstring_insert_for_gpos (OTF_GlyphString *gstring, int gidx)
713 {
714   int errret = -1;
715   int orig_gidx = gidx++;
716
717   while (gidx < gstring->used
718          && ! gstring->glyphs[gidx].glyph_id
719          && gstring->glyphs[gidx].positioning_type)
720     gidx++;
721   GSTRING_INSERT (gstring, gidx, 1);
722   gstring->glyphs[gidx] = gstring->glyphs[orig_gidx];
723   gstring->glyphs[gidx].glyph_id = 0;
724   return gidx;
725 }
726
727 static void
728 print_anchor (char *head, OTF_Anchor *anchor)
729 {
730   if (anchor->AnchorFormat == 1)
731     fprintf (stderr, " %s(X:%d Y:%d)", head,
732              anchor->XCoordinate, anchor->YCoordinate);
733   else if (anchor->AnchorFormat == 2)
734     fprintf (stderr, " %s(X:%d Y:%d AP:%d)", head,
735              anchor->XCoordinate, anchor->YCoordinate,
736              anchor->f.f1.AnchorPoint);
737   else
738     fprintf (stderr, " %s(X:%d Y:%d +alpha)", head,
739              anchor->XCoordinate, anchor->YCoordinate);
740 }
741
742 static void
743 print_glyph_positioning (OTF_Glyph *g, int type)
744 {
745   if (type)
746     fprintf (stderr, " %0X=", g->glyph_id);
747   switch (g->positioning_type)
748     {
749     case 1: case 2:
750       {
751         int format = g->f.f1.format;
752
753         if (format & OTF_XPlacement)
754           fprintf (stderr, "X:%d", g->f.f1.value->XPlacement);
755         if (format & OTF_XPlaDevice)
756           fprintf (stderr, "+alpha");
757         if (format & OTF_YPlacement)
758           fprintf (stderr, "Y:%d", g->f.f1.value->YPlacement);
759         if (format & OTF_YPlaDevice)
760           fprintf (stderr, "+alpha");
761         if (format & OTF_XAdvance)
762           fprintf (stderr, "X+:%d", g->f.f1.value->XAdvance);
763         if (format & OTF_XAdvDevice)
764           fprintf (stderr, "+alpha");
765         break;
766       }
767     case 3:
768       print_anchor ("entry", g->f.f3.entry_anchor);
769       print_anchor ("exit", g->f.f3.entry_anchor);
770       break;
771     case 4:
772       print_anchor ("mark", g->f.f4.mark_anchor);
773       print_anchor ("base", g->f.f4.base_anchor);
774       break;
775     case 5:
776       print_anchor ("mark", g->f.f5.mark_anchor);
777       print_anchor ("lig", g->f.f5.ligature_anchor);
778       break;
779     case 6:
780       print_anchor ("mark1", g->f.f6.mark1_anchor);
781       print_anchor ("mark2", g->f.f6.mark2_anchor);
782       break;
783     }
784 }
785
786 static int
787 lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
788              OTF_GlyphString *gstring, int gidx, int accumulate)
789 {
790   char *errfmt = "GPOS Looking up%s";
791   int errret = -1;
792   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
793   unsigned int flag = (lookup->LookupFlag
794                        & (OTF_LookupFlagIgnoreMask | OTF_MarkAttachmentType));
795   int orig_gidx = gidx;
796   OTF_Glyph *g = gstring->glyphs + gidx;
797   int i;
798
799   if (debug_flag)
800     fprintf (stderr, "[GPOS] glyph:%04X lookup:%02d",
801              g->glyph_id, lookup_list_index);
802   if (IGNORED_GLYPH (g, flag))
803     {
804       if (debug_flag)
805         fprintf (stderr, " glyph ignored\n");
806       return (gidx + 1);
807     }
808
809   /* Try all subtables until one of them handles the current glyph.  */
810   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
811     {
812       unsigned lookup_type = lookup->LookupType;
813       OTF_LookupSubTableGPOS *subtable = lookup->SubTable.gpos + i;
814       int coverage_idx;
815       int positioning_type;
816       enum OTF_ValueFormat format;
817       OTF_ValueRecord *value;
818       OTF_Anchor *anchor1, *anchor2;
819
820       if (lookup_type == 9)
821         {
822           OTF_GPOS_Extension1 *extension1 = &subtable->u.extension1;
823
824           lookup_type = extension1->ExtensionLookupType;
825           subtable = extension1->ExtensionSubtable;
826         }
827
828       if (debug_flag)
829         fprintf (stderr, "/%d", lookup_type);
830       if (subtable->Coverage.offset)
831         {
832           coverage_idx = get_coverage_index (&subtable->Coverage,
833                                              g->glyph_id);
834           if (coverage_idx < 0)
835             continue;
836         }
837
838       switch (lookup_type)
839         {
840         case 1:
841           positioning_type = lookup_type;
842           if (subtable->Format == 1)
843             {
844               OTF_GPOS_Single1 *single1 = &subtable->u.single1;
845
846               format = single1->ValueFormat;
847               value = &single1->Value;
848             }
849           else if (subtable->Format == 2)
850             {
851               OTF_GPOS_Single2 *single2 = &subtable->u.single2;
852
853               format = single2->ValueFormat;
854               value = single2->Value + coverage_idx;
855             }
856           if (accumulate && g->positioning_type)
857             {
858               gidx = gstring_insert_for_gpos (gstring, gidx);
859               g = gstring->glyphs + gidx;
860             }
861           g->positioning_type = positioning_type;
862           g->f.f1.format = format;
863           g->f.f1.value = value;
864           if (debug_flag)
865             print_glyph_positioning (g, 0);
866           gidx++;
867           break;
868
869         case 2:
870           {
871             int next_gidx;
872             OTF_Glyph *nextg;
873
874             for (next_gidx = gidx + 1, nextg = gstring->glyphs + next_gidx;
875                  next_gidx < gstring->used && IGNORED_GLYPH (nextg, flag);
876                  next_gidx++, nextg++);
877
878             if (next_gidx >= gstring->used)
879               continue;
880             if (subtable->Format == 1)
881               {
882                 OTF_GPOS_Pair1 *pair1 = &subtable->u.pair1;
883                 OTF_PairSet *set = pair1->PairSet + coverage_idx;
884                 int j;
885
886                 for (j = 0; j < set->PairValueCount; j++)
887                   if (set->PairValueRecord[j].SecondGlyph == nextg->glyph_id)
888                     {
889                       if (pair1->ValueFormat1)
890                         {
891                           if (accumulate && g->positioning_type)
892                             {
893                               gidx = gstring_insert_for_gpos (gstring, gidx);
894                               g = gstring->glyphs + gidx;
895                               next_gidx += gidx - orig_gidx;
896                               nextg = gstring->glyphs + next_gidx;
897                             }
898                           g->positioning_type = lookup_type;
899                           g->f.f2.format = pair1->ValueFormat1;
900                           g->f.f2.value = &set->PairValueRecord[j].Value1;
901                           if (debug_flag)
902                             print_glyph_positioning (g, 1);
903                         }
904                       gidx = next_gidx;
905                       g = nextg;
906                       if (pair1->ValueFormat2)
907                         {
908                           if (accumulate && g->positioning_type)
909                             {
910                               gidx = gstring_insert_for_gpos (gstring, gidx);
911                               g = gstring->glyphs + gidx;
912                             }
913                           g->positioning_type = lookup_type;
914                           g->f.f2.format = pair1->ValueFormat2;
915                           g->f.f2.value = &set->PairValueRecord[j].Value2;
916                           if (debug_flag)
917                             print_glyph_positioning (g, 2);
918                         }
919                       break;
920                     }
921               }
922             else if (subtable->Format == 2)
923               {
924                 OTF_GPOS_Pair2 *pair2 = &subtable->u.pair2;
925                 unsigned class1, class2;
926
927                 class1 = get_class_def (&pair2->ClassDef1, g->glyph_id);
928                 class2 = get_class_def (&pair2->ClassDef2, nextg->glyph_id);
929                 if (pair2->ValueFormat1)
930                   {
931                     if (accumulate && g->positioning_type)
932                       {
933                         gidx = gstring_insert_for_gpos (gstring, gidx);
934                         g = gstring->glyphs + gidx;
935                         next_gidx += gidx - orig_gidx;
936                         nextg = gstring->glyphs + next_gidx;
937                       }
938                     g->positioning_type = lookup_type;
939                     g->f.f2.format = pair2->ValueFormat1;
940                     g->f.f2.value
941                       = &pair2->Class1Record[class1].Class2Record[class2].Value1;
942                     if (debug_flag)
943                       print_glyph_positioning (g, 1);
944                   }
945                 gidx = next_gidx;
946                 g = nextg;
947                 if (pair2->ValueFormat2)
948                   {
949                     if (accumulate && g->positioning_type)
950                       {
951                         gidx = gstring_insert_for_gpos (gstring, gidx);
952                         g = gstring->glyphs + gidx;
953                       }
954                     g->positioning_type = lookup_type;
955                     g->f.f2.format = pair2->ValueFormat2;
956                     g->f.f2.value
957                       = &pair2->Class1Record[class1].Class2Record[class2].Value2;
958                     if (debug_flag)
959                       print_glyph_positioning (g, 2);
960                   }
961               }
962           }
963           break;
964
965         case 3:
966           {
967             OTF_GPOS_Cursive1 *cursive1 = &subtable->u.cursive1;
968
969             g->positioning_type = lookup_type;
970             g->f.f3.entry_anchor
971               = &cursive1->EntryExitRecord[coverage_idx].EntryAnchor;
972             g->f.f3.exit_anchor
973               = &cursive1->EntryExitRecord[coverage_idx].ExitAnchor;
974             if (debug_flag)
975               print_glyph_positioning (g, 0);
976             gidx++;
977           }
978           break;
979
980         case 4:
981           if (gidx < 1)
982             continue;
983           if (subtable->Format == 1)
984             {
985               OTF_GPOS_MarkBase1 *mark_base1 = &subtable->u.mark_base1;
986               OTF_MarkRecord *mark_record;
987               OTF_AnchorRecord *base_record;
988               OTF_Glyph *baseg;
989               int coverage_idx_base;
990               unsigned int this_flag = flag | OTF_IgnoreMarks;
991
992               for (baseg = g - 1;
993                    baseg >= gstring->glyphs && IGNORED_GLYPH (baseg, this_flag);
994                    baseg--);
995               if (baseg < gstring->glyphs)
996                 continue;
997               coverage_idx_base
998                 = get_coverage_index (&mark_base1->BaseCoverage,
999                                       baseg->glyph_id);
1000               if (coverage_idx_base < 0)
1001                 continue;
1002               mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx;
1003               base_record
1004                 = mark_base1->BaseArray.AnchorRecord + coverage_idx_base;
1005               g->f.f4.mark_anchor = &mark_record->MarkAnchor;
1006               g->f.f4.base_anchor
1007                 = &base_record->Anchor[mark_record->Class];
1008               g->positioning_type = lookup_type;
1009               if (debug_flag)
1010                 print_glyph_positioning (g, 0);
1011               gidx++;
1012             }
1013           break;
1014
1015         case 5:
1016           if (gidx < 1)
1017             continue;
1018           if (subtable->Format == 1)
1019             {
1020               OTF_GPOS_MarkLig1 *mark_lig1 = &subtable->u.mark_lig1;
1021               OTF_Glyph *ligg;
1022               int coverage_idx_lig;
1023               OTF_MarkRecord *mark_record;
1024               OTF_LigatureAttach *attach;
1025               int *num_class = alloca (sizeof (int) * mark_lig1->ClassCount);
1026               int j;
1027
1028               for (j = 0; j < mark_lig1->ClassCount; j++)
1029                 num_class[j] = 0;
1030
1031               for (ligg = g - 1;
1032                    (ligg >= gstring->glyphs
1033                     && (IGNORED_GLYPH (ligg, flag)
1034                         || ligg->GlyphClass > OTF_GlyphClassLigature));
1035                    ligg--)
1036                 if (ligg->positioning_type == 5
1037                     && ligg->MarkAttachClass < mark_lig1->ClassCount)
1038                   num_class[ligg->MarkAttachClass]++;
1039               if (ligg < gstring->glyphs)
1040                 continue;
1041               coverage_idx_lig
1042                 = get_coverage_index (&mark_lig1->LigatureCoverage,
1043                                       ligg->glyph_id);
1044               if (coverage_idx_lig < 0)
1045                 continue;
1046               mark_record = mark_lig1->MarkArray.MarkRecord + coverage_idx;
1047               g->MarkAttachClass = mark_record->Class;
1048               attach = (mark_lig1->LigatureArray.LigatureAttach
1049                         + coverage_idx_lig);
1050               for (j = 0; j < attach->ComponentCount; j++)
1051                 {
1052                   OTF_Anchor *lig_anchor
1053                     = attach->ComponentRecord[j].LigatureAnchor;
1054
1055                   if (lig_anchor[mark_record->Class].AnchorFormat
1056                       && num_class[mark_record->Class]-- == 0)
1057                     {
1058                       g->positioning_type = lookup_type;
1059                       g->f.f5.mark_anchor = &mark_record->MarkAnchor;
1060                       g->f.f5.ligature_anchor = lig_anchor + mark_record->Class;
1061                       if (debug_flag)
1062                         print_glyph_positioning (g, 0);
1063                       gidx++;
1064                       break;
1065                     }
1066                 }
1067             }
1068           break;
1069
1070         case 6:
1071           if (gidx < 1)
1072             continue;
1073           if (subtable->Format == 1)
1074             {
1075               OTF_GPOS_MarkMark1 *mark_mark1 = &subtable->u.mark_mark1;
1076               OTF_MarkRecord *mark1_record;
1077               OTF_AnchorRecord *mark2_record;
1078               OTF_Glyph *prevg;
1079               int coverage_idx_base;
1080
1081               for (prevg = g - 1;
1082                    prevg >= gstring->glyphs && IGNORED_GLYPH (prevg, flag);
1083                    prevg--);
1084               if (prevg < gstring->glyphs)
1085                 continue;
1086               coverage_idx_base
1087                 = get_coverage_index (&mark_mark1->Mark2Coverage,
1088                                       prevg->glyph_id);
1089               if (coverage_idx_base < 0)
1090                 continue;
1091               mark1_record = mark_mark1->Mark1Array.MarkRecord + coverage_idx;
1092               mark2_record
1093                 = mark_mark1->Mark2Array.AnchorRecord + coverage_idx_base;
1094               g->f.f6.mark1_anchor = &mark1_record->MarkAnchor;
1095               g->f.f6.mark2_anchor
1096                 = &mark2_record->Anchor[mark1_record->Class];
1097               g->positioning_type = lookup_type;
1098               if (debug_flag)
1099                 print_glyph_positioning (g, 0);
1100               gidx++;
1101               break;
1102             }
1103           break;
1104
1105         case 7:
1106           if (subtable->Format == 1)
1107             {
1108               OTF_GPOS_Context1 *context1 = &subtable->u.context1;
1109               OTF_RuleSet *set = context1->RuleSet + coverage_idx;
1110               OTF_Rule *rule;
1111               int orig_used;
1112               int j, k;
1113
1114               for (j = 0; j < set->RuleCount; j++)
1115                 {
1116                   rule = set->Rule + j;
1117                   if (match_ids (gstring, gidx + 1, flag,
1118                                  rule->GlyphCount - 1, rule->Input, 1) < 0)
1119                     continue;
1120                   orig_used = gstring->used;
1121                   for (k = 0; k < rule->LookupCount; k++)
1122                     lookup_gpos (lookup_list,
1123                                  rule->LookupRecord[k].LookupListIndex,
1124                                  gstring,
1125                                  gidx + rule->LookupRecord[k].SequenceIndex,
1126                                  accumulate);
1127                   gidx += rule->GlyphCount + (gstring->used - orig_used);
1128                   break;
1129                 }
1130             }
1131           else if (subtable->Format == 2)
1132             {
1133               OTF_GPOS_Context2 *context2 = &subtable->u.context2;
1134               OTF_ClassSet *set;
1135               OTF_ClassRule *rule;
1136               unsigned class;
1137               int orig_used;
1138               int j, k;
1139
1140               class = get_class_def (&context2->ClassDef, g->glyph_id);
1141               set = context2->ClassSet + class;
1142               if (set)
1143                 for (j = 0; j < set->ClassRuleCnt; j++)
1144                   {
1145                     rule = set->ClassRule + j;
1146                     if (match_classes (&context2->ClassDef,
1147                                        gstring, gidx + 1, flag,
1148                                        rule->GlyphCount - 1, rule->Class, 1)
1149                         < 0)
1150                       continue;
1151                     orig_used = gstring->used;
1152                     for (k = 0; k < rule->LookupCount; k++)
1153                       lookup_gpos (lookup_list,
1154                                    rule->LookupRecord[k].LookupListIndex,
1155                                    gstring,
1156                                    gidx + rule->LookupRecord[k].SequenceIndex,
1157                                    accumulate);
1158                     gidx += rule->GlyphCount + (gstring->used - orig_used);
1159                     break;
1160                   }
1161             }
1162           else                  /* subtable->Format == 3 */
1163             {
1164               OTF_GPOS_Context3 *context3 = &subtable->u.context3;
1165               int orig_used;
1166               int j;
1167
1168               if (match_coverages (gstring, gidx + 1, flag,
1169                                    context3->GlyphCount - 1,
1170                                    context3->Coverage + 1, 1) < 0)
1171                 continue;
1172               orig_used = gstring->used;
1173               for (j = 0; j < context3->LookupCount; j++)
1174                 lookup_gpos (lookup_list,
1175                              context3->LookupRecord[j].LookupListIndex,
1176                              gstring,
1177                              gidx + context3->LookupRecord[j].SequenceIndex,
1178                              accumulate);
1179               gidx += context3->GlyphCount + (gstring->used - orig_used);
1180             }
1181           break;
1182
1183         case 8:
1184           if (subtable->Format == 1)
1185             {
1186               OTF_GPOS_ChainContext1 *context1 = &subtable->u.chain_context1;
1187               OTF_ChainRuleSet *set = context1->ChainRuleSet + coverage_idx;
1188               int orig_used;
1189               int j, k;
1190
1191               for (j = 0; j < set->ChainRuleCount; j++)
1192                 {
1193                   OTF_ChainRule *rule = set->ChainRule + j;
1194
1195                   if (gidx < rule->BacktrackGlyphCount
1196                       || (gidx + rule->InputGlyphCount
1197                           + rule->LookaheadGlyphCount) > gstring->used)
1198                     continue;
1199                   if (match_chain_ids (gstring, gidx, flag, rule) < 0)
1200                     continue;
1201                   orig_used = gstring->used;
1202                   for (k = 0; k < rule->LookupCount; k++)
1203                     lookup_gpos (lookup_list,
1204                                  rule->LookupRecord[k].LookupListIndex,
1205                                  gstring,
1206                                  gidx + rule->LookupRecord[k].SequenceIndex,
1207                                  accumulate);
1208                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
1209                   break;
1210                 }
1211             }
1212           else if (subtable->Format == 2)
1213             {
1214               OTF_GPOS_ChainContext2 *context2 = &subtable->u.chain_context2;
1215               OTF_ChainClassSet *set;
1216               unsigned class;
1217               int j;
1218               int orig_used;
1219
1220               class = get_class_def (&context2->InputClassDef, g->glyph_id);
1221               set = context2->ChainClassSet + class;
1222               for (j = 0; j < set->ChainClassRuleCnt; j++)
1223                 {
1224                   OTF_ChainClassRule *rule = set->ChainClassRule + j;
1225                   int k;
1226
1227                   if (gidx < rule->BacktrackGlyphCount
1228                       || (gidx + rule->InputGlyphCount
1229                           + rule->LookaheadGlyphCount) > gstring->used)
1230                     continue;
1231                   if (match_chain_classes (gstring, gidx, flag,
1232                                            &context2->BacktrackClassDef,
1233                                            &context2->InputClassDef,
1234                                            &context2->LookaheadClassDef,
1235                                            rule) < 0)
1236                     continue;
1237                   orig_used = gstring->used;
1238                   for (k = 0; k < rule->LookupCount; k++)
1239                     lookup_gpos (lookup_list,
1240                                  rule->LookupRecord[k].LookupListIndex,
1241                                  gstring,
1242                                  gidx + rule->LookupRecord[k].SequenceIndex,
1243                                  accumulate);
1244                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
1245                   break;
1246                 }
1247             }
1248           else if (subtable->Format == 3)
1249             {
1250               OTF_GPOS_ChainContext3 *context3 = &subtable->u.chain_context3;
1251               int orig_used;
1252               int j;
1253
1254               if (gidx < context3->BacktrackGlyphCount
1255                   || (gidx + context3->InputGlyphCount
1256                       + context3->LookaheadGlyphCount) > gstring->used)
1257                 continue;
1258               if (match_chain_coverages (gstring, gidx, flag, context3) < 0)
1259                 continue;
1260               orig_used = gstring->used;
1261               for (j = 0; j < context3->LookupCount; j++)
1262                 lookup_gpos (lookup_list,
1263                              context3->LookupRecord[j].LookupListIndex,
1264                              gstring,
1265                              gidx + context3->LookupRecord[j].SequenceIndex,
1266                              accumulate);
1267               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
1268             }
1269           else
1270             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (invalid subformat)");
1271           break;
1272
1273         default:
1274           continue;
1275         }
1276     }
1277   if (gidx == orig_gidx)
1278     {
1279       if (debug_flag)
1280         fprintf (stderr, " no match\n");
1281       gidx++;
1282     }
1283   else if (debug_flag)
1284     fprintf (stderr, "\n");
1285   return gidx;
1286 }
1287
1288 static unsigned
1289 lookup_encoding_0 (int c, OTF_EncodingSubtable *sub)
1290 {
1291   return ((c < 0 || c >= 256)
1292           ? 0
1293           : sub->f.f0->glyphIdArray[c]);
1294 }
1295
1296 static unsigned
1297 lookup_encoding_2 (int c, OTF_EncodingSubtable *sub)
1298 {
1299   return 0;
1300 }
1301
1302 static unsigned
1303 lookup_encoding_4 (int c, OTF_EncodingSubtable *sub)
1304 {
1305   int segCount, i;
1306   OTF_EncodingSubtable4 *sub4;
1307
1308   if (c < 0)
1309     return 0;
1310   sub4 = sub->f.f4;
1311   segCount = sub4->segCountX2 / 2;
1312   for (i = 0; i < segCount; i++)
1313     {
1314       OTF_cmapSegment *seg = sub4->segments + i;
1315
1316       if (c >= seg->startCount && c <= seg->endCount)
1317         {
1318           if (seg->idRangeOffset == 0xFFFF)
1319             return c + seg->idDelta;
1320           else
1321             return sub4->glyphIdArray[seg->idRangeOffset
1322                                       + (c - seg->startCount)];
1323         }
1324     }
1325   return 0;
1326 }
1327
1328 static unsigned
1329 lookup_encoding_6 (int c, OTF_EncodingSubtable *sub)
1330 {
1331   return 0;
1332 }
1333
1334 static unsigned
1335 lookup_encoding_8 (int c, OTF_EncodingSubtable *sub)
1336 {
1337   return 0;
1338 }
1339
1340 static unsigned
1341 lookup_encoding_10 (int c, OTF_EncodingSubtable *sub)
1342 {
1343   return 0;
1344 }
1345
1346 static unsigned
1347 lookup_encoding_12 (int c, OTF_EncodingSubtable *sub)
1348 {
1349   OTF_EncodingSubtable12 *sub12;
1350   OTF_cmapGroup *g, *gend;
1351
1352   if (c < 0)
1353     return 0;
1354   sub12 = sub->f.f12;
1355   g = sub12->Groups;
1356   gend = sub12->Groups + sub12->nGroups;
1357   while (g < gend)
1358     {
1359       if (g->startCharCode <= c && c <= g->endCharCode)
1360         return (g->startGlyphID + (c - g->startCharCode));
1361       g++;
1362     }
1363   return 0;
1364 }
1365
1366 typedef unsigned (*lookup_cmap_func) (int, OTF_EncodingSubtable *);
1367
1368 static lookup_cmap_func lookup_cmap_func_table[] =
1369   {
1370     lookup_encoding_0, lookup_encoding_2, lookup_encoding_4, lookup_encoding_6,
1371     lookup_encoding_8, lookup_encoding_10, lookup_encoding_12
1372   };
1373
1374 static unsigned
1375 get_GlyphID (OTF_cmap *cmap, int c)
1376 {
1377   OTF_EncodingSubtable *sub;
1378   lookup_cmap_func lookupper;
1379
1380   if (c < 0x10000 && cmap->unicode_table)
1381     return cmap->unicode_table[c];
1382   if (cmap->table_index < 0)
1383     return 0;
1384   sub = &cmap->EncodingRecord[cmap->table_index].subtable;
1385   lookupper = lookup_cmap_func_table[sub->format / 2];
1386   return lookupper (c, sub);
1387 }
1388
1389 static OTF_GlyphID
1390 get_uvs_glyph (OTF_cmap *cmap, OTF_EncodingSubtable14 *sub14, int c1, int c2)
1391 {
1392   unsigned nRecords = sub14->nRecords;
1393   OTF_VariationSelectorRecord *record;
1394   unsigned i;
1395
1396   for (i = 0; i < nRecords; i++)
1397     {
1398       record = &sub14->Records[i];
1399       if (record->varSelector == c2)
1400         {
1401           if (record->defaultUVSOffset)
1402             {
1403               OTF_UnicodeValueRange *uVRs = record->unicodeValueRanges;
1404               unsigned numUVRs = record->numUnicodeValueRanges;
1405               unsigned top = numUVRs, bottom = 0, middle;
1406
1407               if (uVRs[0].startUnicodeValue <= c1)
1408                 {
1409                   unsigned additionalCount, startUnicodeValue;
1410
1411                   for (;;)
1412                     {
1413                       middle = (top + bottom) / 2;
1414                       if (c1 < uVRs[middle].startUnicodeValue)
1415                         top = middle;
1416                       else if (bottom == middle)
1417                         break;
1418                       else
1419                         bottom = middle;
1420                     }
1421                   startUnicodeValue = uVRs[bottom].startUnicodeValue;
1422                   additionalCount = uVRs[bottom].additionalCount;
1423                   if (c1 <= startUnicodeValue + additionalCount)
1424                     return get_GlyphID (cmap, c1);
1425                 }
1426             }
1427           if (record->nonDefaultUVSOffset)
1428             {
1429               OTF_UVSMapping *uvsMappings = record->uvsMappings;
1430               unsigned numUVSMs = record->numUVSMappings;
1431               unsigned top = numUVSMs, bottom = 0, middle;
1432
1433               if (uvsMappings[0].unicodeValue <= c1)
1434                 {
1435                   for (;;)
1436                     {
1437                       middle = (top + bottom) / 2;
1438                       if (c1 < uvsMappings[middle].unicodeValue)
1439                         top = middle;
1440                       else if (bottom == middle)
1441                         break;
1442                       else
1443                         bottom = middle;
1444                     }
1445                   if (uvsMappings[bottom].unicodeValue == c1)
1446                     return uvsMappings[bottom].glyphID;
1447                 }
1448             }
1449           return 0;
1450         }
1451     }
1452   return 0;
1453 }
1454
1455 static void
1456 check_cmap_uvs (OTF_cmap *cmap, OTF_GlyphString *gstring, int idx)
1457 {
1458   OTF_EncodingSubtable14 *sub14;
1459   int c1 = gstring->glyphs[idx - 1].c;
1460   int c2 = gstring->glyphs[idx].c;
1461   OTF_GlyphID code;
1462   int i;
1463
1464   gstring->glyphs[idx].glyph_id = 0;
1465   for (i = 0; i < cmap->numTables; i++)
1466     if (cmap->EncodingRecord[i].subtable.format == 14)
1467       break;
1468   if (i == cmap->numTables)
1469     return;
1470   code = get_uvs_glyph (cmap, cmap->EncodingRecord[i].subtable.f.f14, c1, c2);
1471   if (code == 0)
1472     return;
1473   gstring->glyphs[idx - 1].glyph_id = code;
1474   gstring->glyphs[idx - 1].f.index.to = gstring->glyphs[idx].f.index.to;
1475   gstring->used--;
1476   memmove (gstring->glyphs + idx, gstring->glyphs + idx + 1,
1477            sizeof (OTF_Glyph) * (gstring->used - idx));
1478 }
1479
1480 \f
1481
1482 /* GDEF */
1483 /* Table of GlyphClass and MarkAttackClass.
1484
1485    For the Nth element CHAR, CHAR and the succeeding characters
1486    (before CHAR of the next element) has GlyphClass C (= (N % 2) ? 3 : 1).
1487
1488    This table is generated from the General Category (GC) property of
1489    characters defined in the Unicode Character Database.  */
1490
1491 static int glyph_class_table[] =
1492   { 0x00000, 0x00300, 0x00370, 0x00483, 0x00487, 0x00488, 0x0048A, 0x00591,
1493     0x005BE, 0x005BF, 0x005C0, 0x005C1, 0x005C3, 0x005C4, 0x005C6, 0x005C7,
1494     0x005C8, 0x00610, 0x00616, 0x0064B, 0x0065F, 0x00670, 0x00671, 0x006D6,
1495     0x006DD, 0x006DE, 0x006E5, 0x006E7, 0x006E9, 0x006EA, 0x006EE, 0x00711,
1496     0x00712, 0x00730, 0x0074B, 0x007A6, 0x007B1, 0x007EB, 0x007F4, 0x00901,
1497     0x00904, 0x0093C, 0x0093D, 0x0093E, 0x0094E, 0x00951, 0x00955, 0x00962,
1498     0x00964, 0x00981, 0x00984, 0x009BC, 0x009BD, 0x009BE, 0x009C5, 0x009C7,
1499     0x009CE, 0x009D7, 0x009D8, 0x009E2, 0x009E4, 0x00A01, 0x00A04, 0x00A3C,
1500     0x00A3D, 0x00A3E, 0x00A4E, 0x00A70, 0x00A72, 0x00A81, 0x00A84, 0x00ABC,
1501     0x00ABD, 0x00ABE, 0x00ACE, 0x00AE2, 0x00AE4, 0x00B01, 0x00B04, 0x00B3C,
1502     0x00B3D, 0x00B3E, 0x00B44, 0x00B47, 0x00B58, 0x00B82, 0x00B83, 0x00BBE,
1503     0x00BCE, 0x00BD7, 0x00BD8, 0x00C01, 0x00C04, 0x00C3E, 0x00C45, 0x00C46,
1504     0x00C57, 0x00C82, 0x00C84, 0x00CBC, 0x00CBD, 0x00CBE, 0x00CC5, 0x00CC6,
1505     0x00CCE, 0x00CD5, 0x00CD7, 0x00CE2, 0x00CE4, 0x00D02, 0x00D04, 0x00D3E,
1506     0x00D44, 0x00D46, 0x00D4E, 0x00D57, 0x00D58, 0x00D82, 0x00D84, 0x00DCA,
1507     0x00DCB, 0x00DCF, 0x00DD7, 0x00DD8, 0x00DF4, 0x00E31, 0x00E32, 0x00E34,
1508     0x00E3B, 0x00E47, 0x00E4F, 0x00EB1, 0x00EB2, 0x00EB4, 0x00EBD, 0x00EC8,
1509     0x00ECE, 0x00F18, 0x00F1A, 0x00F35, 0x00F36, 0x00F37, 0x00F38, 0x00F39,
1510     0x00F3A, 0x00F3E, 0x00F40, 0x00F71, 0x00F85, 0x00F86, 0x00F88, 0x00F90,
1511     0x00FBD, 0x00FC6, 0x00FC7, 0x0102C, 0x0103A, 0x01056, 0x0105A, 0x0135F,
1512     0x01360, 0x01712, 0x01715, 0x01732, 0x01735, 0x01752, 0x01754, 0x01772,
1513     0x01774, 0x017B6, 0x017D4, 0x017DD, 0x017DE, 0x0180B, 0x0180E, 0x018A9,
1514     0x018AA, 0x01920, 0x0193C, 0x019B0, 0x019C1, 0x019C8, 0x019CA, 0x01A17,
1515     0x01A1C, 0x01B00, 0x01B05, 0x01B34, 0x01B45, 0x01B6B, 0x01B74, 0x01DC0,
1516     0x01E00, 0x020D0, 0x020F0, 0x0302A, 0x03030, 0x03099, 0x0309B, 0x0A802,
1517     0x0A803, 0x0A806, 0x0A807, 0x0A80B, 0x0A80C, 0x0A823, 0x0A828, 0x0FB1E,
1518     0x0FB1F, 0x0FE00, 0x0FE10, 0x0FE20, 0x0FE24, 0x10A01, 0x10A10, 0x10A38,
1519     0x10A40, 0x1D165, 0x1D16A, 0x1D16D, 0x1D173, 0x1D17B, 0x1D183, 0x1D185,
1520     0x1D18C, 0x1D1AA, 0x1D1AE, 0x1D242, 0x1D245, 0xE0100, 0xE01F0 };
1521
1522 static int get_class_def_auto (int c)
1523 {
1524   static int table_size
1525     = sizeof glyph_class_table / sizeof glyph_class_table[0];
1526   int low, high, mid;
1527
1528   if (c >= glyph_class_table[table_size - 1])
1529     return 0;
1530   low = 0;
1531   high = table_size - 1;
1532   while (1)
1533     {
1534       mid = (low + high) / 2;
1535       if (c < glyph_class_table[mid])
1536         high = mid - 1;
1537       else if (c >= glyph_class_table[mid + 1])
1538         low = mid + 1;
1539       else
1540         break;
1541     }
1542   return ((mid % 2) ? 3 : 1);
1543 }
1544
1545 \f
1546
1547 /* API */
1548
1549 #define UVS_P(C)        \
1550   (((C) >= 0xFE00 && (C) <= 0xFE0F) || ((C) >= 0xE0100 && (C) <= 0xE01EF))
1551
1552 int
1553 OTF_drive_cmap (OTF *otf, OTF_GlyphString *gstring)
1554 {
1555   OTF_cmap *cmap;
1556   int i;
1557   OTF_EncodingSubtable *sub;
1558   lookup_cmap_func lookupper;
1559
1560   if (! otf->cmap
1561       && OTF_get_table (otf, "cmap") < 0)
1562     return -1;
1563
1564   cmap = otf->cmap;
1565   if (cmap->table_index < 0)
1566     lookupper = NULL;
1567   else
1568     {
1569       sub = &cmap->EncodingRecord[cmap->table_index].subtable;
1570       lookupper = lookup_cmap_func_table[sub->format / 2];
1571     }
1572   for (i = 0; i < gstring->used; i++)
1573     if (! gstring->glyphs[i].glyph_id)
1574       {
1575         int c = gstring->glyphs[i].c;
1576         if (c < 32 || ! cmap->unicode_table)
1577           gstring->glyphs[i].glyph_id = 0;
1578         else if (UVS_P (c) && i > 0)
1579           check_cmap_uvs (cmap, gstring, i);
1580         else if (c < 0x10000)
1581           gstring->glyphs[i].glyph_id = cmap->unicode_table[c];
1582         else if (lookupper)
1583           gstring->glyphs[i].glyph_id = lookupper (c, sub);
1584       }
1585   return 0;
1586 }
1587
1588
1589 int
1590 OTF_drive_cmap2 (OTF *otf, OTF_GlyphString *gstring,
1591                  int platform_id, int encoding_id)
1592 {
1593   OTF_cmap *cmap;
1594   int i;
1595   char *errfmt = "CMAP Looking up%s";
1596   int errret = -1;
1597   OTF_EncodingRecord *enc;
1598   lookup_cmap_func lookupper;
1599
1600   if (! otf->cmap
1601       && OTF_get_table (otf, "cmap") < 0)
1602     return -1;
1603
1604   cmap = otf->cmap;
1605   for (i = 0; i < cmap->numTables; i++)
1606     if (cmap->EncodingRecord[i].platformID == platform_id
1607         && cmap->EncodingRecord[i].encodingID == encoding_id)
1608       break;
1609   if (i == cmap->numTables)
1610     OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (unknown platformID/encodingID)");
1611   enc = cmap->EncodingRecord + i;
1612   if (enc->subtable.format > 12)
1613     OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (invalid format)");
1614   lookupper = lookup_cmap_func_table[enc->subtable.format / 2];
1615
1616   for (i = 0; i < gstring->used; i++)
1617     if (! gstring->glyphs[i].glyph_id)
1618       {
1619         int c = gstring->glyphs[i].c;
1620         if (c < 32 || ! cmap->unicode_table)
1621           gstring->glyphs[i].glyph_id = 0;
1622         else if (UVS_P (c) && i > 0)
1623           check_cmap_uvs (cmap, gstring, i);
1624         else if (c < 0x10000)
1625           gstring->glyphs[i].glyph_id = cmap->unicode_table[c];
1626         else
1627           gstring->glyphs[i].glyph_id = lookupper (c, &enc->subtable);
1628       }
1629 }
1630
1631
1632 int
1633 OTF_get_unicode (OTF *otf, OTF_GlyphID code)
1634 {
1635   if (! otf->cmap
1636       && OTF_get_table (otf, "cmap") < 0)
1637     return 0;
1638   if (code == 0
1639       || code > otf->cmap->max_glyph_id
1640       || ! otf->cmap->decode_table)
1641     return 0;
1642   return otf->cmap->decode_table[code];
1643 }
1644
1645 int
1646 OTF_get_variation_glyphs (OTF *otf, int c, OTF_GlyphID code[256])
1647 {
1648   int i, n;
1649   OTF_cmap *cmap;
1650   OTF_EncodingSubtable14 *sub14;
1651
1652   memset (code, 0, sizeof (OTF_GlyphID) * 256);
1653   if (! otf->cmap
1654       && OTF_get_table (otf, "cmap") < 0)
1655     return 0;
1656   cmap = otf->cmap;
1657   for (i = 0; i < cmap->numTables; i++)
1658     if (cmap->EncodingRecord[i].subtable.format == 14)
1659       break;
1660   if (i == cmap->numTables)
1661     return 0;
1662   sub14 = cmap->EncodingRecord[i].subtable.f.f14;
1663   for (i = 0, n = 0; i < 256; i++)
1664     {
1665       int uvs = (i < 16 ? 0xFE00 + i : 0xE0100 + (i - 16));
1666
1667       if ((code[i] = get_uvs_glyph (cmap, sub14, c, uvs)))
1668         n++;
1669     }
1670   return n;
1671 }
1672
1673
1674 int
1675 OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring)
1676 {
1677   OTF_GDEF *gdef;
1678   int i;
1679
1680   if (! otf->gdef
1681       && OTF_get_table (otf, "GDEF") < 0)
1682     return -1;
1683   gdef = otf->gdef;
1684
1685   if (gdef->glyph_class_def.offset)
1686     for (i = 0; i < gstring->used; i++)
1687       gstring->glyphs[i].GlyphClass
1688         = get_class_def (&gdef->glyph_class_def,
1689                          gstring->glyphs[i].glyph_id);
1690   else
1691     for (i = 0; i < gstring->used; i++)
1692       gstring->glyphs[i].GlyphClass
1693         = get_class_def_auto (gstring->glyphs[i].c);
1694
1695   if (gdef->mark_attach_class_def.offset)
1696     for (i = 0; i < gstring->used; i++)
1697       gstring->glyphs[i].MarkAttachClass
1698         = get_class_def (&gdef->mark_attach_class_def,
1699                          gstring->glyphs[i].glyph_id);
1700
1701   return 0;
1702 }
1703
1704 static int
1705 OTF_drive_gsub_internal (OTF *otf, OTF_GlyphString *gstring,
1706                          const char *script, const char *language,
1707                          const char *features,
1708                          int alternate_subst)
1709 {
1710   char *errfmt = "GSUB driving%s";
1711   int errret = -1;
1712   OTF_GSUB *gsub;
1713   OTF_LangSys *LangSys;
1714   char *lookup_flags;
1715   int i;
1716
1717   for (i = 0; i < gstring->used; i++)
1718     {
1719       gstring->glyphs[i].positioning_type = 0;
1720       gstring->glyphs[i].f.index.from = gstring->glyphs[i].f.index.to = i;
1721     }
1722
1723   if (OTF_get_table (otf, "GSUB") < 0)
1724     return errret;
1725   gsub = otf->gsub;
1726   if (gsub->FeatureList.FeatureCount == 0
1727       || gsub->LookupList.LookupCount == 0)
1728     return 0;
1729
1730   LangSys = get_langsys (&gsub->ScriptList, script, language);
1731   if (! LangSys)
1732     return errret;
1733
1734   lookup_flags = alloca (gsub->LookupList.LookupCount);
1735   if (! lookup_flags
1736       || setup_lookup_flags (&gsub->LookupList, &gsub->FeatureList, LangSys,
1737                              features, lookup_flags) < 0)
1738     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
1739
1740   for (i = 0; i < gsub->LookupList.LookupCount; i++)
1741     {
1742       int gidx;
1743
1744       if (! lookup_flags[i]) continue;
1745
1746       if (gsub->LookupList.Lookup[i].LookupType != 8)
1747         {
1748           gidx = 0;
1749           while (gidx < gstring->used)
1750             {
1751               gidx = lookup_gsub (otf, &gsub->LookupList, i, gstring, gidx,
1752                                   alternate_subst);
1753               if (gidx < 0)
1754                 return errret;
1755             }
1756         }
1757       else
1758         {
1759           gidx = gstring->used - 1;
1760           while (gidx >= 0)
1761             {
1762               gidx = lookup_gsub (otf, &gsub->LookupList, i, gstring, gidx,
1763                                   alternate_subst);
1764               if (gidx < 0)
1765                 return errret;
1766             }
1767         }
1768     }
1769
1770   return 0;
1771 }
1772
1773 int
1774 OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring,
1775                 const char *script, const char *language, const char *features)
1776 {
1777   if (! otf->cmap)
1778     OTF_get_table (otf, "cmap");
1779   return OTF_drive_gsub_internal (otf, gstring, script, language, features, 0);
1780 }
1781
1782 int
1783 OTF_drive_gpos_internal (OTF *otf, OTF_GlyphString *gstring,
1784                          const char *script, const char *language,
1785                          const char *features,
1786                          int accumulate)
1787 {
1788   char *errfmt = "GPOS driving%s";
1789   int errret = -1;
1790   OTF_GPOS *gpos;
1791   OTF_LangSys *LangSys;
1792   char *lookup_flags;
1793   int i, n;
1794
1795   for (i = 0; i < gstring->used; i++)
1796     gstring->glyphs[i].positioning_type = 0;
1797
1798   if (OTF_get_table (otf, "GPOS") < 0)
1799     return errret;
1800   gpos = otf->gpos;
1801   if (gpos->FeatureList.FeatureCount == 0
1802       || gpos->LookupList.LookupCount == 0)
1803     return 0;
1804
1805   LangSys = get_langsys (&gpos->ScriptList, script, language);
1806   if (! LangSys)
1807     return errret;
1808
1809   lookup_flags = alloca (gpos->LookupList.LookupCount);
1810   if (! lookup_flags
1811       || setup_lookup_flags (&gpos->LookupList, &gpos->FeatureList, LangSys,
1812                              features, lookup_flags) < 0)
1813     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
1814
1815   for (i = 0; i < gpos->LookupList.LookupCount; i++)
1816     {
1817       int gidx = 0;
1818
1819       if (! lookup_flags[i]) continue;
1820
1821       while (gidx < gstring->used)
1822         {
1823           gidx = lookup_gpos (&gpos->LookupList, i, gstring, gidx, accumulate);
1824           if (gidx < 0)
1825             return errret;
1826         }
1827     }
1828
1829   return 0;
1830 }
1831
1832 int
1833 OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring,
1834                 const char *script, const char *language, const char *features)
1835 {
1836   if (! otf->cmap)
1837     OTF_get_table (otf, "cmap");
1838   return OTF_drive_gpos_internal (otf, gstring, script, language, features, 0);
1839 }
1840
1841 int
1842 OTF_drive_gpos2 (OTF *otf, OTF_GlyphString *gstring,
1843                 const char *script, const char *language, const char *features)
1844 {
1845   if (! otf->cmap)
1846     OTF_get_table (otf, "cmap");
1847   return OTF_drive_gpos_internal (otf, gstring, script, language, features, 1);
1848 }
1849
1850 int
1851 OTF_drive_tables (OTF *otf, OTF_GlyphString *gstring,
1852                   const char *script, const char *language,
1853                   const char *gsub_features, const char *gpos_features)
1854 {
1855   if (OTF_drive_cmap (otf, gstring) < 0)
1856     return -1;
1857   if (OTF_drive_gdef (otf, gstring) < 0)
1858     return -1;
1859   if (gsub_features
1860       && OTF_drive_gsub (otf, gstring, script, language, gsub_features) < 0)
1861     return -1;
1862   if (gpos_features
1863       && OTF_drive_gpos (otf, gstring, script, language, gpos_features) < 0)
1864     return -1;
1865   return 0;
1866 }
1867
1868 int
1869 OTF_drive_gsub_alternate (OTF *otf, OTF_GlyphString *gstring,
1870                           const char *script, const char *language,
1871                           const char *features)
1872 {
1873   return OTF_drive_gsub_internal (otf, gstring, script, language, features, 1);
1874 }
1875
1876 static int
1877 iterate_coverage (OTF *otf, const char *feature,
1878                   OTF_Feature_Callback callback,
1879                   OTF_Coverage *coverage)
1880 {
1881   int i;
1882
1883   if (coverage->CoverageFormat == 1)
1884     {
1885       for (i = 0; i < coverage->Count; i++)
1886         if (callback (otf, feature, coverage->table.GlyphArray[i]) < 0)
1887           return -1;
1888     }
1889   else
1890     {
1891       for (i = 0; i < coverage->Count; i++)
1892         {
1893           OTF_RangeRecord *range = coverage->table.RangeRecord + i;
1894           unsigned id;
1895           for (id = range->Start; id <= range->End; id++)
1896             if (callback (otf, feature, id) < 0)
1897               return -1;
1898         }
1899     }
1900   return 0;
1901 }
1902
1903 static int
1904 iterate_feature (OTF *otf, const char *feature,
1905                  OTF_Feature_Callback callback,
1906                  OTF_Lookup *lookup)
1907 {
1908   int i, j, k, l;
1909
1910   for (i = 0; i < lookup->SubTableCount; i++)
1911     {
1912       unsigned lookup_type = lookup->LookupType;
1913       OTF_LookupSubTableGSUB *subtable = lookup->SubTable.gsub + i;
1914
1915       if (lookup_type == 7)
1916         {
1917           OTF_GSUB_Extension1 *extension1 = &subtable->u.extension1;
1918
1919           lookup_type = extension1->ExtensionLookupType;
1920           subtable = extension1->ExtensionSubtable;
1921         }
1922
1923       if ((lookup_type >= 1 && lookup_type <= 3) || lookup_type == 8)
1924         {
1925           if (iterate_coverage (otf, feature, callback, &subtable->Coverage)
1926               < 0)
1927             return -1;
1928         }
1929       else if (lookup_type == 4)
1930         {
1931           OTF_GSUB_Ligature1 *lig1;
1932
1933           if (iterate_coverage (otf, feature, callback, &subtable->Coverage)
1934               < 0)
1935             return -1;
1936           lig1 = &subtable->u.ligature1;
1937           for (j = 0; j < lig1->LigSetCount; j++)
1938             {
1939               OTF_LigatureSet *ligset = lig1->LigatureSet + j;
1940
1941               for (k = 0; k < ligset->LigatureCount; k++)
1942                 {
1943                   OTF_Ligature *lig = ligset->Ligature + k;
1944                   for (l = 0; l < lig->CompCount - 1; l++)
1945                     if (callback (otf, feature, lig->Component[l]) < 0)
1946                       return -1;
1947                 }
1948             }
1949         }
1950       else if (lookup_type == 6)
1951         {
1952           if (subtable->Format == 1)
1953             {
1954               OTF_GSUB_ChainContext1 *context1 = &subtable->u.chain_context1;
1955               for (j = 0; j < context1->ChainRuleSetCount; j++)
1956                 {
1957                   OTF_ChainRuleSet *set = context1->ChainRuleSet + j;
1958                   for (k = 0; k < set->ChainRuleCount; k++)
1959                     {
1960                       OTF_ChainRule *rule = set->ChainRule + k;
1961                       for (l = 0; l < rule->LookupCount; l++)
1962                         {
1963                           OTF_Lookup *lkup
1964                             = (otf->gsub->LookupList.Lookup
1965                                + rule->LookupRecord[l].LookupListIndex);
1966                           if (iterate_feature (otf, feature, callback, lkup)
1967                               < 0)
1968                             return -1;
1969                         }
1970                     }
1971                 }
1972             }
1973           else if (subtable->Format == 2)
1974             {
1975               OTF_GSUB_ChainContext2 *context2 = &subtable->u.chain_context2;
1976
1977               for (j = 0; j < context2->ChainClassSetCnt; j++)
1978                 {
1979                   OTF_ChainClassSet *set = context2->ChainClassSet + j;
1980                   for (k = 0; k < set->ChainClassRuleCnt; j++)
1981                     {
1982                       OTF_ChainClassRule *rule = set->ChainClassRule + k;
1983
1984                       for (l = 0; l < rule->LookupCount; l++)
1985                         {
1986                           OTF_Lookup *lkup
1987                             = (otf->gsub->LookupList.Lookup
1988                                + rule->LookupRecord[k].LookupListIndex);
1989                           if (iterate_feature (otf, feature, callback, lkup)
1990                               < 0)
1991                             return -1;
1992                         }
1993                     }
1994                 }
1995             }
1996           else
1997             {
1998               OTF_GSUB_ChainContext3 *context3 = &subtable->u.chain_context3;
1999               for (j = 0; j < context3->LookupCount; j++)
2000                 {
2001                   OTF_Lookup *lkup
2002                     = (otf->gsub->LookupList.Lookup
2003                        + context3->LookupRecord[j].LookupListIndex);
2004                   if (iterate_feature (otf, feature, callback, lkup) < 0)
2005                     return -1;
2006                 }
2007             }
2008         }
2009     }
2010   return 0;
2011 }
2012
2013 int
2014 OTF_iterate_gsub_feature (OTF *otf, OTF_Feature_Callback callback,
2015                           const char *script, const char *language,
2016                           const char *feature)
2017 {
2018   char *errfmt = "GSUB iterate feature%s";
2019   int errret = -1;
2020   int i;
2021
2022   OTF_GSUB *gsub;
2023   OTF_LangSys *langsys;
2024   char *lookup_flags;
2025
2026   if (OTF_get_table (otf, "GSUB") < 0)
2027     return errret;
2028   gsub = otf->gsub;
2029   if (gsub->FeatureList.FeatureCount == 0
2030       || gsub->LookupList.LookupCount == 0)
2031     return 0;
2032   langsys = get_langsys (&gsub->ScriptList, script, language);
2033   if (! langsys)
2034     return errret;
2035   lookup_flags = alloca (gsub->LookupList.LookupCount);
2036   if (! lookup_flags
2037       || setup_lookup_flags (&gsub->LookupList, &gsub->FeatureList, langsys,
2038                              feature, lookup_flags) < 0)
2039     OTF_ERROR (OTF_ERROR_MEMORY, " feature");
2040
2041   for (i = 0; i < gsub->LookupList.LookupCount; i++)
2042     if (lookup_flags[i])
2043       if (iterate_feature (otf, feature, callback, gsub->LookupList.Lookup + i)
2044           < 0)
2045         return -1;
2046   return 0;
2047 }