(lookup_gsub): New arg alternate_subst. Callers
[m17n/libotf.git] / src / otfdrive.c
1 /* otfdrive.c -- OpenType font driver.
2
3 Copyright (C) 2003, 2004
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 /* Return nonzero if OTF_Glyph *G should be ignored according to
33    LookupFlag FLAG.  */
34 #define IGNORED_GLYPH(g, flag)                  \
35   ((g)->glyph_id == 0                           \
36    || ((flag) & (1 << (g)->GlyphClass))         \
37    || (((flag) & OTF_MarkAttachmentType)        \
38        && (g)->GlyphClass == OTF_GlyphClassMark \
39        && ((flag) >> 8) != (g)->MarkAttachClass))
40
41 #define GSTRING_DELETE(gstring, from, len)                              \
42   do {                                                                  \
43     memmove (gstring->glyphs + from, gstring->glyphs + from + len,      \
44              sizeof (OTF_Glyph) * (gstring->used - from - len));        \
45     gstring->used -= len;                                               \
46   } while (0)
47
48
49 #define GSTRING_INSERT(gstring, pos, len)                               \
50   do {                                                                  \
51     if (gstring->used + len > gstring->size)                            \
52       {                                                                 \
53         char *errfmt = "GSTRING%s";                                     \
54                                                                         \
55         gstring->size = gstring->used + len;                            \
56         gstring->glyphs                                                 \
57           = (OTF_Glyph *) realloc (gstring->glyphs,                     \
58                                    sizeof (OTF_Glyph) * gstring->size); \
59         if (! gstring->glyphs)                                          \
60           OTF_ERROR (OTF_ERROR_MEMORY, "");                             \
61       }                                                                 \
62     memmove (gstring->glyphs + pos + len, gstring->glyphs + pos,        \
63              sizeof (OTF_Glyph) * (gstring->used - pos));               \
64     gstring->used += len;                                               \
65   } while (0)
66
67
68 static int
69 gstring_subst (OTF_GlyphString *gstring, int from, int to, int flag,
70                OTF_GlyphID *ids, int num)
71 {
72   int errret = -1;
73   int len = to - from;
74   int i;
75   int c = gstring->glyphs[from].c;
76   int from_idx = gstring->glyphs[from].f.index.from;
77   int to_idx = gstring->glyphs[to - 1].f.index.to;
78   int non_ignored_idx;
79
80   for (i = non_ignored_idx = to - 1; i >= from; i--)
81     {
82       OTF_Glyph *g = gstring->glyphs + i;
83       if (IGNORED_GLYPH (g, flag))
84         {
85           OTF_Glyph temp = *g;
86
87           memmove (g, g + 1, sizeof (OTF_Glyph) * (non_ignored_idx - i));
88           gstring->glyphs[non_ignored_idx--] = temp;
89           len--;
90         }
91     }
92
93   if (len < num)
94     GSTRING_INSERT (gstring, from, (num - len));
95   else if (len > num)
96     GSTRING_DELETE (gstring, from, (len - num));
97   for (i = 0; i < num; i++)
98     {
99       gstring->glyphs[from + i].c = c;
100       gstring->glyphs[from + i].glyph_id = ids[i];
101       gstring->glyphs[from + i].f.index.from = from_idx;
102       gstring->glyphs[from + i].f.index.to = to_idx;
103     }
104   return 0;
105 }
106
107 \f
108 static int
109 get_coverage_index (OTF_Coverage *coverage, OTF_GlyphID id)
110 {
111   int i;
112
113   if (coverage->CoverageFormat == 1)
114     {
115       for (i = 0; i < coverage->Count; i++)
116         if (coverage->table.GlyphArray[i] == id)
117           return i;
118     }
119   else
120     {
121       for (i = 0; i < coverage->Count; i++)
122         if (coverage->table.RangeRecord[i].Start <= id
123             && coverage->table.RangeRecord[i].End >= id)
124           return (coverage->table.RangeRecord[i].StartCoverageIndex
125                   + (id - coverage->table.RangeRecord[i].Start));
126     }
127   return -1;
128 }
129
130 static unsigned
131 get_class_def (OTF_ClassDef *class_def, OTF_GlyphID glyph_id)
132 {
133   if (class_def->ClassFormat == 1)
134     {
135       int idx = (int) glyph_id - (int) class_def->f.f1.StartGlyph;
136
137       if (idx >= 0 && idx < class_def->f.f1.GlyphCount)
138         return class_def->f.f1.ClassValueArray[idx];
139     }
140   else
141     {
142       int i;
143
144       for (i = 0; i < class_def->f.f2.ClassRangeCount; i++)
145         if (glyph_id >= class_def->f.f2.ClassRangeRecord[i].Start
146             && glyph_id <= class_def->f.f2.ClassRangeRecord[i].End)
147           return class_def->f.f2.ClassRangeRecord[i].Class;
148     }
149   return 0;
150 }
151
152 static OTF_LangSys *
153 get_langsys (OTF_ScriptList *script_list, char *script, char *language)
154 {
155
156   OTF_Tag script_tag = OTF_tag (script);
157   OTF_Tag langsys_tag = OTF_tag (language);
158   int i, j;
159   OTF_Tag dflt_tag = OTF_tag ("DFLT");
160   OTF_Script *dflt = NULL;
161
162   for (i = 0; i < script_list->ScriptCount; i++)
163     {
164       OTF_Script *script = script_list->Script + i;
165
166       if (script_list->Script[i].ScriptTag == dflt_tag)
167         dflt = script;
168       if (script_list->Script[i].ScriptTag == script_tag)
169         {
170           if (! langsys_tag)
171             return &script->DefaultLangSys;
172           for (j = 0; j < script->LangSysCount; j++)
173             if (script->LangSysRecord[j].LangSysTag == langsys_tag)
174               return script->LangSys + j;
175           return &script->DefaultLangSys;       
176         }
177     }
178
179   if (! dflt)
180     dflt = script_list->Script;
181   if (! langsys_tag)
182     return &dflt->DefaultLangSys;
183   for (j = 0; j < dflt->LangSysCount; j++)
184     if (dflt->LangSysRecord[j].LangSysTag == langsys_tag)
185       return dflt->LangSys + j;
186   return &dflt->DefaultLangSys; 
187 }
188
189 static int
190 setup_lookup_indices (OTF_LookupList *LookupList, OTF_FeatureList *FeatureList,
191                       char *features, int *lookup_indices)
192 {
193   int i, j, n = 0;
194   OTF_Feature *feature;
195   int *feature_table = alloca (sizeof (int) * FeatureList->FeatureCount);
196
197   for (i = 0; i < FeatureList->FeatureCount; i++)
198     feature_table[i] = 0;
199
200   while (*features)
201     {
202       char tagname[4];
203       OTF_Tag tag;
204       int use_it = 1;
205
206       if (*features == '*')
207         {
208           /* Consume all remaining features.  */
209           for (i = 0; i < FeatureList->FeatureCount; i++)
210             if (! feature_table[i])
211               {
212                 feature = FeatureList->Feature + i;
213                 for (j = 0; j < feature->LookupCount; j++)
214                   lookup_indices[n++] = feature->LookupListIndex[j];
215               }
216           break;
217         }
218
219       if (*features == '~')
220         use_it = -1, features++;
221       for (i = 0; *features && *features != ','; i++, features++)
222         tagname[i] = *features;
223       if (*features)
224         /* Skip ',' */
225         features++;
226       for (; i < 4; i++)
227         tagname[i] = '\0';
228       tag = OTF_tag (tagname);
229       for (i = 0; i < FeatureList->FeatureCount; i++)
230         {
231           feature = FeatureList->Feature + i;
232           if (tag == feature->FeatureTag)
233             {
234               if (feature_table[i])
235                 break;
236               if (use_it > 0)
237                 for (j = 0; j < feature->LookupCount; j++)
238                   lookup_indices[n++] = feature->LookupListIndex[j];
239               feature_table[i] = use_it;
240               break;
241             }
242         }
243     }
244
245   return n;
246 }
247
248 static int
249 match_ids (OTF_GlyphString *gstring, int gidx, int flag,
250            int count, OTF_GlyphID *ids)
251 {
252   OTF_Glyph *gbeg = gstring->glyphs + gidx;
253   OTF_Glyph *gend = gstring->glyphs + gstring->used;
254   OTF_Glyph *g;
255   int i;
256
257   for (g = gbeg, i = 0; g < gend && i < count; g++)
258     if (! IGNORED_GLYPH (g, flag) && g->glyph_id != ids[i++])
259       return -1;
260   return (i < count ? -1 : g - gbeg);
261 }
262
263 static int
264 match_chain_ids (OTF_GlyphString *gstring, int gidx, int flag,
265                  OTF_ChainRule *rule)
266 {
267   int i = rule->BacktrackGlyphCount;
268
269   if (i > 0)
270     {
271       int j;
272       OTF_Glyph *g;
273
274       for (j = gidx - 1, g = gstring->glyphs + j; j >= 0; j--, g--)
275         if (! IGNORED_GLYPH (g, flag) && --i == 0)
276           break;
277       if (i > 0)
278         return -1;
279       if (match_ids (gstring, j, flag,
280                      rule->BacktrackGlyphCount, rule->Backtrack)
281           < 0)
282         return -1;
283     }
284   gidx++;
285   i = match_ids (gstring, gidx, flag,
286                  rule->InputGlyphCount - 1, rule->Input);
287   if (i < 0)
288     return -1;
289   gidx += i;
290   i = match_ids (gstring, gidx, flag,
291                  rule->LookaheadGlyphCount, rule->LookAhead);
292   if (i < 0)
293     return -1;
294   return 0;
295 }
296
297 static int
298 match_classes (OTF_ClassDef *class_def, OTF_GlyphString *gstring, int gidx,
299                int flag, int count, unsigned *classes)
300 {
301   OTF_Glyph *gbeg = gstring->glyphs + gidx;
302   OTF_Glyph *gend = gstring->glyphs + gstring->used;
303   OTF_Glyph *g;
304   int i;
305
306   for (g = gbeg, i = 0; g < gend && i < count; g++)
307     if (! IGNORED_GLYPH (g, flag)
308         && get_class_def (class_def, g->glyph_id) != classes[i++])
309       return -1;
310   return (i < count ? -1 : g - gbeg);
311 }
312
313 static int
314 match_chain_classes (OTF_GlyphString *gstring, int gidx, int flag,
315                      OTF_ClassDef *BacktrackClassDef,
316                      OTF_ClassDef *InputClassDef,
317                      OTF_ClassDef *LookaheadClassDef,
318                      OTF_ChainClassRule *rule)
319 {
320   int i = rule->BacktrackGlyphCount;
321
322   if (i > 0)
323     {
324       int j;
325       OTF_Glyph *g;
326
327       for (j = gidx - 1, g = gstring->glyphs + j; j >= 0; j--, g--)
328         if (! IGNORED_GLYPH (g, flag) && i-- == 0)
329           break;
330       if (i > 0)
331         return -1;
332       if (match_classes (BacktrackClassDef, gstring, j, flag,
333                          rule->BacktrackGlyphCount, rule->Backtrack) < 0);
334       return -1;
335     }
336   gidx++;
337   i = match_classes (InputClassDef, gstring, gidx, flag,
338                      rule->InputGlyphCount - 1, rule->Input);
339   if (i < 0)
340     return -1;
341   gidx += i;
342   i = match_classes (LookaheadClassDef, gstring, gidx, flag,
343                      rule->LookaheadGlyphCount, rule->LookAhead);
344   if (i < 0)
345     return -1;
346   return 0;
347 }
348
349
350 static int
351 match_coverages (OTF_GlyphString *gstring, int gidx, int flag, int count,
352                  OTF_Coverage *coverages)
353 {
354   OTF_Glyph *gbeg = gstring->glyphs + gidx;
355   OTF_Glyph *gend = gstring->glyphs + gstring->used;
356   OTF_Glyph *g;
357   int i;
358
359   for (g = gbeg, i = 0; g < gend && i < count; g++)
360     if (! IGNORED_GLYPH (g, flag)
361         && get_coverage_index (coverages + i++, g->glyph_id) < 0)
362       return -1;
363   return (i < count ? -1 : g - gbeg);
364 }
365
366 static int
367 match_chain_coverages (OTF_GlyphString *gstring, int gidx, int flag,
368                        OTF_GSUB_ChainContext3 *context3)
369 {
370   int i = context3->BacktrackGlyphCount;
371
372   if (i > 0)
373     {
374       int j;
375       OTF_Glyph *g;
376
377       for (j = gidx - 1, g= gstring->glyphs +j; j >= 0; j--, g--)
378         if (! IGNORED_GLYPH (g, flag) && --i == 0)
379           break;
380       if (i > 0)
381         return -1;
382       if (match_coverages (gstring, j, flag, context3->BacktrackGlyphCount,
383                            context3->Backtrack) < 0)
384         return -1;
385     }
386   gidx++;
387   if (context3->InputGlyphCount > 1)
388     {
389       i = match_coverages (gstring, gidx, flag, context3->InputGlyphCount - 1,
390                            context3->Input + 1);
391       if (i < 0)
392         return -1;
393       gidx += i;
394     }
395   if (match_coverages (gstring, gidx, flag, context3->LookaheadGlyphCount,
396                        context3->LookAhead) < 0)
397     return -1;
398   return 0;
399 }
400
401 static int
402 lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
403              OTF_GlyphString *gstring, int gidx, int alternate_subst)
404 {
405   char *errfmt = "GSUB Looking up%s";
406   int errret = -1;
407   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
408   unsigned int flag = (lookup->LookupFlag
409                        & (OTF_LookupFlagIgnoreMask | OTF_MarkAttachmentType));
410   int orig_gidx = gidx;
411   OTF_Glyph *g = gstring->glyphs + gidx;
412   int i;
413
414   if (IGNORED_GLYPH (g, flag))
415     return (gidx + 1);
416
417   /* Try all subtables until one of them handles the current glyph.  */
418   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
419     {
420       unsigned lookup_type = lookup->LookupType;
421       OTF_LookupSubTableGSUB *subtable = lookup->SubTable.gsub + i;
422       int coverage_idx;
423
424       if (lookup_type == 7)
425         {
426           OTF_GSUB_Extension1 *extension1 = &subtable->u.extension1;
427
428           lookup_type = extension1->ExtensionLookupType;
429           subtable = extension1->ExtensionSubtable;
430         }
431
432       if (alternate_subst
433           ? (lookup_type != 3 && lookup_type != 5 && lookup_type != 6)
434           : (lookup_type == 3))
435         continue;
436
437       if (subtable->Coverage.offset)
438         {
439           coverage_idx = get_coverage_index (&subtable->Coverage,
440                                              g->glyph_id);
441           if (coverage_idx < 0)
442             continue;
443         }
444
445       switch (lookup_type)
446         {
447         case 1:
448           if (subtable->Format == 1)
449             g->glyph_id += subtable->u.single1.DeltaGlyphID;
450           else
451             g->glyph_id = subtable->u.single2.Substitute[coverage_idx];
452           gidx++;
453           break;
454
455         case 2:
456           if (subtable->Format == 1)
457             {
458               OTF_GSUB_Multiple1 *multiple1 = &subtable->u.multiple1;
459               OTF_Sequence *seq = multiple1->Sequence + coverage_idx;
460
461               gstring_subst (gstring, gidx, gidx + 1, flag,
462                              seq->Substitute, seq->GlyphCount);
463               gidx += seq->GlyphCount;
464             }
465           else
466             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
467           break;
468
469         case 3:
470           if (subtable->Format == 1)
471             {
472               OTF_GSUB_Alternate1 *alt1 = &subtable->u.alternate1;
473               OTF_AlternateSet *altset = alt1->AlternateSet + coverage_idx;
474
475               gstring_subst (gstring, gidx + 1, gidx + 1, flag,
476                              altset->Alternate, altset->GlyphCount);
477               gidx += altset->GlyphCount;;
478             }
479           else
480             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
481           break;
482
483         case 4:
484           if (subtable->Format == 1)
485             {
486               OTF_GSUB_Ligature1 *lig1 = &subtable->u.ligature1;
487               OTF_LigatureSet *ligset = lig1->LigatureSet + coverage_idx;
488               OTF_Ligature *lig;
489               int j;
490
491               for (j = 0; j < ligset->LigatureCount; j++)
492                 {
493                   int n;
494
495                   lig = ligset->Ligature + j;
496                   n = match_ids (gstring, gidx + 1, flag,
497                                  lig->CompCount - 1, lig->Component);
498                   if (n < 0)
499                     continue;
500                   gstring_subst (gstring, gidx, gidx + 1 + n, flag,
501                                  &lig->LigGlyph, 1);
502                   gidx++;
503                   break;
504                 }
505             }
506           else
507             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
508           break;
509
510         case 5:
511           if (subtable->Format == 1)
512             {
513               OTF_GSUB_Context1 *context1 = &subtable->u.context1;
514               OTF_RuleSet *set = context1->RuleSet + coverage_idx;
515               OTF_Rule *rule;
516               int orig_used;
517               int j, k;
518
519               for (j = 0; j < set->RuleCount; j++)
520                 {
521                   rule = set->Rule + j;
522                   if (match_ids (gstring, gidx + 1, flag,
523                                  rule->GlyphCount - 1, rule->Input) < 0)
524                     continue;
525                   orig_used = gstring->used;
526                   for (k = 0; k < rule->LookupCount; k++)
527                     lookup_gsub (lookup_list,
528                                  rule->LookupRecord[k].LookupListIndex,
529                                  gstring,
530                                  gidx + rule->LookupRecord[k].SequenceIndex,
531                                  alternate_subst);
532                   gidx += rule->GlyphCount + (gstring->used - orig_used);
533                   break;
534                 }
535             }
536           else if (subtable->Format == 2)
537             {
538               OTF_GSUB_Context2 *context2 = &subtable->u.context2;
539               OTF_ClassSet *set;
540               OTF_ClassRule *rule;
541               unsigned class;
542               int orig_used;
543               int j, k;
544
545               class = get_class_def (&context2->ClassDef, g->glyph_id);
546               set = context2->ClassSet + class;
547               if (set)
548                 for (j = 0; j < set->ClassRuleCnt; j++)
549                   {
550                     rule = set->ClassRule + j;
551                     if (match_classes (&context2->ClassDef,
552                                        gstring, gidx + 1, flag,
553                                        rule->GlyphCount - 1, rule->Class)
554                         < 0)
555                       continue;
556                     orig_used = gstring->used;
557                     for (k = 0; k < rule->LookupCount; k++)
558                       lookup_gsub (lookup_list,
559                                    rule->LookupRecord[k].LookupListIndex,
560                                    gstring,
561                                    gidx + rule->LookupRecord[k].SequenceIndex,
562                                    alternate_subst);
563                     gidx += rule->GlyphCount + (gstring->used - orig_used);
564                     break;
565                   }
566             }
567           else                  /* subtable->Format == 3 */
568             {
569               OTF_GSUB_Context3 *context3 = &subtable->u.context3;
570               int orig_used;
571               int j;
572
573               if (match_coverages (gstring, gidx + 1, flag,
574                                    context3->GlyphCount - 1,
575                                    context3->Coverage + 1) < 0)
576                 continue;
577               orig_used = gstring->used;
578               for (j = 0; j < context3->LookupCount; j++)
579                 lookup_gsub (lookup_list,
580                              context3->LookupRecord[j].LookupListIndex,
581                              gstring,
582                              gidx + context3->LookupRecord[j].SequenceIndex,
583                              alternate_subst);
584               gidx += context3->GlyphCount + (gstring->used - orig_used);
585             }
586           break;
587
588         case 6:
589           if (subtable->Format == 1)
590             {
591               OTF_GSUB_ChainContext1 *context1 = &subtable->u.chain_context1;
592               OTF_ChainRuleSet *set = context1->ChainRuleSet + coverage_idx;
593               int orig_used;
594               int j, k;
595               
596               for (j = 0; j < set->ChainRuleCount; j++)
597                 {
598                   OTF_ChainRule *rule = set->ChainRule + j;
599
600                   if (gidx < rule->BacktrackGlyphCount
601                       || (gidx + rule->InputGlyphCount
602                           + rule->LookaheadGlyphCount) > gstring->used)
603                     continue;
604                   if (match_chain_ids (gstring, gidx, flag, rule) < 0)
605                     continue;
606                   orig_used = gstring->used;
607                   for (k = 0; k < rule->LookupCount; k++)
608                     lookup_gsub (lookup_list,
609                                  rule->LookupRecord[k].LookupListIndex,
610                                  gstring,
611                                  gidx + rule->LookupRecord[k].SequenceIndex,
612                                  alternate_subst);
613                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
614                   break;
615                 }
616             }
617           else if (subtable->Format == 2)
618             {
619               OTF_GSUB_ChainContext2 *context2 = &subtable->u.chain_context2;
620               OTF_ChainClassSet *set;
621               unsigned class;
622               int j;
623               int orig_used;
624
625               class = get_class_def (&context2->InputClassDef, g->glyph_id);
626               set = context2->ChainClassSet + class;
627               for (j = 0; j < set->ChainClassRuleCnt; j++)
628                 {
629                   OTF_ChainClassRule *rule = set->ChainClassRule + j;
630                   int k;
631
632                   if (gidx < rule->BacktrackGlyphCount
633                       || (gidx + rule->InputGlyphCount
634                           + rule->LookaheadGlyphCount) > gstring->used)
635                     continue;
636                   if (match_chain_classes (gstring, gidx, flag,
637                                            &context2->BacktrackClassDef,
638                                            &context2->InputClassDef,
639                                            &context2->LookaheadClassDef,
640                                            rule) < 0)
641                     continue;
642                   orig_used = gstring->used;
643                   for (k = 0; k < rule->LookupCount; k++)
644                     lookup_gsub (lookup_list,
645                                  rule->LookupRecord[k].LookupListIndex,
646                                  gstring,
647                                  gidx + rule->LookupRecord[k].SequenceIndex,
648                                  alternate_subst);
649                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
650                   break;
651                 }
652             }
653           else
654             {
655               OTF_GSUB_ChainContext3 *context3 = &subtable->u.chain_context3;
656               int orig_used;
657               int j;
658
659               if (gidx < context3->BacktrackGlyphCount
660                   || (gidx + context3->InputGlyphCount
661                       + context3->LookaheadGlyphCount) > gstring->used)
662                 continue;
663               if (match_chain_coverages (gstring, gidx, flag, context3) < 0)
664                 continue;
665               orig_used = gstring->used;
666               for (j = 0; j < context3->LookupCount; j++)
667                 lookup_gsub (lookup_list,
668                              context3->LookupRecord[j].LookupListIndex,
669                              gstring,
670                              gidx + context3->LookupRecord[j].SequenceIndex,
671                              alternate_subst);
672               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
673             }
674           break;
675
676         case 8:
677           {
678             OTF_GSUB_ReverseChain1 *reverse = &subtable->u.reverse_chain1;
679             int back_gidx = gidx + 1 + reverse->BacktrackGlyphCount;
680             int ahead_gidx = gidx - reverse->LookaheadGlyphCount;
681             int j;
682
683             if (back_gidx > gstring->used || ahead_gidx < 0)
684               break;
685
686             for (j = 0; j < reverse->BacktrackGlyphCount; j++)
687               if (get_coverage_index (reverse->Backtrack + j,
688                                       gstring->glyphs[gidx + 1 + j].glyph_id)
689                   < 0)
690                 break;
691             if (j < reverse->BacktrackGlyphCount)
692               continue;
693             for (j = 0; j < reverse->LookaheadGlyphCount; j++)
694               if (get_coverage_index (reverse->LookAhead + j,
695                                       gstring->glyphs[gidx - 1 - j].glyph_id)
696                   < 0)
697                 break;
698             if (j < reverse->LookaheadGlyphCount)
699               continue;
700             g->glyph_id = reverse->Substitute[coverage_idx];
701             gidx--;
702           }
703
704         default:
705           continue;
706         }
707     }
708   if (gidx == orig_gidx)
709     gidx++;
710   return gidx;
711 }
712
713 \f
714
715 /* GPOS */
716 unsigned
717 get_anchor (OTF_Anchor *anchor, OTF_ValueRecord *rec)
718 {
719   unsigned value_format = OTF_XPlacement | OTF_YPlacement;
720
721   rec->XPlacement = anchor->XCoordinate;
722   rec->YPlacement = anchor->YCoordinate;
723   if (anchor->AnchorFormat == 1)
724     /* Nothing to do */
725     ;
726   else if (anchor->AnchorFormat == 2)
727     /* Not yet implemented */
728     ;
729   else if (anchor->AnchorFormat == 3)
730     /* Not yet implemented */
731     ;
732   return value_format;
733 }
734
735
736 static int
737 lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
738              OTF_GlyphString *gstring, int gidx)
739 {
740   char *errfmt = "GPOS Looking up%s";
741   int errret = -1;
742   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
743   unsigned int flag = (lookup->LookupFlag
744                        & (OTF_LookupFlagIgnoreMask | OTF_MarkAttachmentType));
745   int orig_gidx = gidx;
746   OTF_Glyph *g = gstring->glyphs + gidx;
747   int i;
748
749   if (IGNORED_GLYPH (g, flag)
750       || g->positioning_type)
751     return (gidx + 1);
752
753   /* Try all subtables until one of them handles the current glyph.  */
754   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
755     {
756       unsigned lookup_type = lookup->LookupType;
757       OTF_LookupSubTableGPOS *subtable = lookup->SubTable.gpos + i;
758       int coverage_idx;
759
760       if (lookup_type == 9)
761         {
762           OTF_GPOS_Extension1 *extension1 = &subtable->u.extension1;
763
764           lookup_type = extension1->ExtensionLookupType;
765           subtable = extension1->ExtensionSubtable;
766         }
767
768       if (subtable->Coverage.offset)
769         {
770           coverage_idx = get_coverage_index (&subtable->Coverage,
771                                              g->glyph_id);
772           if (coverage_idx < 0)
773             continue;
774         }
775
776       switch (lookup_type)
777         {
778         case 1:
779           g->positioning_type = lookup_type;
780           if (subtable->Format == 1)
781             {
782               OTF_GPOS_Single1 *single1 = &subtable->u.single1;
783
784               g->f.f1.format = single1->ValueFormat;
785               g->f.f1.value = &single1->Value;
786             }
787           else if (subtable->Format == 2)
788             {
789               OTF_GPOS_Single2 *single2 = &subtable->u.single2;
790
791               g->f.f1.format = single2->ValueFormat;
792               g->f.f1.value = single2->Value + coverage_idx;
793             }
794           break;
795
796         case 2:
797           {
798             int next_gidx;
799             OTF_Glyph *nextg;
800
801             for (next_gidx = gidx + 1, nextg = gstring->glyphs + next_gidx;
802                  next_gidx < gstring->used && ! IGNORED_GLYPH (nextg, flag);
803                  next_gidx++, nextg++);
804
805             if (next_gidx >= gstring->used
806                 || nextg->positioning_type)
807               continue;
808             if (subtable->Format == 1)
809               {
810                 OTF_GPOS_Pair1 *pair1 = &subtable->u.pair1;
811                 OTF_PairSet *set = pair1->PairSet + coverage_idx;
812                 int j;
813
814                 for (j = 0; j < set->PairValueCount; j++)
815                   if (set->PairValueRecord[j].SecondGlyph == nextg->glyph_id)
816                     {
817                       if (pair1->ValueFormat1)
818                         {
819                           g->positioning_type = lookup_type;
820                           g->f.f2.format = pair1->ValueFormat1;
821                           g->f.f2.value = &set->PairValueRecord[j].Value1;
822                         }
823                       gidx = next_gidx;
824                       if (pair1->ValueFormat2)
825                         {
826                           nextg->positioning_type = lookup_type;
827                           nextg->f.f2.format = pair1->ValueFormat2;
828                           nextg->f.f2.value = &set->PairValueRecord[j].Value2;
829                           gidx++;
830                         }
831                       break;
832                     }
833               }
834             else if (subtable->Format == 2)
835               {
836                 OTF_GPOS_Pair2 *pair2 = &subtable->u.pair2;
837                 unsigned class1, class2;
838
839                 class1 = get_class_def (&pair2->ClassDef1, g->glyph_id);
840                 class2 = get_class_def (&pair2->ClassDef2, nextg->glyph_id);
841                 if (pair2->ValueFormat1)
842                   {
843                     g->positioning_type = lookup_type;
844                     g->f.f2.format = pair2->ValueFormat1;
845                     g->f.f2.value
846                       = &pair2->Class1Record[class1].Class2Record[class2].Value1;
847                   }
848                 gidx = next_gidx;
849                 if (pair2->ValueFormat2)
850                   {
851                     nextg->positioning_type = lookup_type;
852                     nextg->f.f2.format = pair2->ValueFormat2;
853                     nextg->f.f2.value
854                       = &pair2->Class1Record[class1].Class2Record[class2].Value2;
855                     gidx++;
856                   }
857               }
858           }
859           break;
860
861         case 3:
862           {
863             OTF_GPOS_Cursive1 *cursive1 = &subtable->u.cursive1;
864           
865             g->positioning_type = lookup_type;
866             g->f.f3.entry_anchor
867               = &cursive1->EntryExitRecord[coverage_idx].EntryAnchor;
868             g->f.f3.exit_anchor
869               = &cursive1->EntryExitRecord[coverage_idx].ExitAnchor;
870           }
871           break;
872
873         case 4:
874           if (gidx < 1)
875             continue;
876           if (subtable->Format == 1)
877             {
878               OTF_GPOS_MarkBase1 *mark_base1 = &subtable->u.mark_base1;
879               OTF_MarkRecord *mark_record;
880               OTF_AnchorRecord *base_record;
881               OTF_Glyph *baseg;
882               int coverage_idx_base;
883
884               for (baseg = g - 1;
885                    baseg >= gstring->glyphs && IGNORED_GLYPH (baseg, flag);
886                    baseg--);
887               if (baseg < gstring->glyphs)
888                 continue;
889               coverage_idx_base
890                 = get_coverage_index (&mark_base1->BaseCoverage,
891                                       baseg->glyph_id);
892               if (coverage_idx_base < 0)
893                 continue;
894               mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx;
895               base_record
896                 = mark_base1->BaseArray.AnchorRecord + coverage_idx_base;
897               g->f.f4.mark_anchor = &mark_record->MarkAnchor;
898               g->f.f4.base_anchor
899                 = &base_record->Anchor[mark_record->Class];
900               g->positioning_type = lookup_type;
901             }
902           break;
903
904         case 5:
905           if (gidx < 1)
906             continue;
907           if (subtable->Format == 1)
908             {
909               OTF_GPOS_MarkLig1 *mark_lig1 = &subtable->u.mark_lig1;
910               OTF_Glyph *ligg;
911               int coverage_idx_lig;
912               OTF_MarkRecord *mark_record;
913               OTF_LigatureAttach *attach;
914               int *num_class = alloca (sizeof (int) * mark_lig1->ClassCount);
915               int j;
916                                        
917               for (j = 0; j < mark_lig1->ClassCount; j++)
918                 num_class[j] = 0;
919
920               for (ligg = g - 1;
921                    (ligg >= gstring->glyphs
922                     && (IGNORED_GLYPH (ligg, flag)
923                         || ligg->GlyphClass > OTF_GlyphClassLigature));
924                    ligg--)
925                 if (ligg->positioning_type == 5
926                     && ligg->MarkAttachClass < mark_lig1->ClassCount)
927                   num_class[ligg->MarkAttachClass]++;
928               if (ligg < gstring->glyphs)
929                 continue;
930               coverage_idx_lig
931                 = get_coverage_index (&mark_lig1->LigatureCoverage,
932                                       ligg->glyph_id);
933               if (coverage_idx_lig < 0)
934                 continue;
935               mark_record = mark_lig1->MarkArray.MarkRecord + coverage_idx;
936               g->MarkAttachClass = mark_record->Class;
937               attach = (mark_lig1->LigatureArray.LigatureAttach
938                         + coverage_idx_lig);
939               for (j = 0; j < attach->ComponentCount; j++)
940                 {
941                   OTF_Anchor *lig_anchor
942                     = attach->ComponentRecord[j].LigatureAnchor;
943
944                   if (lig_anchor[mark_record->Class].AnchorFormat
945                       && num_class[mark_record->Class]-- == 0)
946                     {
947                       g->positioning_type = lookup_type;
948                       g->f.f5.mark_anchor = &mark_record->MarkAnchor;
949                       g->f.f5.ligature_anchor = lig_anchor + mark_record->Class;
950                       break;
951                     }
952                 }
953             }
954           break;
955
956         case 6:
957           if (gidx < 1)
958             continue;
959           if (subtable->Format == 1)
960             {
961               OTF_GPOS_MarkMark1 *mark_mark1 = &subtable->u.mark_mark1;
962               OTF_MarkRecord *mark1_record;
963               OTF_AnchorRecord *mark2_record;
964               OTF_Glyph *prevg;
965               int coverage_idx_base;
966
967               for (prevg = g - 1;
968                    prevg >= gstring->glyphs && IGNORED_GLYPH (prevg, flag);
969                    prevg--);
970               if (prevg < gstring->glyphs)
971                 continue;
972               coverage_idx_base
973                 = get_coverage_index (&mark_mark1->Mark2Coverage,
974                                       prevg->glyph_id);
975               if (coverage_idx_base < 0)
976                 continue;
977               mark1_record = mark_mark1->Mark1Array.MarkRecord + coverage_idx;
978               mark2_record
979                 = mark_mark1->Mark2Array.AnchorRecord + coverage_idx_base;
980               g->f.f6.mark1_anchor = &mark1_record->MarkAnchor;
981               g->f.f6.mark2_anchor
982                 = &mark2_record->Anchor[mark1_record->Class];
983               g->positioning_type = lookup_type;
984               break;
985             }
986           break;
987
988         case 7:
989           if (subtable->Format == 1)
990             {
991               OTF_GPOS_Context1 *context1 = &subtable->u.context1;
992               OTF_RuleSet *set = context1->RuleSet + coverage_idx;
993               OTF_Rule *rule;
994               int orig_used;
995               int j, k;
996
997               for (j = 0; j < set->RuleCount; j++)
998                 {
999                   rule = set->Rule + j;
1000                   if (match_ids (gstring, gidx + 1, flag,
1001                                  rule->GlyphCount - 1, rule->Input) < 0)
1002                     continue;
1003                   orig_used = gstring->used;
1004                   for (k = 0; k < rule->LookupCount; k++)
1005                     lookup_gpos (lookup_list,
1006                                  rule->LookupRecord[k].LookupListIndex,
1007                                  gstring,
1008                                  gidx + rule->LookupRecord[k].SequenceIndex);
1009                   gidx += rule->GlyphCount + (gstring->used - orig_used);
1010                   break;
1011                 }
1012             }
1013           else if (subtable->Format == 2)
1014             {
1015               OTF_GPOS_Context2 *context2 = &subtable->u.context2;
1016               OTF_ClassSet *set;
1017               OTF_ClassRule *rule;
1018               unsigned class;
1019               int orig_used;
1020               int j, k;
1021
1022               class = get_class_def (&context2->ClassDef, g->glyph_id);
1023               set = context2->ClassSet + class;
1024               if (set)
1025                 for (j = 0; j < set->ClassRuleCnt; j++)
1026                   {
1027                     rule = set->ClassRule + j;
1028                     if (match_classes (&context2->ClassDef,
1029                                        gstring, gidx + 1, flag,
1030                                        rule->GlyphCount - 1, rule->Class)
1031                         < 0)
1032                       continue;
1033                     orig_used = gstring->used;
1034                     for (k = 0; k < rule->LookupCount; k++)
1035                       lookup_gpos (lookup_list,
1036                                    rule->LookupRecord[k].LookupListIndex,
1037                                    gstring,
1038                                    gidx + rule->LookupRecord[k].SequenceIndex);
1039                     gidx += rule->GlyphCount + (gstring->used - orig_used);
1040                     break;
1041                   }
1042             }
1043           else                  /* subtable->Format == 3 */
1044             {
1045               OTF_GPOS_Context3 *context3 = &subtable->u.context3;
1046               int orig_used;
1047               int j;
1048
1049               if (match_coverages (gstring, gidx + 1, flag,
1050                                    context3->GlyphCount - 1,
1051                                    context3->Coverage + 1) < 0)
1052                 continue;
1053               orig_used = gstring->used;
1054               for (j = 0; j < context3->LookupCount; j++)
1055                 lookup_gpos (lookup_list,
1056                              context3->LookupRecord[j].LookupListIndex,
1057                              gstring,
1058                              gidx + context3->LookupRecord[j].SequenceIndex);
1059               gidx += context3->GlyphCount + (gstring->used - orig_used);
1060             }
1061           break;
1062
1063         case 8:
1064           if (subtable->Format == 1)
1065             {
1066               OTF_GPOS_ChainContext1 *context1 = &subtable->u.chain_context1;
1067               OTF_ChainRuleSet *set = context1->ChainRuleSet + coverage_idx;
1068               int orig_used;
1069               int j, k;
1070               
1071               for (j = 0; j < set->ChainRuleCount; j++)
1072                 {
1073                   OTF_ChainRule *rule = set->ChainRule + j;
1074
1075                   if (gidx < rule->BacktrackGlyphCount
1076                       || (gidx + rule->InputGlyphCount
1077                           + rule->LookaheadGlyphCount) > gstring->used)
1078                     continue;
1079                   if (match_chain_ids (gstring, gidx, flag, rule) < 0)
1080                     continue;
1081                   orig_used = gstring->used;
1082                   for (k = 0; k < rule->LookupCount; k++)
1083                     lookup_gpos (lookup_list,
1084                                  rule->LookupRecord[k].LookupListIndex,
1085                                  gstring,
1086                                  gidx + rule->LookupRecord[k].SequenceIndex);
1087                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
1088                   break;
1089                 }
1090             }
1091           else if (subtable->Format == 2)
1092             {
1093               OTF_GPOS_ChainContext2 *context2 = &subtable->u.chain_context2;
1094               OTF_ChainClassSet *set;
1095               unsigned class;
1096               int j;
1097               int orig_used;
1098
1099               class = get_class_def (&context2->InputClassDef, g->glyph_id);
1100               set = context2->ChainClassSet + class;
1101               for (j = 0; j < set->ChainClassRuleCnt; j++)
1102                 {
1103                   OTF_ChainClassRule *rule = set->ChainClassRule + j;
1104                   int k;
1105
1106                   if (gidx < rule->BacktrackGlyphCount
1107                       || (gidx + rule->InputGlyphCount
1108                           + rule->LookaheadGlyphCount) > gstring->used)
1109                     continue;
1110                   if (match_chain_classes (gstring, gidx, flag,
1111                                            &context2->BacktrackClassDef,
1112                                            &context2->InputClassDef,
1113                                            &context2->LookaheadClassDef,
1114                                            rule) < 0)
1115                     continue;
1116                   orig_used = gstring->used;
1117                   for (k = 0; k < rule->LookupCount; k++)
1118                     lookup_gpos (lookup_list,
1119                                  rule->LookupRecord[k].LookupListIndex,
1120                                  gstring,
1121                                  gidx + rule->LookupRecord[k].SequenceIndex);
1122                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
1123                   break;
1124                 }
1125             }
1126           else if (subtable->Format == 3)
1127             {
1128               OTF_GPOS_ChainContext3 *context3 = &subtable->u.chain_context3;
1129               int orig_used;
1130               int j;
1131
1132               if (gidx < context3->BacktrackGlyphCount
1133                   || (gidx + context3->InputGlyphCount
1134                       + context3->LookaheadGlyphCount) > gstring->used)
1135                 continue;
1136               if (match_chain_coverages (gstring, gidx, flag, context3) < 0)
1137                 continue;
1138               orig_used = gstring->used;
1139               for (j = 0; j < context3->LookupCount; j++)
1140                 lookup_gpos (lookup_list,
1141                              context3->LookupRecord[j].LookupListIndex,
1142                              gstring,
1143                              gidx + context3->LookupRecord[j].SequenceIndex);
1144               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
1145             }
1146           else
1147             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (invalid subformat)");
1148           break;
1149
1150         default:
1151           continue;
1152         }
1153     }
1154   if (gidx == orig_gidx)
1155     gidx++;
1156   return gidx;
1157 }
1158
1159 static int
1160 lookup_encoding_0 (OTF_EncodingSubtable0 *sub0, OTF_GlyphString *gstring)
1161 {
1162   int i, c;
1163
1164   for (i = 0; i < gstring->used; i++)
1165     {
1166       c = gstring->glyphs[i].c;
1167       if (c < 0 || c >= 256)
1168         gstring->glyphs[i].glyph_id = 0;
1169       else
1170         gstring->glyphs[i].glyph_id = sub0->glyphIdArray[c];
1171     }
1172   return 0;
1173 }
1174
1175 static int
1176 lookup_encoding_2 (OTF_EncodingSubtable2 *sub2, OTF_GlyphString *gstring)
1177 {
1178   return 0;
1179 }
1180
1181 static int
1182 lookup_encoding_4 (OTF_EncodingSubtable4 *sub4, OTF_GlyphString *gstring)
1183 {
1184   int i, j, c;
1185   int segCount = sub4->segCountX2 / 2;
1186
1187   for (i = 0; i < gstring->used; i++)
1188     {
1189       c = gstring->glyphs[i].c;
1190       if (c < 0)
1191         gstring->glyphs[i].glyph_id = 0;
1192       for (j = 0; j < segCount; j++)
1193         {
1194           OTF_cmapSegument *seg = sub4->segments + i;
1195
1196           if (c >= seg->startCount && c <= seg->endCount)
1197             {
1198               if (seg->idRangeOffset == 0xFFFF)
1199                 gstring->glyphs[i].glyph_id = c + seg->idDelta;
1200               else
1201                 gstring->glyphs[i].glyph_id
1202                   = sub4->glyphIdArray[seg->idRangeOffset
1203                                        + (c - seg->startCount)];
1204               break;
1205             }
1206         }
1207     }
1208
1209   return 0;
1210 }
1211
1212 static int
1213 lookup_encoding_6 (OTF_EncodingSubtable6 *sub6, OTF_GlyphString *gstring)
1214 {
1215   return 0;
1216 }
1217
1218 static int
1219 lookup_encoding_8 (OTF_EncodingSubtable8 *sub8, OTF_GlyphString *gstring)
1220 {
1221   return 0;
1222 }
1223
1224 static int
1225 lookup_encoding_10 (OTF_EncodingSubtable10 *sub10, OTF_GlyphString *gstring)
1226 {
1227   return 0;
1228 }
1229
1230 static int
1231 lookup_encoding_12 (OTF_EncodingSubtable12 *sub12, OTF_GlyphString *gstring)
1232 {
1233   return 0;
1234 }
1235
1236 \f
1237
1238 /* API */
1239
1240 int
1241 OTF_drive_cmap (OTF *otf, OTF_GlyphString *gstring)
1242 {
1243   OTF_cmap *cmap;
1244   int i;
1245
1246   if (! otf->cmap
1247       && OTF_get_table (otf, "cmap") < 0)
1248     return -1;
1249
1250   cmap = otf->cmap;
1251   for (i = 0; i < gstring->used; i++)
1252     if (! gstring->glyphs[i].glyph_id)
1253       {
1254         int c = gstring->glyphs[i].c;
1255         if (c < 32 || ! cmap->unicode_table)
1256           gstring->glyphs[i].glyph_id = 0;
1257         else
1258           gstring->glyphs[i].glyph_id = cmap->unicode_table[c];
1259       }
1260   return 0;
1261 }
1262
1263
1264 int
1265 OTF_drive_cmap2 (OTF *otf, OTF_GlyphString *gstring,
1266                  int platform_id, int encoding_id)
1267 {
1268   OTF_cmap *cmap;
1269   int i;
1270   char *errfmt = "CMAP Looking up%s";
1271   int errret = -1;
1272   OTF_EncodingRecord *enc;
1273
1274   if (! otf->cmap
1275       && OTF_get_table (otf, "cmap") < 0)
1276     return -1;
1277
1278   cmap = otf->cmap;
1279   for (i = 0; i < cmap->numTables; i++)
1280     if (cmap->EncodingRecord[i].platformID == platform_id
1281         && cmap->EncodingRecord[i].encodingID == encoding_id)
1282       break;
1283   if (i == cmap->numTables)
1284     OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (unknown platformID/encodingID)");
1285   enc = cmap->EncodingRecord + i;
1286   switch (enc->subtable.format)
1287     {
1288     case 0: return lookup_encoding_0 (enc->subtable.f.f0, gstring);
1289     case 2: return lookup_encoding_2 (enc->subtable.f.f2, gstring);
1290     case 4: return lookup_encoding_4 (enc->subtable.f.f4, gstring);
1291     case 6: return lookup_encoding_6 (enc->subtable.f.f6, gstring);
1292     case 8: return lookup_encoding_8 (enc->subtable.f.f8, gstring);
1293     case 10: return lookup_encoding_10 (enc->subtable.f.f10, gstring);
1294     case 12: return lookup_encoding_12 (enc->subtable.f.f12, gstring);
1295     }
1296   OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (invalid format)");
1297 }
1298
1299
1300 int
1301 OTF_get_unicode (OTF *otf, OTF_GlyphID code)
1302 {
1303   if (! otf->cmap
1304       && OTF_get_table (otf, "cmap") < 0)
1305     return 0;
1306   if (code == 0
1307       || code > otf->cmap->max_glyph_id
1308       || ! otf->cmap->decode_table)
1309     return 0;
1310   return otf->cmap->decode_table[code];
1311 }
1312
1313 int
1314 OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring)
1315 {
1316   OTF_GDEF *gdef;
1317   int i;
1318
1319   if (! otf->gdef
1320       && OTF_get_table (otf, "GDEF") < 0)
1321     return -1;
1322   gdef = otf->gdef;
1323
1324   if (gdef->glyph_class_def.offset)
1325     for (i = 0; i < gstring->used; i++)
1326       gstring->glyphs[i].GlyphClass
1327         = get_class_def (&gdef->glyph_class_def,
1328                          gstring->glyphs[i].glyph_id);
1329
1330   if (gdef->mark_attach_class_def.offset)
1331     for (i = 0; i < gstring->used; i++)
1332       gstring->glyphs[i].MarkAttachClass
1333         = get_class_def (&gdef->mark_attach_class_def,
1334                          gstring->glyphs[i].glyph_id);
1335
1336   return 0;
1337 }
1338
1339 static int
1340 OTF_drive_gsub_internal (OTF *otf, OTF_GlyphString *gstring,
1341                          char *script, char *language, char *features,
1342                          int alternate_subst)
1343 {
1344   char *errfmt = "GSUB driving%s";
1345   int errret = -1;
1346   OTF_GSUB *gsub;
1347   OTF_LangSys *LangSys;
1348   int *lookup_indices;
1349   int i, n;
1350
1351   for (i = 0; i < gstring->used; i++)
1352     gstring->glyphs[i].f.index.from = gstring->glyphs[i].f.index.to = i;
1353
1354   if (! otf->gsub
1355       && OTF_get_table (otf, "GSUB") < 0)
1356     return errret;
1357   gsub = otf->gsub;
1358   if (gsub->FeatureList.FeatureCount == 0
1359       || gsub->LookupList.LookupCount == 0)
1360     return 0;
1361
1362   LangSys = get_langsys (&gsub->ScriptList, script, language);
1363   if (! LangSys)
1364     return errret;
1365
1366   /* One lookup may be used by multiple features.  */
1367   lookup_indices = alloca (sizeof (int)
1368                            * gsub->LookupList.LookupCount
1369                            * (gsub->FeatureList.FeatureCount + 1));
1370   if (! lookup_indices)
1371     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
1372   n = setup_lookup_indices (&gsub->LookupList, &gsub->FeatureList,
1373                             features, lookup_indices);
1374   if (n < 0)
1375     return errret;
1376
1377   for (i = 0; i < n; i++)
1378     {
1379       int index = lookup_indices[i];
1380       int gidx;
1381
1382       if (gsub->LookupList.Lookup[index].LookupType != 8)
1383         {
1384           gidx = 0;
1385           while (gidx < gstring->used)
1386             {
1387               gidx = lookup_gsub (&gsub->LookupList, index, gstring, gidx,
1388                                   alternate_subst);
1389               if (gidx < 0)
1390                 return errret;
1391             }
1392         }
1393       else
1394         {
1395           gidx = gstring->used - 1;
1396           while (gidx >= 0)
1397             {
1398               gidx = lookup_gsub (&gsub->LookupList, index, gstring, gidx,
1399                                   alternate_subst);
1400               if (gidx < 0)
1401                 return errret;
1402             }
1403         }
1404     }
1405
1406   return 0;
1407 }
1408
1409 int
1410 OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring,
1411                 char *script, char *language, char *features)
1412 {
1413   return OTF_drive_gsub_internal (otf, gstring, script, language, features, 0);
1414 }
1415
1416 int
1417 OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring,
1418                 char *script, char *language, char *features)
1419 {
1420   char *errfmt = "GPOS driving%s";
1421   int errret = -1;
1422   OTF_GPOS *gpos;
1423   OTF_LangSys *LangSys;
1424   int *lookup_indices;
1425   int i, n;
1426
1427   if (! otf->gpos
1428       && OTF_get_table (otf, "GPOS") < 0)
1429     return errret;
1430   gpos = otf->gpos;
1431   if (gpos->FeatureList.FeatureCount == 0
1432       || gpos->LookupList.LookupCount == 0)
1433     return 0;
1434
1435   LangSys = get_langsys (&gpos->ScriptList, script, language);
1436   if (! LangSys)
1437     return errret;
1438
1439   /* One lookup may be used by multiple features.  */
1440   lookup_indices = alloca (sizeof (int)
1441                            * gpos->LookupList.LookupCount
1442                            * (gpos->FeatureList.FeatureCount + 1));
1443   if (! lookup_indices)
1444     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
1445   n = setup_lookup_indices (&gpos->LookupList, &gpos->FeatureList,
1446                             features, lookup_indices);
1447   if (n < 0)
1448     return errret;
1449
1450   for (i = 0; i < gstring->used; i++)
1451     gstring->glyphs[i].positioning_type = 0;
1452
1453   for (i = 0; i < n; i++)
1454     {
1455       int index = lookup_indices[i];
1456       int gidx = 0;
1457
1458       while (gidx < gstring->used)
1459         {
1460           gidx = lookup_gpos (&gpos->LookupList, index, gstring, gidx);
1461           if (gidx < 0)
1462             return errret;
1463         }
1464     }
1465
1466   return 0;
1467 }
1468
1469 int
1470 OTF_drive_tables (OTF *otf, OTF_GlyphString *gstring,
1471                   char *script, char *language,
1472                   char *gsub_features, char *gpos_features)
1473 {
1474   if (OTF_drive_cmap (otf, gstring) < 0)
1475     return -1;
1476   if (OTF_drive_gdef (otf, gstring) < 0)
1477     return -1;
1478   if (gsub_features
1479       && OTF_drive_gsub (otf, gstring, script, language, gsub_features) < 0)
1480     return -1;
1481   if (gpos_features
1482       && OTF_drive_gpos (otf, gstring, script, language, gpos_features) < 0)
1483     return -1;
1484   return 0;
1485 }
1486
1487 int
1488 OTF_drive_gsub_alternate (OTF *otf, OTF_GlyphString *gstring,
1489                           char *script, char *language, char *features)
1490 {
1491   return OTF_drive_gsub_internal (otf, gstring, script, language, features, 1);
1492 }