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