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