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