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