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