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