(IGNORED_GLYPH): Fix checking of MarkAttachClass.
[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        && ((flag) >> 8) != (g)->MarkAttachClass))
39
40 #define GSTRING_DELETE(gstring, from, len)                              \
41   do {                                                                  \
42     memmove (gstring->glyphs + from, gstring->glyphs + from + len,      \
43              sizeof (OTF_Glyph) * (gstring->used - from - len));        \
44     gstring->used -= len;                                               \
45   } while (0)
46
47
48 #define GSTRING_INSERT(gstring, pos, len)                               \
49   do {                                                                  \
50     if (gstring->used + len > gstring->size)                            \
51       {                                                                 \
52         char *errfmt = "GSTRING%s";                                     \
53                                                                         \
54         gstring->size = gstring->used + len;                            \
55         gstring->glyphs = (OTF_Glyph *) realloc (gstring->glyphs,       \
56                                                  gstring->size);        \
57         if (! gstring->glyphs)                                          \
58           OTF_ERROR (OTF_ERROR_MEMORY, "");                             \
59       }                                                                 \
60     memmove (gstring->glyphs + pos + len, gstring->glyphs + pos,        \
61              sizeof (OTF_Glyph) * (gstring->used - pos));               \
62     gstring->used += len;                                               \
63   } while (0)
64
65
66 static int
67 gstring_subst (OTF_GlyphString *gstring, int from, int to, int flag,
68                OTF_GlyphID *ids, int num)
69 {
70   int errret = -1;
71   int len = to - from;
72   int i;
73   int c = gstring->glyphs[from].c;
74   int from_idx = gstring->glyphs[from].f.index.from;
75   int to_idx = gstring->glyphs[to - 1].f.index.to;
76   int non_ignored_idx;
77
78   for (i = non_ignored_idx = to - 1; i >= from; i--)
79     {
80       OTF_Glyph *g = gstring->glyphs + i;
81       if (IGNORED_GLYPH (g, flag))
82         {
83           OTF_Glyph temp = *g;
84
85           memmove (g, g + 1, sizeof (OTF_Glyph) * (non_ignored_idx - i));
86           gstring->glyphs[non_ignored_idx--] = temp;
87           len--;
88         }
89     }
90
91   if (len < num)
92     GSTRING_INSERT (gstring, from, (num - len));
93   else if (len > num)
94     GSTRING_DELETE (gstring, from, (len - num));
95   for (i = 0; i < num; i++)
96     {
97       gstring->glyphs[from + i].c = c;
98       gstring->glyphs[from + i].glyph_id = ids[i];
99       gstring->glyphs[from + i].f.index.from = from_idx;
100       gstring->glyphs[from + i].f.index.to = to_idx;
101     }
102   return 0;
103 }
104
105 \f
106 static int
107 get_coverage_index (OTF_Coverage *coverage, OTF_GlyphID id)
108 {
109   int i;
110
111   if (coverage->CoverageFormat == 1)
112     {
113       for (i = 0; i < coverage->Count; i++)
114         if (coverage->table.GlyphArray[i] == id)
115           return i;
116     }
117   else
118     {
119       for (i = 0; i < coverage->Count; i++)
120         if (coverage->table.RangeRecord[i].Start <= id
121             && coverage->table.RangeRecord[i].End >= id)
122           return (coverage->table.RangeRecord[i].StartCoverageIndex
123                   + (id - coverage->table.RangeRecord[i].Start));
124     }
125   return -1;
126 }
127
128 static unsigned
129 get_class_def (OTF_ClassDef *class_def, OTF_GlyphID glyph_id)
130 {
131   if (class_def->ClassFormat == 1)
132     {
133       int idx = (int) glyph_id - (int) class_def->f.f1.StartGlyph;
134
135       if (idx >= 0 && idx < class_def->f.f1.GlyphCount)
136         return class_def->f.f1.ClassValueArray[idx];
137     }
138   else
139     {
140       int i;
141
142       for (i = 0; i < class_def->f.f2.ClassRangeCount; i++)
143         if (glyph_id >= class_def->f.f2.ClassRangeRecord[i].Start
144             && glyph_id <= class_def->f.f2.ClassRangeRecord[i].End)
145           return class_def->f.f2.ClassRangeRecord[i].Class;
146     }
147   return 0;
148 }
149
150 static OTF_LangSys *
151 get_langsys (OTF_ScriptList *script_list, char *script, char *language)
152 {
153
154   OTF_Tag script_tag = OTF_tag (script);
155   OTF_Tag langsys_tag = OTF_tag (language);
156   int i, j;
157   OTF_Tag dflt_tag = OTF_tag ("DFLT");
158   OTF_Script *dflt = NULL;
159
160   for (i = 0; i < script_list->ScriptCount; i++)
161     {
162       OTF_Script *script = script_list->Script + i;
163
164       if (script_list->Script[i].ScriptTag == dflt_tag)
165         dflt = script;
166       if (script_list->Script[i].ScriptTag == script_tag)
167         {
168           if (! langsys_tag)
169             return &script->DefaultLangSys;
170           for (j = 0; j < script->LangSysCount; j++)
171             if (script->LangSysRecord[j].LangSysTag == langsys_tag)
172               return script->LangSys + j;
173           return &script->DefaultLangSys;       
174         }
175     }
176
177   if (! dflt)
178     dflt = script_list->Script;
179   if (! langsys_tag)
180     return &dflt->DefaultLangSys;
181   for (j = 0; j < dflt->LangSysCount; j++)
182     if (dflt->LangSysRecord[j].LangSysTag == langsys_tag)
183       return dflt->LangSys + j;
184   return &dflt->DefaultLangSys; 
185 }
186
187 static int
188 setup_lookup_indices (OTF_LookupList *LookupList, OTF_FeatureList *FeatureList,
189                       char *features, int *lookup_indices)
190 {
191   int i, j, n = 0;
192   OTF_Feature *feature;
193   int *feature_table = alloca (sizeof (int) * FeatureList->FeatureCount);
194
195   for (i = 0; i < FeatureList->FeatureCount; i++)
196     feature_table[i] = 0;
197
198   while (*features)
199     {
200       char tagname[4];
201       OTF_Tag tag;
202       int use_it = 1;
203
204       if (*features == '*')
205         {
206           /* Consume all remaining features.  */
207           for (i = 0; i < FeatureList->FeatureCount; i++)
208             if (! feature_table[i])
209               {
210                 feature = FeatureList->Feature + i;
211                 for (j = 0; j < feature->LookupCount; j++)
212                   lookup_indices[n++] = feature->LookupListIndex[j];
213               }
214           break;
215         }
216
217       if (*features == '~')
218         use_it = -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 (feature_table[i])
233                 break;
234               if (use_it > 0)
235                 for (j = 0; j < feature->LookupCount; j++)
236                   lookup_indices[n++] = feature->LookupListIndex[j];
237               feature_table[i] = use_it;
238               break;
239             }
240         }
241     }
242
243   return n;
244 }
245
246 static int
247 match_ids (OTF_GlyphString *gstring, int gidx, int flag,
248            int count, OTF_GlyphID *ids)
249 {
250   OTF_Glyph *gbeg = gstring->glyphs + gidx;
251   OTF_Glyph *gend = gstring->glyphs + gstring->used;
252   OTF_Glyph *g;
253   int i;
254
255   for (g = gbeg, i = 0; g < gend && i < count; g++)
256     if (! IGNORED_GLYPH (g, flag) && g->glyph_id != ids[i++])
257       return -1;
258   return (i < count ? -1 : g - gbeg);
259 }
260
261 static int
262 match_chain_ids (OTF_GlyphString *gstring, int gidx, int flag,
263                  OTF_ChainRule *rule)
264 {
265   int i = rule->BacktrackGlyphCount;
266
267   if (i > 0)
268     {
269       int j;
270       OTF_Glyph *g;
271
272       for (j = gidx - 1, g = gstring->glyphs + j; j >= 0; j--, g--)
273         if (! IGNORED_GLYPH (g, flag) && --i == 0)
274           break;
275       if (i > 0)
276         return -1;
277       if (match_ids (gstring, j, flag,
278                      rule->BacktrackGlyphCount, rule->Backtrack)
279           < 0)
280         return -1;
281     }
282   gidx++;
283   i = match_ids (gstring, gidx, flag,
284                  rule->InputGlyphCount - 1, rule->Input);
285   if (i < 0)
286     return -1;
287   gidx += i;
288   i = match_ids (gstring, gidx, flag,
289                  rule->LookaheadGlyphCount, rule->LookAhead);
290   if (i < 0)
291     return -1;
292   return 0;
293 }
294
295 static int
296 match_classes (OTF_ClassDef *class_def, OTF_GlyphString *gstring, int gidx,
297                int flag, int count, unsigned *classes)
298 {
299   OTF_Glyph *gbeg = gstring->glyphs + gidx;
300   OTF_Glyph *gend = gstring->glyphs + gstring->used;
301   OTF_Glyph *g;
302   int i;
303
304   for (g = gbeg, i = 0; g < gend && i < count; g++)
305     if (! IGNORED_GLYPH (g, flag)
306         && get_class_def (class_def, g->glyph_id) != classes[i++])
307       return -1;
308   return (i < count ? -1 : g - gbeg);
309 }
310
311 static int
312 match_chain_classes (OTF_GlyphString *gstring, int gidx, int flag,
313                      OTF_ClassDef *BacktrackClassDef,
314                      OTF_ClassDef *InputClassDef,
315                      OTF_ClassDef *LookaheadClassDef,
316                      OTF_ChainClassRule *rule)
317 {
318   int i = rule->BacktrackGlyphCount;
319
320   if (i > 0)
321     {
322       int j;
323       OTF_Glyph *g;
324
325       for (j = gidx - 1, g = gstring->glyphs + j; j >= 0; j--, g--)
326         if (! IGNORED_GLYPH (g, flag) && i-- == 0)
327           break;
328       if (i > 0)
329         return -1;
330       if (match_classes (BacktrackClassDef, gstring, j, flag,
331                          rule->BacktrackGlyphCount, rule->Backtrack) < 0);
332       return -1;
333     }
334   gidx++;
335   i = match_classes (InputClassDef, gstring, gidx, flag,
336                      rule->InputGlyphCount - 1, rule->Input);
337   if (i < 0)
338     return -1;
339   gidx += i;
340   i = match_classes (LookaheadClassDef, gstring, gidx, flag,
341                      rule->LookaheadGlyphCount, rule->LookAhead);
342   if (i < 0)
343     return -1;
344   return 0;
345 }
346
347
348 static int
349 match_coverages (OTF_GlyphString *gstring, int gidx, int flag, int count,
350                  OTF_Coverage *coverages)
351 {
352   OTF_Glyph *gbeg = gstring->glyphs + gidx;
353   OTF_Glyph *gend = gstring->glyphs + gstring->used;
354   OTF_Glyph *g;
355   int i;
356
357   for (g = gbeg, i = 0; g < gend && i < count; g++)
358     if (! IGNORED_GLYPH (g, flag)
359         && get_coverage_index (coverages + i++, g->glyph_id) < 0)
360       return -1;
361   return (i < count ? -1 : g - gbeg);
362 }
363
364 static int
365 match_chain_coverages (OTF_GlyphString *gstring, int gidx, int flag,
366                        OTF_GSUB_ChainContext3 *context3)
367 {
368   int i = context3->BacktrackGlyphCount;
369
370   if (i > 0)
371     {
372       int j;
373       OTF_Glyph *g;
374
375       for (j = gidx - 1, g= gstring->glyphs +j; j >= 0; j--, g--)
376         if (! IGNORED_GLYPH (g, flag) && --i == 0)
377           break;
378       if (i > 0)
379         return -1;
380       if (match_coverages (gstring, j, flag, context3->BacktrackGlyphCount,
381                            context3->Backtrack) < 0)
382         return -1;
383     }
384   gidx++;
385   if (context3->InputGlyphCount > 1)
386     {
387       i = match_coverages (gstring, gidx, flag, context3->InputGlyphCount - 1,
388                            context3->Input + 1);
389       if (i < 0)
390         return -1;
391       gidx += i;
392     }
393   if (match_coverages (gstring, gidx, flag, context3->LookaheadGlyphCount,
394                        context3->LookAhead) < 0)
395     return -1;
396   return 0;
397 }
398
399 static int
400 lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
401              OTF_GlyphString *gstring, int gidx)
402 {
403   char *errfmt = "GSUB Looking up%s";
404   int errret = -1;
405   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
406   unsigned int flag = (lookup->LookupFlag
407                        & (OTF_LookupFlagIgnoreMask | OTF_MarkAttachmentType));
408   int orig_gidx = gidx;
409   OTF_Glyph *g = gstring->glyphs + gidx;
410   int i;
411
412   if (IGNORED_GLYPH (g, flag))
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
729                        & (OTF_LookupFlagIgnoreMask | OTF_MarkAttachmentType));
730   int orig_gidx = gidx;
731   OTF_Glyph *g = gstring->glyphs + gidx;
732   int i;
733
734   if (IGNORED_GLYPH (g, flag)
735       || g->positioning_type)
736     return (gidx + 1);
737
738   /* Try all subtables until one of them handles the current glyph.  */
739   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
740     {
741       unsigned lookup_type = lookup->LookupType;
742       OTF_LookupSubTableGPOS *subtable = lookup->SubTable.gpos + i;
743       int coverage_idx;
744
745       if (lookup_type == 9)
746         {
747           OTF_GPOS_Extension1 *extension1 = &subtable->u.extension1;
748
749           lookup_type = extension1->ExtensionLookupType;
750           subtable = extension1->ExtensionSubtable;
751         }
752
753       if (subtable->Coverage.offset)
754         {
755           coverage_idx = get_coverage_index (&subtable->Coverage,
756                                              g->glyph_id);
757           if (coverage_idx < 0)
758             continue;
759         }
760
761       switch (lookup_type)
762         {
763         case 1:
764           g->positioning_type = lookup_type;
765           if (subtable->Format == 1)
766             {
767               OTF_GPOS_Single1 *single1 = &subtable->u.single1;
768
769               g->f.f1.format = single1->ValueFormat;
770               g->f.f1.value = &single1->Value;
771             }
772           else if (subtable->Format == 2)
773             {
774               OTF_GPOS_Single2 *single2 = &subtable->u.single2;
775
776               g->f.f1.format = single2->ValueFormat;
777               g->f.f1.value = single2->Value + coverage_idx;
778             }
779           break;
780
781         case 2:
782           {
783             int next_gidx;
784             OTF_Glyph *nextg;
785
786             for (next_gidx = gidx + 1, nextg = gstring->glyphs + next_gidx;
787                  next_gidx < gstring->used && ! IGNORED_GLYPH (nextg, flag);
788                  next_gidx++, nextg++);
789
790             if (next_gidx >= gstring->used
791                 || nextg->positioning_type)
792               continue;
793             if (subtable->Format == 1)
794               {
795                 OTF_GPOS_Pair1 *pair1 = &subtable->u.pair1;
796                 OTF_PairSet *set = pair1->PairSet + coverage_idx;
797                 int j;
798
799                 for (j = 0; j < set->PairValueCount; j++)
800                   if (set->PairValueRecord[j].SecondGlyph == nextg->glyph_id)
801                     {
802                       if (pair1->ValueFormat1)
803                         {
804                           g->positioning_type = lookup_type;
805                           g->f.f2.format = pair1->ValueFormat1;
806                           g->f.f2.value = &set->PairValueRecord[j].Value1;
807                         }
808                       gidx = next_gidx;
809                       if (pair1->ValueFormat2)
810                         {
811                           nextg->positioning_type = lookup_type;
812                           nextg->f.f2.format = pair1->ValueFormat2;
813                           nextg->f.f2.value = &set->PairValueRecord[j].Value2;
814                           gidx++;
815                         }
816                       break;
817                     }
818               }
819             else if (subtable->Format == 2)
820               {
821                 OTF_GPOS_Pair2 *pair2 = &subtable->u.pair2;
822                 unsigned class1, class2;
823
824                 class1 = get_class_def (&pair2->ClassDef1, g->glyph_id);
825                 class2 = get_class_def (&pair2->ClassDef2, nextg->glyph_id);
826                 if (pair2->ValueFormat1)
827                   {
828                     g->positioning_type = lookup_type;
829                     g->f.f2.format = pair2->ValueFormat1;
830                     g->f.f2.value
831                       = &pair2->Class1Record[class1].Class2Record[class2].Value1;
832                   }
833                 gidx = next_gidx;
834                 if (pair2->ValueFormat2)
835                   {
836                     nextg->positioning_type = lookup_type;
837                     nextg->f.f2.format = pair2->ValueFormat2;
838                     nextg->f.f2.value
839                       = &pair2->Class1Record[class1].Class2Record[class2].Value2;
840                     gidx++;
841                   }
842               }
843           }
844           break;
845
846         case 3:
847           {
848             OTF_GPOS_Cursive1 *cursive1 = &subtable->u.cursive1;
849           
850             g->positioning_type = lookup_type;
851             g->f.f3.entry_anchor
852               = &cursive1->EntryExitRecord[coverage_idx].EntryAnchor;
853             g->f.f3.exit_anchor
854               = &cursive1->EntryExitRecord[coverage_idx].ExitAnchor;
855           }
856           break;
857
858         case 4:
859           if (gidx < 1)
860             continue;
861           if (subtable->Format == 1)
862             {
863               OTF_GPOS_MarkBase1 *mark_base1 = &subtable->u.mark_base1;
864               OTF_MarkRecord *mark_record;
865               OTF_AnchorRecord *base_record;
866               OTF_Glyph *baseg;
867               int coverage_idx_base;
868
869               for (baseg = g - 1;
870                    baseg >= gstring->glyphs && IGNORED_GLYPH (baseg, flag);
871                    baseg--);
872               if (baseg < gstring->glyphs)
873                 continue;
874               coverage_idx_base
875                 = get_coverage_index (&mark_base1->BaseCoverage,
876                                       baseg->glyph_id);
877               if (coverage_idx_base < 0)
878                 continue;
879               mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx;
880               base_record
881                 = mark_base1->BaseArray.AnchorRecord + coverage_idx_base;
882               g->f.f4.mark_anchor = &mark_record->MarkAnchor;
883               g->f.f4.base_anchor
884                 = &base_record->Anchor[mark_record->Class];
885               g->positioning_type = lookup_type;
886             }
887           break;
888
889         case 5:
890           if (gidx < 1)
891             continue;
892           if (subtable->Format == 1)
893             {
894               OTF_GPOS_MarkLig1 *mark_lig1 = &subtable->u.mark_lig1;
895               OTF_Glyph *ligg;
896               int coverage_idx_lig;
897               OTF_MarkRecord *mark_record;
898               OTF_LigatureAttach *attach;
899               int *num_class = alloca (sizeof (int) * mark_lig1->ClassCount);
900               int j;
901                                        
902               for (j = 0; j < mark_lig1->ClassCount; j++)
903                 num_class[j] = 0;
904
905               for (ligg = g - 1;
906                    ligg >= gstring->glyphs && IGNORED_GLYPH (ligg, flag);
907                    ligg--)
908                 if (ligg->positioning_type == 5
909                     && ligg->MarkAttachClass < mark_lig1->ClassCount)
910                   num_class[ligg->MarkAttachClass]++;
911               if (ligg < gstring->glyphs)
912                 continue;
913               coverage_idx_lig
914                 = get_coverage_index (&mark_lig1->LigatureCoverage,
915                                       ligg->glyph_id);
916               if (coverage_idx_lig < 0)
917                 continue;
918               mark_record = mark_lig1->MarkArray.MarkRecord + coverage_idx;
919               g->MarkAttachClass = mark_record->Class;
920               attach = (mark_lig1->LigatureArray.LigatureAttach
921                         + coverage_idx_lig);
922               for (j = 0; j < attach->ComponentCount; j++)
923                 {
924                   OTF_Anchor *lig_anchor
925                     = attach->ComponentRecord[j].LigatureAnchor;
926
927                   if (lig_anchor[mark_record->Class].AnchorFormat
928                       && num_class[mark_record->Class]-- == 0)
929                     {
930                       g->positioning_type = lookup_type;
931                       g->f.f5.mark_anchor = &mark_record->MarkAnchor;
932                       g->f.f5.ligature_anchor = lig_anchor + mark_record->Class;
933                       break;
934                     }
935                 }
936             }
937           break;
938
939         case 6:
940           if (gidx < 1)
941             continue;
942           if (subtable->Format == 1)
943             {
944               OTF_GPOS_MarkMark1 *mark_mark1 = &subtable->u.mark_mark1;
945               OTF_MarkRecord *mark1_record;
946               OTF_AnchorRecord *mark2_record;
947               OTF_Glyph *prevg;
948               int coverage_idx_base;
949
950               for (prevg = g - 1;
951                    prevg >= gstring->glyphs && IGNORED_GLYPH (prevg, flag);
952                    prevg--);
953               if (prevg < gstring->glyphs)
954                 continue;
955               coverage_idx_base
956                 = get_coverage_index (&mark_mark1->Mark2Coverage,
957                                       prevg->glyph_id);
958               if (coverage_idx_base < 0)
959                 continue;
960               mark1_record = mark_mark1->Mark1Array.MarkRecord + coverage_idx;
961               mark2_record
962                 = mark_mark1->Mark2Array.AnchorRecord + coverage_idx_base;
963               g->f.f6.mark1_anchor = &mark1_record->MarkAnchor;
964               g->f.f6.mark2_anchor
965                 = &mark2_record->Anchor[mark1_record->Class];
966               g->positioning_type = lookup_type;
967               break;
968             }
969           break;
970
971         case 7:
972           if (subtable->Format == 1)
973             {
974               OTF_GPOS_Context1 *context1 = &subtable->u.context1;
975               OTF_RuleSet *set = context1->RuleSet + coverage_idx;
976               OTF_Rule *rule;
977               int orig_used;
978               int j, k;
979
980               for (j = 0; j < set->RuleCount; j++)
981                 {
982                   rule = set->Rule + j;
983                   if (match_ids (gstring, gidx + 1, flag,
984                                  rule->GlyphCount - 1, rule->Input) < 0)
985                     continue;
986                   orig_used = gstring->used;
987                   for (k = 0; k < rule->LookupCount; k++)
988                     lookup_gpos (lookup_list,
989                                  rule->LookupRecord[k].LookupListIndex,
990                                  gstring,
991                                  gidx + rule->LookupRecord[k].SequenceIndex);
992                   gidx += rule->GlyphCount + (gstring->used - orig_used);
993                   break;
994                 }
995             }
996           else if (subtable->Format == 2)
997             {
998               OTF_GPOS_Context2 *context2 = &subtable->u.context2;
999               OTF_ClassSet *set;
1000               OTF_ClassRule *rule;
1001               unsigned class;
1002               int orig_used;
1003               int j, k;
1004
1005               class = get_class_def (&context2->ClassDef, g->glyph_id);
1006               set = context2->ClassSet + class;
1007               if (set)
1008                 for (j = 0; j < set->ClassRuleCnt; j++)
1009                   {
1010                     rule = set->ClassRule + j;
1011                     if (match_classes (&context2->ClassDef,
1012                                        gstring, gidx + 1, flag,
1013                                        rule->GlyphCount - 1, rule->Class)
1014                         < 0)
1015                       continue;
1016                     orig_used = gstring->used;
1017                     for (k = 0; k < rule->LookupCount; k++)
1018                       lookup_gpos (lookup_list,
1019                                    rule->LookupRecord[k].LookupListIndex,
1020                                    gstring,
1021                                    gidx + rule->LookupRecord[k].SequenceIndex);
1022                     gidx += rule->GlyphCount + (gstring->used - orig_used);
1023                     break;
1024                   }
1025             }
1026           else                  /* subtable->Format == 3 */
1027             {
1028               OTF_GPOS_Context3 *context3 = &subtable->u.context3;
1029               int orig_used;
1030               int j;
1031
1032               if (match_coverages (gstring, gidx + 1, flag,
1033                                    context3->GlyphCount - 1,
1034                                    context3->Coverage + 1) < 0)
1035                 continue;
1036               orig_used = gstring->used;
1037               for (j = 0; j < context3->LookupCount; j++)
1038                 lookup_gpos (lookup_list,
1039                              context3->LookupRecord[j].LookupListIndex,
1040                              gstring,
1041                              gidx + context3->LookupRecord[j].SequenceIndex);
1042               gidx += context3->GlyphCount + (gstring->used - orig_used);
1043             }
1044           break;
1045
1046         case 8:
1047           if (subtable->Format == 1)
1048             {
1049               OTF_GPOS_ChainContext1 *context1 = &subtable->u.chain_context1;
1050               OTF_ChainRuleSet *set = context1->ChainRuleSet + coverage_idx;
1051               int orig_used;
1052               int j, k;
1053               
1054               for (j = 0; j < set->ChainRuleCount; j++)
1055                 {
1056                   OTF_ChainRule *rule = set->ChainRule + j;
1057
1058                   if (gidx < rule->BacktrackGlyphCount
1059                       || (gidx + rule->InputGlyphCount
1060                           + rule->LookaheadGlyphCount) > gstring->used)
1061                     continue;
1062                   if (match_chain_ids (gstring, gidx, flag, rule) < 0)
1063                     continue;
1064                   orig_used = gstring->used;
1065                   for (k = 0; k < rule->LookupCount; k++)
1066                     lookup_gpos (lookup_list,
1067                                  rule->LookupRecord[k].LookupListIndex,
1068                                  gstring,
1069                                  gidx + rule->LookupRecord[k].SequenceIndex);
1070                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
1071                   break;
1072                 }
1073             }
1074           else if (subtable->Format == 2)
1075             {
1076               OTF_GPOS_ChainContext2 *context2 = &subtable->u.chain_context2;
1077               OTF_ChainClassSet *set;
1078               unsigned class;
1079               int j;
1080               int orig_used;
1081
1082               class = get_class_def (&context2->InputClassDef, g->glyph_id);
1083               set = context2->ChainClassSet + class;
1084               for (j = 0; j < set->ChainClassRuleCnt; j++)
1085                 {
1086                   OTF_ChainClassRule *rule = set->ChainClassRule + j;
1087                   int k;
1088
1089                   if (gidx < rule->BacktrackGlyphCount
1090                       || (gidx + rule->InputGlyphCount
1091                           + rule->LookaheadGlyphCount) > gstring->used)
1092                     continue;
1093                   if (match_chain_classes (gstring, gidx, flag,
1094                                            &context2->BacktrackClassDef,
1095                                            &context2->InputClassDef,
1096                                            &context2->LookaheadClassDef,
1097                                            rule) < 0)
1098                     continue;
1099                   orig_used = gstring->used;
1100                   for (k = 0; k < rule->LookupCount; k++)
1101                     lookup_gpos (lookup_list,
1102                                  rule->LookupRecord[k].LookupListIndex,
1103                                  gstring,
1104                                  gidx + rule->LookupRecord[k].SequenceIndex);
1105                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
1106                   break;
1107                 }
1108             }
1109           else if (subtable->Format == 3)
1110             {
1111               OTF_GPOS_ChainContext3 *context3 = &subtable->u.chain_context3;
1112               int orig_used;
1113               int j;
1114
1115               if (gidx < context3->BacktrackGlyphCount
1116                   || (gidx + context3->InputGlyphCount
1117                       + context3->LookaheadGlyphCount) > gstring->used)
1118                 continue;
1119               if (match_chain_coverages (gstring, gidx, flag, context3) < 0)
1120                 continue;
1121               orig_used = gstring->used;
1122               for (j = 0; j < context3->LookupCount; j++)
1123                 lookup_gpos (lookup_list,
1124                              context3->LookupRecord[j].LookupListIndex,
1125                              gstring,
1126                              gidx + context3->LookupRecord[j].SequenceIndex);
1127               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
1128             }
1129           else
1130             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (invalid subformat)");
1131           break;
1132
1133         default:
1134           continue;
1135         }
1136     }
1137   if (gidx == orig_gidx)
1138     gidx++;
1139   return gidx;
1140 }
1141
1142 static int
1143 lookup_encoding_0 (OTF_EncodingSubtable0 *sub0, OTF_GlyphString *gstring)
1144 {
1145   int i, c;
1146
1147   for (i = 0; i < gstring->used; i++)
1148     {
1149       c = gstring->glyphs[i].c;
1150       if (c < 0 || c >= 256)
1151         gstring->glyphs[i].glyph_id = 0;
1152       else
1153         gstring->glyphs[i].glyph_id = sub0->glyphIdArray[c];
1154     }
1155   return 0;
1156 }
1157
1158 static int
1159 lookup_encoding_2 (OTF_EncodingSubtable2 *sub2, OTF_GlyphString *gstring)
1160 {
1161   return 0;
1162 }
1163
1164 static int
1165 lookup_encoding_4 (OTF_EncodingSubtable4 *sub4, OTF_GlyphString *gstring)
1166 {
1167   int i, j, c;
1168   int segCount = sub4->segCountX2 / 2;
1169
1170   for (i = 0; i < gstring->used; i++)
1171     {
1172       c = gstring->glyphs[i].c;
1173       if (c < 0)
1174         gstring->glyphs[i].glyph_id = 0;
1175       for (j = 0; j < segCount; j++)
1176         {
1177           OTF_cmapSegument *seg = sub4->segments + i;
1178
1179           if (c >= seg->startCount && c <= seg->endCount)
1180             {
1181               if (seg->idRangeOffset == 0xFFFF)
1182                 gstring->glyphs[i].glyph_id = c + seg->idDelta;
1183               else
1184                 gstring->glyphs[i].glyph_id
1185                   = sub4->glyphIdArray[seg->idRangeOffset
1186                                        + (c - seg->startCount)];
1187               break;
1188             }
1189         }
1190     }
1191
1192   return 0;
1193 }
1194
1195 static int
1196 lookup_encoding_6 (OTF_EncodingSubtable6 *sub6, OTF_GlyphString *gstring)
1197 {
1198   return 0;
1199 }
1200
1201 static int
1202 lookup_encoding_8 (OTF_EncodingSubtable8 *sub8, OTF_GlyphString *gstring)
1203 {
1204   return 0;
1205 }
1206
1207 static int
1208 lookup_encoding_10 (OTF_EncodingSubtable10 *sub10, OTF_GlyphString *gstring)
1209 {
1210   return 0;
1211 }
1212
1213 static int
1214 lookup_encoding_12 (OTF_EncodingSubtable12 *sub12, OTF_GlyphString *gstring)
1215 {
1216   return 0;
1217 }
1218
1219 \f
1220
1221 /* API */
1222
1223 int
1224 OTF_drive_cmap (OTF *otf, OTF_GlyphString *gstring)
1225 {
1226   OTF_cmap *cmap;
1227   int i;
1228
1229   if (! otf->cmap
1230       && OTF_get_table (otf, "cmap") < 0)
1231     return -1;
1232
1233   cmap = otf->cmap;
1234   for (i = 0; i < gstring->used; i++)
1235     if (! gstring->glyphs[i].glyph_id)
1236       {
1237         int c = gstring->glyphs[i].c;
1238         if (c < 32 || ! cmap->unicode_table)
1239           gstring->glyphs[i].glyph_id = 0;
1240         else
1241           gstring->glyphs[i].glyph_id = cmap->unicode_table[c];
1242       }
1243   return 0;
1244 }
1245
1246
1247 int
1248 OTF_drive_cmap2 (OTF *otf, OTF_GlyphString *gstring,
1249                  int platform_id, int encoding_id)
1250 {
1251   OTF_cmap *cmap;
1252   int i;
1253   char *errfmt = "CMAP Looking up%s";
1254   int errret = -1;
1255   OTF_EncodingRecord *enc;
1256
1257   if (! otf->cmap
1258       && OTF_get_table (otf, "cmap") < 0)
1259     return -1;
1260
1261   cmap = otf->cmap;
1262   for (i = 0; i < cmap->numTables; i++)
1263     if (cmap->EncodingRecord[i].platformID == platform_id
1264         && cmap->EncodingRecord[i].encodingID == encoding_id)
1265       break;
1266   if (i == cmap->numTables)
1267     OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (unknown platformID/encodingID)");
1268   enc = cmap->EncodingRecord + i;
1269   switch (enc->subtable.format)
1270     {
1271     case 0: return lookup_encoding_0 (enc->subtable.f.f0, gstring);
1272     case 2: return lookup_encoding_2 (enc->subtable.f.f2, gstring);
1273     case 4: return lookup_encoding_4 (enc->subtable.f.f4, gstring);
1274     case 6: return lookup_encoding_6 (enc->subtable.f.f6, gstring);
1275     case 8: return lookup_encoding_8 (enc->subtable.f.f8, gstring);
1276     case 10: return lookup_encoding_10 (enc->subtable.f.f10, gstring);
1277     case 12: return lookup_encoding_12 (enc->subtable.f.f12, gstring);
1278     }
1279   OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (invalid format)");
1280 }
1281
1282
1283 int
1284 OTF_get_unicode (OTF *otf, OTF_GlyphID code)
1285 {
1286   if (! otf->cmap
1287       && OTF_get_table (otf, "cmap") < 0)
1288     return 0;
1289   if (code == 0
1290       || code > otf->cmap->max_glyph_id
1291       || ! otf->cmap->decode_table)
1292     return 0;
1293   return otf->cmap->decode_table[code];
1294 }
1295
1296 int
1297 OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring)
1298 {
1299   OTF_GDEF *gdef;
1300   int i;
1301
1302   if (! otf->gdef
1303       && OTF_get_table (otf, "GDEF") < 0)
1304     return -1;
1305   gdef = otf->gdef;
1306
1307   if (gdef->glyph_class_def.offset)
1308     for (i = 0; i < gstring->used; i++)
1309       gstring->glyphs[i].GlyphClass
1310         = get_class_def (&gdef->glyph_class_def,
1311                          gstring->glyphs[i].glyph_id);
1312
1313   if (gdef->mark_attach_class_def.offset)
1314     for (i = 0; i < gstring->used; i++)
1315       gstring->glyphs[i].MarkAttachClass
1316         = get_class_def (&gdef->mark_attach_class_def,
1317                          gstring->glyphs[i].glyph_id);
1318
1319   return 0;
1320 }
1321
1322
1323 int
1324 OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring,
1325                 char *script, char *language, char *features)
1326 {
1327   char *errfmt = "GSUB driving%s";
1328   int errret = -1;
1329   OTF_GSUB *gsub;
1330   OTF_LangSys *LangSys;
1331   int *lookup_indices;
1332   int i, n;
1333
1334   for (i = 0; i < gstring->used; i++)
1335     gstring->glyphs[i].f.index.from = gstring->glyphs[i].f.index.to = i;
1336
1337   if (! otf->gsub
1338       && OTF_get_table (otf, "GSUB") < 0)
1339     return errret;
1340   gsub = otf->gsub;
1341   if (gsub->FeatureList.FeatureCount == 0
1342       || gsub->LookupList.LookupCount == 0)
1343     return 0;
1344
1345   LangSys = get_langsys (&gsub->ScriptList, script, language);
1346   if (! LangSys)
1347     return errret;
1348
1349   /* One lookup may be used by multiple features.  */
1350   lookup_indices = alloca (sizeof (int)
1351                            * gsub->LookupList.LookupCount
1352                            * (gsub->FeatureList.FeatureCount + 1));
1353   if (! lookup_indices)
1354     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
1355   n = setup_lookup_indices (&gsub->LookupList, &gsub->FeatureList,
1356                             features, lookup_indices);
1357   if (n < 0)
1358     return errret;
1359
1360   for (i = 0; i < n; i++)
1361     {
1362       int index = lookup_indices[i];
1363       int gidx;
1364
1365       if (gsub->LookupList.Lookup[index].LookupType != 8)
1366         {
1367           gidx = 0;
1368           while (gidx < gstring->used)
1369             {
1370               gidx = lookup_gsub (&gsub->LookupList, index, gstring, gidx);
1371               if (gidx < 0)
1372                 return errret;
1373             }
1374         }
1375       else
1376         {
1377           gidx = gstring->used - 1;
1378           while (gidx >= 0)
1379             {
1380               gidx = lookup_gsub (&gsub->LookupList, index, gstring, gidx);
1381               if (gidx < 0)
1382                 return errret;
1383             }
1384         }
1385     }
1386
1387   return 0;
1388 }
1389
1390 int
1391 OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring,
1392                 char *script, char *language, char *features)
1393 {
1394   char *errfmt = "GPOS driving%s";
1395   int errret = -1;
1396   OTF_GPOS *gpos;
1397   OTF_LangSys *LangSys;
1398   int *lookup_indices;
1399   int i, n;
1400
1401   if (! otf->gpos
1402       && OTF_get_table (otf, "GPOS") < 0)
1403     return errret;
1404   gpos = otf->gpos;
1405   if (gpos->FeatureList.FeatureCount == 0
1406       || gpos->LookupList.LookupCount == 0)
1407     return 0;
1408
1409   LangSys = get_langsys (&gpos->ScriptList, script, language);
1410   if (! LangSys)
1411     return errret;
1412
1413   /* One lookup may be used by multiple features.  */
1414   lookup_indices = alloca (sizeof (int)
1415                            * gpos->LookupList.LookupCount
1416                            * (gpos->FeatureList.FeatureCount + 1));
1417   if (! lookup_indices)
1418     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
1419   n = setup_lookup_indices (&gpos->LookupList, &gpos->FeatureList,
1420                             features, lookup_indices);
1421   if (n < 0)
1422     return errret;
1423
1424   for (i = 0; i < gstring->used; i++)
1425     gstring->glyphs[i].positioning_type = 0;
1426
1427   for (i = 0; i < n; i++)
1428     {
1429       int index = lookup_indices[i];
1430       int gidx = 0;
1431
1432       while (gidx < gstring->used)
1433         {
1434           gidx = lookup_gpos (&gpos->LookupList, index, gstring, gidx);
1435           if (gidx < 0)
1436             return errret;
1437         }
1438     }
1439
1440   return 0;
1441 }
1442
1443 int
1444 OTF_drive_tables (OTF *otf, OTF_GlyphString *gstring,
1445                   char *script, char *language,
1446                   char *gsub_features, char *gpos_features)
1447 {
1448   if (OTF_drive_cmap (otf, gstring) < 0)
1449     return -1;
1450   if (OTF_drive_gdef (otf, gstring) < 0)
1451     return -1;
1452   if (gsub_features
1453       && OTF_drive_gsub (otf, gstring, script, language, gsub_features) < 0)
1454     return -1;
1455   if (gpos_features
1456       && OTF_drive_gpos (otf, gstring, script, language, gpos_features) < 0)
1457     return -1;
1458   return 0;
1459 }