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