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