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