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