975e9693758619f1f34ded8694c91a1b2f623d37
[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)
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 (subtable->Coverage.offset)
433         {
434           coverage_idx = get_coverage_index (&subtable->Coverage,
435                                              g->glyph_id);
436           if (coverage_idx < 0)
437             continue;
438         }
439
440       switch (lookup_type)
441         {
442         case 1:
443           if (subtable->Format == 1)
444             g->glyph_id += subtable->u.single1.DeltaGlyphID;
445           else
446             g->glyph_id = subtable->u.single2.Substitute[coverage_idx];
447           gidx++;
448           break;
449
450         case 2:
451           {
452             OTF_GSUB_Multiple1 *multiple1 = &subtable->u.multiple1;
453             OTF_Sequence *seq = multiple1->Sequence + coverage_idx;
454
455             gstring_subst (gstring, gidx, gidx + 1, flag,
456                            seq->Substitute, seq->GlyphCount);
457             gidx += seq->GlyphCount;
458           }
459           break;
460
461         case 3:
462           /* For the moment, we always ignore this feature.  */
463           break;
464           if (subtable->Format == 1)
465             {
466               OTF_GSUB_Alternate1 *alt1 = &subtable->u.alternate1;
467               OTF_AlternateSet *altset = alt1->AlternateSet + coverage_idx;
468
469               g->glyph_id = altset->Alternate[0];
470               gidx++;
471             }
472           else
473             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
474           break;
475
476         case 4:
477           if (subtable->Format == 1)
478             {
479               OTF_GSUB_Ligature1 *lig1 = &subtable->u.ligature1;
480               OTF_LigatureSet *ligset = lig1->LigatureSet + coverage_idx;
481               OTF_Ligature *lig;
482               int j;
483
484               for (j = 0; j < ligset->LigatureCount; j++)
485                 {
486                   int n;
487
488                   lig = ligset->Ligature + j;
489                   n = match_ids (gstring, gidx + 1, flag,
490                                  lig->CompCount - 1, lig->Component);
491                   if (n < 0)
492                     continue;
493                   gstring_subst (gstring, gidx, gidx + 1 + n, flag,
494                                  &lig->LigGlyph, 1);
495                   gidx++;
496                   break;
497                 }
498             }
499           else
500             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
501           break;
502
503         case 5:
504           if (subtable->Format == 1)
505             {
506               OTF_GSUB_Context1 *context1 = &subtable->u.context1;
507               OTF_RuleSet *set = context1->RuleSet + coverage_idx;
508               OTF_Rule *rule;
509               int orig_used;
510               int j, k;
511
512               for (j = 0; j < set->RuleCount; j++)
513                 {
514                   rule = set->Rule + j;
515                   if (match_ids (gstring, gidx + 1, flag,
516                                  rule->GlyphCount - 1, rule->Input) < 0)
517                     continue;
518                   orig_used = gstring->used;
519                   for (k = 0; k < rule->LookupCount; k++)
520                     lookup_gsub (lookup_list,
521                                  rule->LookupRecord[k].LookupListIndex,
522                                  gstring,
523                                  gidx + rule->LookupRecord[k].SequenceIndex);
524                   gidx += rule->GlyphCount + (gstring->used - orig_used);
525                   break;
526                 }
527             }
528           else if (subtable->Format == 2)
529             {
530               OTF_GSUB_Context2 *context2 = &subtable->u.context2;
531               OTF_ClassSet *set;
532               OTF_ClassRule *rule;
533               unsigned class;
534               int orig_used;
535               int j, k;
536
537               class = get_class_def (&context2->ClassDef, g->glyph_id);
538               set = context2->ClassSet + class;
539               if (set)
540                 for (j = 0; j < set->ClassRuleCnt; j++)
541                   {
542                     rule = set->ClassRule + j;
543                     if (match_classes (&context2->ClassDef,
544                                        gstring, gidx + 1, flag,
545                                        rule->GlyphCount - 1, rule->Class)
546                         < 0)
547                       continue;
548                     orig_used = gstring->used;
549                     for (k = 0; k < rule->LookupCount; k++)
550                       lookup_gsub (lookup_list,
551                                    rule->LookupRecord[k].LookupListIndex,
552                                    gstring,
553                                    gidx + rule->LookupRecord[k].SequenceIndex);
554                     gidx += rule->GlyphCount + (gstring->used - orig_used);
555                     break;
556                   }
557             }
558           else                  /* subtable->Format == 3 */
559             {
560               OTF_GSUB_Context3 *context3 = &subtable->u.context3;
561               int orig_used;
562               int j;
563
564               if (match_coverages (gstring, gidx + 1, flag,
565                                    context3->GlyphCount - 1,
566                                    context3->Coverage + 1) < 0)
567                 continue;
568               orig_used = gstring->used;
569               for (j = 0; j < context3->LookupCount; j++)
570                 lookup_gsub (lookup_list,
571                              context3->LookupRecord[j].LookupListIndex,
572                              gstring,
573                              gidx + context3->LookupRecord[j].SequenceIndex);
574               gidx += context3->GlyphCount + (gstring->used - orig_used);
575             }
576           break;
577
578         case 6:
579           if (subtable->Format == 1)
580             {
581               OTF_GSUB_ChainContext1 *context1 = &subtable->u.chain_context1;
582               OTF_ChainRuleSet *set = context1->ChainRuleSet + coverage_idx;
583               int orig_used;
584               int j, k;
585               
586               for (j = 0; j < set->ChainRuleCount; j++)
587                 {
588                   OTF_ChainRule *rule = set->ChainRule + j;
589
590                   if (gidx < rule->BacktrackGlyphCount
591                       || (gidx + rule->InputGlyphCount
592                           + rule->LookaheadGlyphCount) > gstring->used)
593                     continue;
594                   if (match_chain_ids (gstring, gidx, flag, rule) < 0)
595                     continue;
596                   orig_used = gstring->used;
597                   for (k = 0; k < rule->LookupCount; k++)
598                     lookup_gsub (lookup_list,
599                                  rule->LookupRecord[k].LookupListIndex,
600                                  gstring,
601                                  gidx + rule->LookupRecord[k].SequenceIndex);
602                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
603                   break;
604                 }
605             }
606           else if (subtable->Format == 2)
607             {
608               OTF_GSUB_ChainContext2 *context2 = &subtable->u.chain_context2;
609               OTF_ChainClassSet *set;
610               unsigned class;
611               int j;
612               int orig_used;
613
614               class = get_class_def (&context2->InputClassDef, g->glyph_id);
615               set = context2->ChainClassSet + class;
616               for (j = 0; j < set->ChainClassRuleCnt; j++)
617                 {
618                   OTF_ChainClassRule *rule = set->ChainClassRule + j;
619                   int k;
620
621                   if (gidx < rule->BacktrackGlyphCount
622                       || (gidx + rule->InputGlyphCount
623                           + rule->LookaheadGlyphCount) > gstring->used)
624                     continue;
625                   if (match_chain_classes (gstring, gidx, flag,
626                                            &context2->BacktrackClassDef,
627                                            &context2->InputClassDef,
628                                            &context2->LookaheadClassDef,
629                                            rule) < 0)
630                     continue;
631                   orig_used = gstring->used;
632                   for (k = 0; k < rule->LookupCount; k++)
633                     lookup_gsub (lookup_list,
634                                  rule->LookupRecord[k].LookupListIndex,
635                                  gstring,
636                                  gidx + rule->LookupRecord[k].SequenceIndex);
637                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
638                   break;
639                 }
640             }
641           else
642             {
643               OTF_GSUB_ChainContext3 *context3 = &subtable->u.chain_context3;
644               int orig_used;
645               int j;
646
647               if (gidx < context3->BacktrackGlyphCount
648                   || (gidx + context3->InputGlyphCount
649                       + context3->LookaheadGlyphCount) > gstring->used)
650                 continue;
651               if (match_chain_coverages (gstring, gidx, flag, context3) < 0)
652                 continue;
653               orig_used = gstring->used;
654               for (j = 0; j < context3->LookupCount; j++)
655                 lookup_gsub (lookup_list,
656                              context3->LookupRecord[j].LookupListIndex,
657                              gstring,
658                              gidx + context3->LookupRecord[j].SequenceIndex);
659               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
660             }
661           break;
662
663         case 8:
664           {
665             OTF_GSUB_ReverseChain1 *reverse = &subtable->u.reverse_chain1;
666             int back_gidx = gidx + 1 + reverse->BacktrackGlyphCount;
667             int ahead_gidx = gidx - reverse->LookaheadGlyphCount;
668             int j;
669
670             if (back_gidx > gstring->used || ahead_gidx < 0)
671               break;
672
673             for (j = 0; j < reverse->BacktrackGlyphCount; j++)
674               if (get_coverage_index (reverse->Backtrack + j,
675                                       gstring->glyphs[gidx + 1 + j].glyph_id)
676                   < 0)
677                 break;
678             if (j < reverse->BacktrackGlyphCount)
679               continue;
680             for (j = 0; j < reverse->LookaheadGlyphCount; j++)
681               if (get_coverage_index (reverse->LookAhead + j,
682                                       gstring->glyphs[gidx - 1 - j].glyph_id)
683                   < 0)
684                 break;
685             if (j < reverse->LookaheadGlyphCount)
686               continue;
687             g->glyph_id = reverse->Substitute[coverage_idx];
688             gidx--;
689           }
690
691         default:
692           continue;
693         }
694     }
695   if (gidx == orig_gidx)
696     gidx++;
697   return gidx;
698 }
699
700 \f
701
702 /* GPOS */
703 unsigned
704 get_anchor (OTF_Anchor *anchor, OTF_ValueRecord *rec)
705 {
706   unsigned value_format = OTF_XPlacement | OTF_YPlacement;
707
708   rec->XPlacement = anchor->XCoordinate;
709   rec->YPlacement = anchor->YCoordinate;
710   if (anchor->AnchorFormat == 1)
711     /* Nothing to do */
712     ;
713   else if (anchor->AnchorFormat == 2)
714     /* Not yet implemented */
715     ;
716   else if (anchor->AnchorFormat == 3)
717     /* Not yet implemented */
718     ;
719   return value_format;
720 }
721
722
723 static int
724 lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
725              OTF_GlyphString *gstring, int gidx)
726 {
727   char *errfmt = "GPOS Looking up%s";
728   int errret = -1;
729   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
730   unsigned int flag = (lookup->LookupFlag
731                        & (OTF_LookupFlagIgnoreMask | OTF_MarkAttachmentType));
732   int orig_gidx = gidx;
733   OTF_Glyph *g = gstring->glyphs + gidx;
734   int i;
735
736   if (IGNORED_GLYPH (g, flag)
737       || g->positioning_type)
738     return (gidx + 1);
739
740   /* Try all subtables until one of them handles the current glyph.  */
741   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
742     {
743       unsigned lookup_type = lookup->LookupType;
744       OTF_LookupSubTableGPOS *subtable = lookup->SubTable.gpos + i;
745       int coverage_idx;
746
747       if (lookup_type == 9)
748         {
749           OTF_GPOS_Extension1 *extension1 = &subtable->u.extension1;
750
751           lookup_type = extension1->ExtensionLookupType;
752           subtable = extension1->ExtensionSubtable;
753         }
754
755       if (subtable->Coverage.offset)
756         {
757           coverage_idx = get_coverage_index (&subtable->Coverage,
758                                              g->glyph_id);
759           if (coverage_idx < 0)
760             continue;
761         }
762
763       switch (lookup_type)
764         {
765         case 1:
766           g->positioning_type = lookup_type;
767           if (subtable->Format == 1)
768             {
769               OTF_GPOS_Single1 *single1 = &subtable->u.single1;
770
771               g->f.f1.format = single1->ValueFormat;
772               g->f.f1.value = &single1->Value;
773             }
774           else if (subtable->Format == 2)
775             {
776               OTF_GPOS_Single2 *single2 = &subtable->u.single2;
777
778               g->f.f1.format = single2->ValueFormat;
779               g->f.f1.value = single2->Value + coverage_idx;
780             }
781           break;
782
783         case 2:
784           {
785             int next_gidx;
786             OTF_Glyph *nextg;
787
788             for (next_gidx = gidx + 1, nextg = gstring->glyphs + next_gidx;
789                  next_gidx < gstring->used && ! IGNORED_GLYPH (nextg, flag);
790                  next_gidx++, nextg++);
791
792             if (next_gidx >= gstring->used
793                 || nextg->positioning_type)
794               continue;
795             if (subtable->Format == 1)
796               {
797                 OTF_GPOS_Pair1 *pair1 = &subtable->u.pair1;
798                 OTF_PairSet *set = pair1->PairSet + coverage_idx;
799                 int j;
800
801                 for (j = 0; j < set->PairValueCount; j++)
802                   if (set->PairValueRecord[j].SecondGlyph == nextg->glyph_id)
803                     {
804                       if (pair1->ValueFormat1)
805                         {
806                           g->positioning_type = lookup_type;
807                           g->f.f2.format = pair1->ValueFormat1;
808                           g->f.f2.value = &set->PairValueRecord[j].Value1;
809                         }
810                       gidx = next_gidx;
811                       if (pair1->ValueFormat2)
812                         {
813                           nextg->positioning_type = lookup_type;
814                           nextg->f.f2.format = pair1->ValueFormat2;
815                           nextg->f.f2.value = &set->PairValueRecord[j].Value2;
816                           gidx++;
817                         }
818                       break;
819                     }
820               }
821             else if (subtable->Format == 2)
822               {
823                 OTF_GPOS_Pair2 *pair2 = &subtable->u.pair2;
824                 unsigned class1, class2;
825
826                 class1 = get_class_def (&pair2->ClassDef1, g->glyph_id);
827                 class2 = get_class_def (&pair2->ClassDef2, nextg->glyph_id);
828                 if (pair2->ValueFormat1)
829                   {
830                     g->positioning_type = lookup_type;
831                     g->f.f2.format = pair2->ValueFormat1;
832                     g->f.f2.value
833                       = &pair2->Class1Record[class1].Class2Record[class2].Value1;
834                   }
835                 gidx = next_gidx;
836                 if (pair2->ValueFormat2)
837                   {
838                     nextg->positioning_type = lookup_type;
839                     nextg->f.f2.format = pair2->ValueFormat2;
840                     nextg->f.f2.value
841                       = &pair2->Class1Record[class1].Class2Record[class2].Value2;
842                     gidx++;
843                   }
844               }
845           }
846           break;
847
848         case 3:
849           {
850             OTF_GPOS_Cursive1 *cursive1 = &subtable->u.cursive1;
851           
852             g->positioning_type = lookup_type;
853             g->f.f3.entry_anchor
854               = &cursive1->EntryExitRecord[coverage_idx].EntryAnchor;
855             g->f.f3.exit_anchor
856               = &cursive1->EntryExitRecord[coverage_idx].ExitAnchor;
857           }
858           break;
859
860         case 4:
861           if (gidx < 1)
862             continue;
863           if (subtable->Format == 1)
864             {
865               OTF_GPOS_MarkBase1 *mark_base1 = &subtable->u.mark_base1;
866               OTF_MarkRecord *mark_record;
867               OTF_AnchorRecord *base_record;
868               OTF_Glyph *baseg;
869               int coverage_idx_base;
870
871               for (baseg = g - 1;
872                    baseg >= gstring->glyphs && IGNORED_GLYPH (baseg, flag);
873                    baseg--);
874               if (baseg < gstring->glyphs)
875                 continue;
876               coverage_idx_base
877                 = get_coverage_index (&mark_base1->BaseCoverage,
878                                       baseg->glyph_id);
879               if (coverage_idx_base < 0)
880                 continue;
881               mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx;
882               base_record
883                 = mark_base1->BaseArray.AnchorRecord + coverage_idx_base;
884               g->f.f4.mark_anchor = &mark_record->MarkAnchor;
885               g->f.f4.base_anchor
886                 = &base_record->Anchor[mark_record->Class];
887               g->positioning_type = lookup_type;
888             }
889           break;
890
891         case 5:
892           if (gidx < 1)
893             continue;
894           if (subtable->Format == 1)
895             {
896               OTF_GPOS_MarkLig1 *mark_lig1 = &subtable->u.mark_lig1;
897               OTF_Glyph *ligg;
898               int coverage_idx_lig;
899               OTF_MarkRecord *mark_record;
900               OTF_LigatureAttach *attach;
901               int *num_class = alloca (sizeof (int) * mark_lig1->ClassCount);
902               int j;
903                                        
904               for (j = 0; j < mark_lig1->ClassCount; j++)
905                 num_class[j] = 0;
906
907               for (ligg = g - 1;
908                    ligg >= gstring->glyphs && IGNORED_GLYPH (ligg, flag);
909                    ligg--)
910                 if (ligg->positioning_type == 5
911                     && ligg->MarkAttachClass < mark_lig1->ClassCount)
912                   num_class[ligg->MarkAttachClass]++;
913               if (ligg < gstring->glyphs)
914                 continue;
915               coverage_idx_lig
916                 = get_coverage_index (&mark_lig1->LigatureCoverage,
917                                       ligg->glyph_id);
918               if (coverage_idx_lig < 0)
919                 continue;
920               mark_record = mark_lig1->MarkArray.MarkRecord + coverage_idx;
921               g->MarkAttachClass = mark_record->Class;
922               attach = (mark_lig1->LigatureArray.LigatureAttach
923                         + coverage_idx_lig);
924               for (j = 0; j < attach->ComponentCount; j++)
925                 {
926                   OTF_Anchor *lig_anchor
927                     = attach->ComponentRecord[j].LigatureAnchor;
928
929                   if (lig_anchor[mark_record->Class].AnchorFormat
930                       && num_class[mark_record->Class]-- == 0)
931                     {
932                       g->positioning_type = lookup_type;
933                       g->f.f5.mark_anchor = &mark_record->MarkAnchor;
934                       g->f.f5.ligature_anchor = lig_anchor + mark_record->Class;
935                       break;
936                     }
937                 }
938             }
939           break;
940
941         case 6:
942           if (gidx < 1)
943             continue;
944           if (subtable->Format == 1)
945             {
946               OTF_GPOS_MarkMark1 *mark_mark1 = &subtable->u.mark_mark1;
947               OTF_MarkRecord *mark1_record;
948               OTF_AnchorRecord *mark2_record;
949               OTF_Glyph *prevg;
950               int coverage_idx_base;
951
952               for (prevg = g - 1;
953                    prevg >= gstring->glyphs && IGNORED_GLYPH (prevg, flag);
954                    prevg--);
955               if (prevg < gstring->glyphs)
956                 continue;
957               coverage_idx_base
958                 = get_coverage_index (&mark_mark1->Mark2Coverage,
959                                       prevg->glyph_id);
960               if (coverage_idx_base < 0)
961                 continue;
962               mark1_record = mark_mark1->Mark1Array.MarkRecord + coverage_idx;
963               mark2_record
964                 = mark_mark1->Mark2Array.AnchorRecord + coverage_idx_base;
965               g->f.f6.mark1_anchor = &mark1_record->MarkAnchor;
966               g->f.f6.mark2_anchor
967                 = &mark2_record->Anchor[mark1_record->Class];
968               g->positioning_type = lookup_type;
969               break;
970             }
971           break;
972
973         case 7:
974           if (subtable->Format == 1)
975             {
976               OTF_GPOS_Context1 *context1 = &subtable->u.context1;
977               OTF_RuleSet *set = context1->RuleSet + coverage_idx;
978               OTF_Rule *rule;
979               int orig_used;
980               int j, k;
981
982               for (j = 0; j < set->RuleCount; j++)
983                 {
984                   rule = set->Rule + j;
985                   if (match_ids (gstring, gidx + 1, flag,
986                                  rule->GlyphCount - 1, rule->Input) < 0)
987                     continue;
988                   orig_used = gstring->used;
989                   for (k = 0; k < rule->LookupCount; k++)
990                     lookup_gpos (lookup_list,
991                                  rule->LookupRecord[k].LookupListIndex,
992                                  gstring,
993                                  gidx + rule->LookupRecord[k].SequenceIndex);
994                   gidx += rule->GlyphCount + (gstring->used - orig_used);
995                   break;
996                 }
997             }
998           else if (subtable->Format == 2)
999             {
1000               OTF_GPOS_Context2 *context2 = &subtable->u.context2;
1001               OTF_ClassSet *set;
1002               OTF_ClassRule *rule;
1003               unsigned class;
1004               int orig_used;
1005               int j, k;
1006
1007               class = get_class_def (&context2->ClassDef, g->glyph_id);
1008               set = context2->ClassSet + class;
1009               if (set)
1010                 for (j = 0; j < set->ClassRuleCnt; j++)
1011                   {
1012                     rule = set->ClassRule + j;
1013                     if (match_classes (&context2->ClassDef,
1014                                        gstring, gidx + 1, flag,
1015                                        rule->GlyphCount - 1, rule->Class)
1016                         < 0)
1017                       continue;
1018                     orig_used = gstring->used;
1019                     for (k = 0; k < rule->LookupCount; k++)
1020                       lookup_gpos (lookup_list,
1021                                    rule->LookupRecord[k].LookupListIndex,
1022                                    gstring,
1023                                    gidx + rule->LookupRecord[k].SequenceIndex);
1024                     gidx += rule->GlyphCount + (gstring->used - orig_used);
1025                     break;
1026                   }
1027             }
1028           else                  /* subtable->Format == 3 */
1029             {
1030               OTF_GPOS_Context3 *context3 = &subtable->u.context3;
1031               int orig_used;
1032               int j;
1033
1034               if (match_coverages (gstring, gidx + 1, flag,
1035                                    context3->GlyphCount - 1,
1036                                    context3->Coverage + 1) < 0)
1037                 continue;
1038               orig_used = gstring->used;
1039               for (j = 0; j < context3->LookupCount; j++)
1040                 lookup_gpos (lookup_list,
1041                              context3->LookupRecord[j].LookupListIndex,
1042                              gstring,
1043                              gidx + context3->LookupRecord[j].SequenceIndex);
1044               gidx += context3->GlyphCount + (gstring->used - orig_used);
1045             }
1046           break;
1047
1048         case 8:
1049           if (subtable->Format == 1)
1050             {
1051               OTF_GPOS_ChainContext1 *context1 = &subtable->u.chain_context1;
1052               OTF_ChainRuleSet *set = context1->ChainRuleSet + coverage_idx;
1053               int orig_used;
1054               int j, k;
1055               
1056               for (j = 0; j < set->ChainRuleCount; j++)
1057                 {
1058                   OTF_ChainRule *rule = set->ChainRule + j;
1059
1060                   if (gidx < rule->BacktrackGlyphCount
1061                       || (gidx + rule->InputGlyphCount
1062                           + rule->LookaheadGlyphCount) > gstring->used)
1063                     continue;
1064                   if (match_chain_ids (gstring, gidx, flag, rule) < 0)
1065                     continue;
1066                   orig_used = gstring->used;
1067                   for (k = 0; k < rule->LookupCount; k++)
1068                     lookup_gpos (lookup_list,
1069                                  rule->LookupRecord[k].LookupListIndex,
1070                                  gstring,
1071                                  gidx + rule->LookupRecord[k].SequenceIndex);
1072                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
1073                   break;
1074                 }
1075             }
1076           else if (subtable->Format == 2)
1077             {
1078               OTF_GPOS_ChainContext2 *context2 = &subtable->u.chain_context2;
1079               OTF_ChainClassSet *set;
1080               unsigned class;
1081               int j;
1082               int orig_used;
1083
1084               class = get_class_def (&context2->InputClassDef, g->glyph_id);
1085               set = context2->ChainClassSet + class;
1086               for (j = 0; j < set->ChainClassRuleCnt; j++)
1087                 {
1088                   OTF_ChainClassRule *rule = set->ChainClassRule + j;
1089                   int k;
1090
1091                   if (gidx < rule->BacktrackGlyphCount
1092                       || (gidx + rule->InputGlyphCount
1093                           + rule->LookaheadGlyphCount) > gstring->used)
1094                     continue;
1095                   if (match_chain_classes (gstring, gidx, flag,
1096                                            &context2->BacktrackClassDef,
1097                                            &context2->InputClassDef,
1098                                            &context2->LookaheadClassDef,
1099                                            rule) < 0)
1100                     continue;
1101                   orig_used = gstring->used;
1102                   for (k = 0; k < rule->LookupCount; k++)
1103                     lookup_gpos (lookup_list,
1104                                  rule->LookupRecord[k].LookupListIndex,
1105                                  gstring,
1106                                  gidx + rule->LookupRecord[k].SequenceIndex);
1107                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
1108                   break;
1109                 }
1110             }
1111           else if (subtable->Format == 3)
1112             {
1113               OTF_GPOS_ChainContext3 *context3 = &subtable->u.chain_context3;
1114               int orig_used;
1115               int j;
1116
1117               if (gidx < context3->BacktrackGlyphCount
1118                   || (gidx + context3->InputGlyphCount
1119                       + context3->LookaheadGlyphCount) > gstring->used)
1120                 continue;
1121               if (match_chain_coverages (gstring, gidx, flag, context3) < 0)
1122                 continue;
1123               orig_used = gstring->used;
1124               for (j = 0; j < context3->LookupCount; j++)
1125                 lookup_gpos (lookup_list,
1126                              context3->LookupRecord[j].LookupListIndex,
1127                              gstring,
1128                              gidx + context3->LookupRecord[j].SequenceIndex);
1129               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
1130             }
1131           else
1132             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (invalid subformat)");
1133           break;
1134
1135         default:
1136           continue;
1137         }
1138     }
1139   if (gidx == orig_gidx)
1140     gidx++;
1141   return gidx;
1142 }
1143
1144 static int
1145 lookup_encoding_0 (OTF_EncodingSubtable0 *sub0, OTF_GlyphString *gstring)
1146 {
1147   int i, c;
1148
1149   for (i = 0; i < gstring->used; i++)
1150     {
1151       c = gstring->glyphs[i].c;
1152       if (c < 0 || c >= 256)
1153         gstring->glyphs[i].glyph_id = 0;
1154       else
1155         gstring->glyphs[i].glyph_id = sub0->glyphIdArray[c];
1156     }
1157   return 0;
1158 }
1159
1160 static int
1161 lookup_encoding_2 (OTF_EncodingSubtable2 *sub2, OTF_GlyphString *gstring)
1162 {
1163   return 0;
1164 }
1165
1166 static int
1167 lookup_encoding_4 (OTF_EncodingSubtable4 *sub4, OTF_GlyphString *gstring)
1168 {
1169   int i, j, c;
1170   int segCount = sub4->segCountX2 / 2;
1171
1172   for (i = 0; i < gstring->used; i++)
1173     {
1174       c = gstring->glyphs[i].c;
1175       if (c < 0)
1176         gstring->glyphs[i].glyph_id = 0;
1177       for (j = 0; j < segCount; j++)
1178         {
1179           OTF_cmapSegument *seg = sub4->segments + i;
1180
1181           if (c >= seg->startCount && c <= seg->endCount)
1182             {
1183               if (seg->idRangeOffset == 0xFFFF)
1184                 gstring->glyphs[i].glyph_id = c + seg->idDelta;
1185               else
1186                 gstring->glyphs[i].glyph_id
1187                   = sub4->glyphIdArray[seg->idRangeOffset
1188                                        + (c - seg->startCount)];
1189               break;
1190             }
1191         }
1192     }
1193
1194   return 0;
1195 }
1196
1197 static int
1198 lookup_encoding_6 (OTF_EncodingSubtable6 *sub6, OTF_GlyphString *gstring)
1199 {
1200   return 0;
1201 }
1202
1203 static int
1204 lookup_encoding_8 (OTF_EncodingSubtable8 *sub8, OTF_GlyphString *gstring)
1205 {
1206   return 0;
1207 }
1208
1209 static int
1210 lookup_encoding_10 (OTF_EncodingSubtable10 *sub10, OTF_GlyphString *gstring)
1211 {
1212   return 0;
1213 }
1214
1215 static int
1216 lookup_encoding_12 (OTF_EncodingSubtable12 *sub12, OTF_GlyphString *gstring)
1217 {
1218   return 0;
1219 }
1220
1221 \f
1222
1223 /* API */
1224
1225 int
1226 OTF_drive_cmap (OTF *otf, OTF_GlyphString *gstring)
1227 {
1228   OTF_cmap *cmap;
1229   int i;
1230
1231   if (! otf->cmap
1232       && OTF_get_table (otf, "cmap") < 0)
1233     return -1;
1234
1235   cmap = otf->cmap;
1236   for (i = 0; i < gstring->used; i++)
1237     if (! gstring->glyphs[i].glyph_id)
1238       {
1239         int c = gstring->glyphs[i].c;
1240         if (c < 32 || ! cmap->unicode_table)
1241           gstring->glyphs[i].glyph_id = 0;
1242         else
1243           gstring->glyphs[i].glyph_id = cmap->unicode_table[c];
1244       }
1245   return 0;
1246 }
1247
1248
1249 int
1250 OTF_drive_cmap2 (OTF *otf, OTF_GlyphString *gstring,
1251                  int platform_id, int encoding_id)
1252 {
1253   OTF_cmap *cmap;
1254   int i;
1255   char *errfmt = "CMAP Looking up%s";
1256   int errret = -1;
1257   OTF_EncodingRecord *enc;
1258
1259   if (! otf->cmap
1260       && OTF_get_table (otf, "cmap") < 0)
1261     return -1;
1262
1263   cmap = otf->cmap;
1264   for (i = 0; i < cmap->numTables; i++)
1265     if (cmap->EncodingRecord[i].platformID == platform_id
1266         && cmap->EncodingRecord[i].encodingID == encoding_id)
1267       break;
1268   if (i == cmap->numTables)
1269     OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (unknown platformID/encodingID)");
1270   enc = cmap->EncodingRecord + i;
1271   switch (enc->subtable.format)
1272     {
1273     case 0: return lookup_encoding_0 (enc->subtable.f.f0, gstring);
1274     case 2: return lookup_encoding_2 (enc->subtable.f.f2, gstring);
1275     case 4: return lookup_encoding_4 (enc->subtable.f.f4, gstring);
1276     case 6: return lookup_encoding_6 (enc->subtable.f.f6, gstring);
1277     case 8: return lookup_encoding_8 (enc->subtable.f.f8, gstring);
1278     case 10: return lookup_encoding_10 (enc->subtable.f.f10, gstring);
1279     case 12: return lookup_encoding_12 (enc->subtable.f.f12, gstring);
1280     }
1281   OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (invalid format)");
1282 }
1283
1284
1285 int
1286 OTF_get_unicode (OTF *otf, OTF_GlyphID code)
1287 {
1288   if (! otf->cmap
1289       && OTF_get_table (otf, "cmap") < 0)
1290     return 0;
1291   if (code == 0
1292       || code > otf->cmap->max_glyph_id
1293       || ! otf->cmap->decode_table)
1294     return 0;
1295   return otf->cmap->decode_table[code];
1296 }
1297
1298 int
1299 OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring)
1300 {
1301   OTF_GDEF *gdef;
1302   int i;
1303
1304   if (! otf->gdef
1305       && OTF_get_table (otf, "GDEF") < 0)
1306     return -1;
1307   gdef = otf->gdef;
1308
1309   if (gdef->glyph_class_def.offset)
1310     for (i = 0; i < gstring->used; i++)
1311       gstring->glyphs[i].GlyphClass
1312         = get_class_def (&gdef->glyph_class_def,
1313                          gstring->glyphs[i].glyph_id);
1314
1315   if (gdef->mark_attach_class_def.offset)
1316     for (i = 0; i < gstring->used; i++)
1317       gstring->glyphs[i].MarkAttachClass
1318         = get_class_def (&gdef->mark_attach_class_def,
1319                          gstring->glyphs[i].glyph_id);
1320
1321   return 0;
1322 }
1323
1324
1325 int
1326 OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring,
1327                 char *script, char *language, char *features)
1328 {
1329   char *errfmt = "GSUB driving%s";
1330   int errret = -1;
1331   OTF_GSUB *gsub;
1332   OTF_LangSys *LangSys;
1333   int *lookup_indices;
1334   int i, n;
1335
1336   for (i = 0; i < gstring->used; i++)
1337     gstring->glyphs[i].f.index.from = gstring->glyphs[i].f.index.to = i;
1338
1339   if (! otf->gsub
1340       && OTF_get_table (otf, "GSUB") < 0)
1341     return errret;
1342   gsub = otf->gsub;
1343   if (gsub->FeatureList.FeatureCount == 0
1344       || gsub->LookupList.LookupCount == 0)
1345     return 0;
1346
1347   LangSys = get_langsys (&gsub->ScriptList, script, language);
1348   if (! LangSys)
1349     return errret;
1350
1351   /* One lookup may be used by multiple features.  */
1352   lookup_indices = alloca (sizeof (int)
1353                            * gsub->LookupList.LookupCount
1354                            * (gsub->FeatureList.FeatureCount + 1));
1355   if (! lookup_indices)
1356     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
1357   n = setup_lookup_indices (&gsub->LookupList, &gsub->FeatureList,
1358                             features, lookup_indices);
1359   if (n < 0)
1360     return errret;
1361
1362   for (i = 0; i < n; i++)
1363     {
1364       int index = lookup_indices[i];
1365       int gidx;
1366
1367       if (gsub->LookupList.Lookup[index].LookupType != 8)
1368         {
1369           gidx = 0;
1370           while (gidx < gstring->used)
1371             {
1372               gidx = lookup_gsub (&gsub->LookupList, index, gstring, gidx);
1373               if (gidx < 0)
1374                 return errret;
1375             }
1376         }
1377       else
1378         {
1379           gidx = gstring->used - 1;
1380           while (gidx >= 0)
1381             {
1382               gidx = lookup_gsub (&gsub->LookupList, index, gstring, gidx);
1383               if (gidx < 0)
1384                 return errret;
1385             }
1386         }
1387     }
1388
1389   return 0;
1390 }
1391
1392 int
1393 OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring,
1394                 char *script, char *language, char *features)
1395 {
1396   char *errfmt = "GPOS driving%s";
1397   int errret = -1;
1398   OTF_GPOS *gpos;
1399   OTF_LangSys *LangSys;
1400   int *lookup_indices;
1401   int i, n;
1402
1403   if (! otf->gpos
1404       && OTF_get_table (otf, "GPOS") < 0)
1405     return errret;
1406   gpos = otf->gpos;
1407   if (gpos->FeatureList.FeatureCount == 0
1408       || gpos->LookupList.LookupCount == 0)
1409     return 0;
1410
1411   LangSys = get_langsys (&gpos->ScriptList, script, language);
1412   if (! LangSys)
1413     return errret;
1414
1415   /* One lookup may be used by multiple features.  */
1416   lookup_indices = alloca (sizeof (int)
1417                            * gpos->LookupList.LookupCount
1418                            * (gpos->FeatureList.FeatureCount + 1));
1419   if (! lookup_indices)
1420     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
1421   n = setup_lookup_indices (&gpos->LookupList, &gpos->FeatureList,
1422                             features, lookup_indices);
1423   if (n < 0)
1424     return errret;
1425
1426   for (i = 0; i < gstring->used; i++)
1427     gstring->glyphs[i].positioning_type = 0;
1428
1429   for (i = 0; i < n; i++)
1430     {
1431       int index = lookup_indices[i];
1432       int gidx = 0;
1433
1434       while (gidx < gstring->used)
1435         {
1436           gidx = lookup_gpos (&gpos->LookupList, index, gstring, gidx);
1437           if (gidx < 0)
1438             return errret;
1439         }
1440     }
1441
1442   return 0;
1443 }
1444
1445 int
1446 OTF_drive_tables (OTF *otf, OTF_GlyphString *gstring,
1447                   char *script, char *language,
1448                   char *gsub_features, char *gpos_features)
1449 {
1450   if (OTF_drive_cmap (otf, gstring) < 0)
1451     return -1;
1452   if (OTF_drive_gdef (otf, gstring) < 0)
1453     return -1;
1454   if (gsub_features
1455       && OTF_drive_gsub (otf, gstring, script, language, gsub_features) < 0)
1456     return -1;
1457   if (gpos_features
1458       && OTF_drive_gpos (otf, gstring, script, language, gpos_features) < 0)
1459     return -1;
1460   return 0;
1461 }