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