(lookup_gpos): Ignore mark glyphs while
[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               unsigned int this_flag = flag | OTF_IgnoreMarks;
900
901               for (baseg = g - 1;
902                    baseg >= gstring->glyphs && IGNORED_GLYPH (baseg, this_flag);
903                    baseg--);
904               if (baseg < gstring->glyphs)
905                 continue;
906               coverage_idx_base
907                 = get_coverage_index (&mark_base1->BaseCoverage,
908                                       baseg->glyph_id);
909               if (coverage_idx_base < 0)
910                 continue;
911               mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx;
912               base_record
913                 = mark_base1->BaseArray.AnchorRecord + coverage_idx_base;
914               g->f.f4.mark_anchor = &mark_record->MarkAnchor;
915               g->f.f4.base_anchor
916                 = &base_record->Anchor[mark_record->Class];
917               g->positioning_type = lookup_type;
918             }
919           break;
920
921         case 5:
922           if (gidx < 1)
923             continue;
924           if (subtable->Format == 1)
925             {
926               OTF_GPOS_MarkLig1 *mark_lig1 = &subtable->u.mark_lig1;
927               OTF_Glyph *ligg;
928               int coverage_idx_lig;
929               OTF_MarkRecord *mark_record;
930               OTF_LigatureAttach *attach;
931               int *num_class = alloca (sizeof (int) * mark_lig1->ClassCount);
932               int j;
933                                        
934               for (j = 0; j < mark_lig1->ClassCount; j++)
935                 num_class[j] = 0;
936
937               for (ligg = g - 1;
938                    (ligg >= gstring->glyphs
939                     && (IGNORED_GLYPH (ligg, flag)
940                         || ligg->GlyphClass > OTF_GlyphClassLigature));
941                    ligg--)
942                 if (ligg->positioning_type == 5
943                     && ligg->MarkAttachClass < mark_lig1->ClassCount)
944                   num_class[ligg->MarkAttachClass]++;
945               if (ligg < gstring->glyphs)
946                 continue;
947               coverage_idx_lig
948                 = get_coverage_index (&mark_lig1->LigatureCoverage,
949                                       ligg->glyph_id);
950               if (coverage_idx_lig < 0)
951                 continue;
952               mark_record = mark_lig1->MarkArray.MarkRecord + coverage_idx;
953               g->MarkAttachClass = mark_record->Class;
954               attach = (mark_lig1->LigatureArray.LigatureAttach
955                         + coverage_idx_lig);
956               for (j = 0; j < attach->ComponentCount; j++)
957                 {
958                   OTF_Anchor *lig_anchor
959                     = attach->ComponentRecord[j].LigatureAnchor;
960
961                   if (lig_anchor[mark_record->Class].AnchorFormat
962                       && num_class[mark_record->Class]-- == 0)
963                     {
964                       g->positioning_type = lookup_type;
965                       g->f.f5.mark_anchor = &mark_record->MarkAnchor;
966                       g->f.f5.ligature_anchor = lig_anchor + mark_record->Class;
967                       break;
968                     }
969                 }
970             }
971           break;
972
973         case 6:
974           if (gidx < 1)
975             continue;
976           if (subtable->Format == 1)
977             {
978               OTF_GPOS_MarkMark1 *mark_mark1 = &subtable->u.mark_mark1;
979               OTF_MarkRecord *mark1_record;
980               OTF_AnchorRecord *mark2_record;
981               OTF_Glyph *prevg;
982               int coverage_idx_base;
983
984               for (prevg = g - 1;
985                    prevg >= gstring->glyphs && IGNORED_GLYPH (prevg, flag);
986                    prevg--);
987               if (prevg < gstring->glyphs)
988                 continue;
989               coverage_idx_base
990                 = get_coverage_index (&mark_mark1->Mark2Coverage,
991                                       prevg->glyph_id);
992               if (coverage_idx_base < 0)
993                 continue;
994               mark1_record = mark_mark1->Mark1Array.MarkRecord + coverage_idx;
995               mark2_record
996                 = mark_mark1->Mark2Array.AnchorRecord + coverage_idx_base;
997               g->f.f6.mark1_anchor = &mark1_record->MarkAnchor;
998               g->f.f6.mark2_anchor
999                 = &mark2_record->Anchor[mark1_record->Class];
1000               g->positioning_type = lookup_type;
1001               break;
1002             }
1003           break;
1004
1005         case 7:
1006           if (subtable->Format == 1)
1007             {
1008               OTF_GPOS_Context1 *context1 = &subtable->u.context1;
1009               OTF_RuleSet *set = context1->RuleSet + coverage_idx;
1010               OTF_Rule *rule;
1011               int orig_used;
1012               int j, k;
1013
1014               for (j = 0; j < set->RuleCount; j++)
1015                 {
1016                   rule = set->Rule + j;
1017                   if (match_ids (gstring, gidx + 1, flag,
1018                                  rule->GlyphCount - 1, rule->Input) < 0)
1019                     continue;
1020                   orig_used = gstring->used;
1021                   for (k = 0; k < rule->LookupCount; k++)
1022                     lookup_gpos (lookup_list,
1023                                  rule->LookupRecord[k].LookupListIndex,
1024                                  gstring,
1025                                  gidx + rule->LookupRecord[k].SequenceIndex);
1026                   gidx += rule->GlyphCount + (gstring->used - orig_used);
1027                   break;
1028                 }
1029             }
1030           else if (subtable->Format == 2)
1031             {
1032               OTF_GPOS_Context2 *context2 = &subtable->u.context2;
1033               OTF_ClassSet *set;
1034               OTF_ClassRule *rule;
1035               unsigned class;
1036               int orig_used;
1037               int j, k;
1038
1039               class = get_class_def (&context2->ClassDef, g->glyph_id);
1040               set = context2->ClassSet + class;
1041               if (set)
1042                 for (j = 0; j < set->ClassRuleCnt; j++)
1043                   {
1044                     rule = set->ClassRule + j;
1045                     if (match_classes (&context2->ClassDef,
1046                                        gstring, gidx + 1, flag,
1047                                        rule->GlyphCount - 1, rule->Class)
1048                         < 0)
1049                       continue;
1050                     orig_used = gstring->used;
1051                     for (k = 0; k < rule->LookupCount; k++)
1052                       lookup_gpos (lookup_list,
1053                                    rule->LookupRecord[k].LookupListIndex,
1054                                    gstring,
1055                                    gidx + rule->LookupRecord[k].SequenceIndex);
1056                     gidx += rule->GlyphCount + (gstring->used - orig_used);
1057                     break;
1058                   }
1059             }
1060           else                  /* subtable->Format == 3 */
1061             {
1062               OTF_GPOS_Context3 *context3 = &subtable->u.context3;
1063               int orig_used;
1064               int j;
1065
1066               if (match_coverages (gstring, gidx + 1, flag,
1067                                    context3->GlyphCount - 1,
1068                                    context3->Coverage + 1) < 0)
1069                 continue;
1070               orig_used = gstring->used;
1071               for (j = 0; j < context3->LookupCount; j++)
1072                 lookup_gpos (lookup_list,
1073                              context3->LookupRecord[j].LookupListIndex,
1074                              gstring,
1075                              gidx + context3->LookupRecord[j].SequenceIndex);
1076               gidx += context3->GlyphCount + (gstring->used - orig_used);
1077             }
1078           break;
1079
1080         case 8:
1081           if (subtable->Format == 1)
1082             {
1083               OTF_GPOS_ChainContext1 *context1 = &subtable->u.chain_context1;
1084               OTF_ChainRuleSet *set = context1->ChainRuleSet + coverage_idx;
1085               int orig_used;
1086               int j, k;
1087               
1088               for (j = 0; j < set->ChainRuleCount; j++)
1089                 {
1090                   OTF_ChainRule *rule = set->ChainRule + j;
1091
1092                   if (gidx < rule->BacktrackGlyphCount
1093                       || (gidx + rule->InputGlyphCount
1094                           + rule->LookaheadGlyphCount) > gstring->used)
1095                     continue;
1096                   if (match_chain_ids (gstring, gidx, flag, rule) < 0)
1097                     continue;
1098                   orig_used = gstring->used;
1099                   for (k = 0; k < rule->LookupCount; k++)
1100                     lookup_gpos (lookup_list,
1101                                  rule->LookupRecord[k].LookupListIndex,
1102                                  gstring,
1103                                  gidx + rule->LookupRecord[k].SequenceIndex);
1104                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
1105                   break;
1106                 }
1107             }
1108           else if (subtable->Format == 2)
1109             {
1110               OTF_GPOS_ChainContext2 *context2 = &subtable->u.chain_context2;
1111               OTF_ChainClassSet *set;
1112               unsigned class;
1113               int j;
1114               int orig_used;
1115
1116               class = get_class_def (&context2->InputClassDef, g->glyph_id);
1117               set = context2->ChainClassSet + class;
1118               for (j = 0; j < set->ChainClassRuleCnt; j++)
1119                 {
1120                   OTF_ChainClassRule *rule = set->ChainClassRule + j;
1121                   int k;
1122
1123                   if (gidx < rule->BacktrackGlyphCount
1124                       || (gidx + rule->InputGlyphCount
1125                           + rule->LookaheadGlyphCount) > gstring->used)
1126                     continue;
1127                   if (match_chain_classes (gstring, gidx, flag,
1128                                            &context2->BacktrackClassDef,
1129                                            &context2->InputClassDef,
1130                                            &context2->LookaheadClassDef,
1131                                            rule) < 0)
1132                     continue;
1133                   orig_used = gstring->used;
1134                   for (k = 0; k < rule->LookupCount; k++)
1135                     lookup_gpos (lookup_list,
1136                                  rule->LookupRecord[k].LookupListIndex,
1137                                  gstring,
1138                                  gidx + rule->LookupRecord[k].SequenceIndex);
1139                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
1140                   break;
1141                 }
1142             }
1143           else if (subtable->Format == 3)
1144             {
1145               OTF_GPOS_ChainContext3 *context3 = &subtable->u.chain_context3;
1146               int orig_used;
1147               int j;
1148
1149               if (gidx < context3->BacktrackGlyphCount
1150                   || (gidx + context3->InputGlyphCount
1151                       + context3->LookaheadGlyphCount) > gstring->used)
1152                 continue;
1153               if (match_chain_coverages (gstring, gidx, flag, context3) < 0)
1154                 continue;
1155               orig_used = gstring->used;
1156               for (j = 0; j < context3->LookupCount; j++)
1157                 lookup_gpos (lookup_list,
1158                              context3->LookupRecord[j].LookupListIndex,
1159                              gstring,
1160                              gidx + context3->LookupRecord[j].SequenceIndex);
1161               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
1162             }
1163           else
1164             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (invalid subformat)");
1165           break;
1166
1167         default:
1168           continue;
1169         }
1170     }
1171   if (gidx == orig_gidx)
1172     gidx++;
1173   return gidx;
1174 }
1175
1176 static int
1177 lookup_encoding_0 (OTF_EncodingSubtable0 *sub0, OTF_GlyphString *gstring)
1178 {
1179   int i, c;
1180
1181   for (i = 0; i < gstring->used; i++)
1182     {
1183       c = gstring->glyphs[i].c;
1184       if (c < 0 || c >= 256)
1185         gstring->glyphs[i].glyph_id = 0;
1186       else
1187         gstring->glyphs[i].glyph_id = sub0->glyphIdArray[c];
1188     }
1189   return 0;
1190 }
1191
1192 static int
1193 lookup_encoding_2 (OTF_EncodingSubtable2 *sub2, OTF_GlyphString *gstring)
1194 {
1195   return 0;
1196 }
1197
1198 static int
1199 lookup_encoding_4 (OTF_EncodingSubtable4 *sub4, OTF_GlyphString *gstring)
1200 {
1201   int i, j, c;
1202   int segCount = sub4->segCountX2 / 2;
1203
1204   for (i = 0; i < gstring->used; i++)
1205     {
1206       c = gstring->glyphs[i].c;
1207       if (c < 0)
1208         gstring->glyphs[i].glyph_id = 0;
1209       for (j = 0; j < segCount; j++)
1210         {
1211           OTF_cmapSegument *seg = sub4->segments + i;
1212
1213           if (c >= seg->startCount && c <= seg->endCount)
1214             {
1215               if (seg->idRangeOffset == 0xFFFF)
1216                 gstring->glyphs[i].glyph_id = c + seg->idDelta;
1217               else
1218                 gstring->glyphs[i].glyph_id
1219                   = sub4->glyphIdArray[seg->idRangeOffset
1220                                        + (c - seg->startCount)];
1221               break;
1222             }
1223         }
1224     }
1225
1226   return 0;
1227 }
1228
1229 static int
1230 lookup_encoding_6 (OTF_EncodingSubtable6 *sub6, OTF_GlyphString *gstring)
1231 {
1232   return 0;
1233 }
1234
1235 static int
1236 lookup_encoding_8 (OTF_EncodingSubtable8 *sub8, OTF_GlyphString *gstring)
1237 {
1238   return 0;
1239 }
1240
1241 static int
1242 lookup_encoding_10 (OTF_EncodingSubtable10 *sub10, OTF_GlyphString *gstring)
1243 {
1244   return 0;
1245 }
1246
1247 static int
1248 lookup_encoding_12 (OTF_EncodingSubtable12 *sub12, OTF_GlyphString *gstring)
1249 {
1250   return 0;
1251 }
1252
1253 \f
1254
1255 /* API */
1256
1257 int
1258 OTF_drive_cmap (OTF *otf, OTF_GlyphString *gstring)
1259 {
1260   OTF_cmap *cmap;
1261   int i;
1262
1263   if (! otf->cmap
1264       && OTF_get_table (otf, "cmap") < 0)
1265     return -1;
1266
1267   cmap = otf->cmap;
1268   for (i = 0; i < gstring->used; i++)
1269     if (! gstring->glyphs[i].glyph_id)
1270       {
1271         int c = gstring->glyphs[i].c;
1272         if (c < 32 || ! cmap->unicode_table)
1273           gstring->glyphs[i].glyph_id = 0;
1274         else
1275           gstring->glyphs[i].glyph_id = cmap->unicode_table[c];
1276       }
1277   return 0;
1278 }
1279
1280
1281 int
1282 OTF_drive_cmap2 (OTF *otf, OTF_GlyphString *gstring,
1283                  int platform_id, int encoding_id)
1284 {
1285   OTF_cmap *cmap;
1286   int i;
1287   char *errfmt = "CMAP Looking up%s";
1288   int errret = -1;
1289   OTF_EncodingRecord *enc;
1290
1291   if (! otf->cmap
1292       && OTF_get_table (otf, "cmap") < 0)
1293     return -1;
1294
1295   cmap = otf->cmap;
1296   for (i = 0; i < cmap->numTables; i++)
1297     if (cmap->EncodingRecord[i].platformID == platform_id
1298         && cmap->EncodingRecord[i].encodingID == encoding_id)
1299       break;
1300   if (i == cmap->numTables)
1301     OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (unknown platformID/encodingID)");
1302   enc = cmap->EncodingRecord + i;
1303   switch (enc->subtable.format)
1304     {
1305     case 0: return lookup_encoding_0 (enc->subtable.f.f0, gstring);
1306     case 2: return lookup_encoding_2 (enc->subtable.f.f2, gstring);
1307     case 4: return lookup_encoding_4 (enc->subtable.f.f4, gstring);
1308     case 6: return lookup_encoding_6 (enc->subtable.f.f6, gstring);
1309     case 8: return lookup_encoding_8 (enc->subtable.f.f8, gstring);
1310     case 10: return lookup_encoding_10 (enc->subtable.f.f10, gstring);
1311     case 12: return lookup_encoding_12 (enc->subtable.f.f12, gstring);
1312     }
1313   OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (invalid format)");
1314 }
1315
1316
1317 int
1318 OTF_get_unicode (OTF *otf, OTF_GlyphID code)
1319 {
1320   if (! otf->cmap
1321       && OTF_get_table (otf, "cmap") < 0)
1322     return 0;
1323   if (code == 0
1324       || code > otf->cmap->max_glyph_id
1325       || ! otf->cmap->decode_table)
1326     return 0;
1327   return otf->cmap->decode_table[code];
1328 }
1329
1330 int
1331 OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring)
1332 {
1333   OTF_GDEF *gdef;
1334   int i;
1335
1336   if (! otf->gdef
1337       && OTF_get_table (otf, "GDEF") < 0)
1338     return -1;
1339   gdef = otf->gdef;
1340
1341   if (gdef->glyph_class_def.offset)
1342     for (i = 0; i < gstring->used; i++)
1343       gstring->glyphs[i].GlyphClass
1344         = get_class_def (&gdef->glyph_class_def,
1345                          gstring->glyphs[i].glyph_id);
1346
1347   if (gdef->mark_attach_class_def.offset)
1348     for (i = 0; i < gstring->used; i++)
1349       gstring->glyphs[i].MarkAttachClass
1350         = get_class_def (&gdef->mark_attach_class_def,
1351                          gstring->glyphs[i].glyph_id);
1352
1353   return 0;
1354 }
1355
1356 static int
1357 OTF_drive_gsub_internal (OTF *otf, OTF_GlyphString *gstring,
1358                          const char *script, const char *language,
1359                          const char *features,
1360                          int alternate_subst)
1361 {
1362   char *errfmt = "GSUB driving%s";
1363   int errret = -1;
1364   OTF_GSUB *gsub;
1365   OTF_LangSys *LangSys;
1366   int *lookup_indices;
1367   int i, n;
1368
1369   for (i = 0; i < gstring->used; i++)
1370     {
1371       gstring->glyphs[i].positioning_type = 0;
1372       gstring->glyphs[i].f.index.from = gstring->glyphs[i].f.index.to = i;
1373     }
1374
1375   if (OTF_get_table (otf, "GSUB") < 0)
1376     return errret;
1377   gsub = otf->gsub;
1378   if (gsub->FeatureList.FeatureCount == 0
1379       || gsub->LookupList.LookupCount == 0)
1380     return 0;
1381
1382   LangSys = get_langsys (&gsub->ScriptList, script, language);
1383   if (! LangSys)
1384     return errret;
1385
1386   /* One lookup may be used by multiple features.  */
1387   lookup_indices = alloca (sizeof (int)
1388                            * gsub->LookupList.LookupCount
1389                            * (gsub->FeatureList.FeatureCount + 1));
1390   if (! lookup_indices)
1391     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
1392   n = setup_lookup_indices (&gsub->LookupList, &gsub->FeatureList,
1393                             features, lookup_indices);
1394   if (n < 0)
1395     return errret;
1396
1397   for (i = 0; i < n; i++)
1398     {
1399       int index = lookup_indices[i];
1400       int gidx;
1401
1402       if (gsub->LookupList.Lookup[index].LookupType != 8)
1403         {
1404           gidx = 0;
1405           while (gidx < gstring->used)
1406             {
1407               gidx = lookup_gsub (otf, &gsub->LookupList, index, gstring, gidx,
1408                                   alternate_subst);
1409               if (gidx < 0)
1410                 return errret;
1411             }
1412         }
1413       else
1414         {
1415           gidx = gstring->used - 1;
1416           while (gidx >= 0)
1417             {
1418               gidx = lookup_gsub (otf, &gsub->LookupList, index, gstring, gidx,
1419                                   alternate_subst);
1420               if (gidx < 0)
1421                 return errret;
1422             }
1423         }
1424     }
1425
1426   return 0;
1427 }
1428
1429 int
1430 OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring,
1431                 const char *script, const char *language, const char *features)
1432 {
1433   if (! otf->cmap)
1434     OTF_get_table (otf, "cmap");
1435   return OTF_drive_gsub_internal (otf, gstring, script, language, features, 0);
1436 }
1437
1438 int
1439 OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring,
1440                 const char *script, const char *language, const char *features)
1441 {
1442   char *errfmt = "GPOS driving%s";
1443   int errret = -1;
1444   OTF_GPOS *gpos;
1445   OTF_LangSys *LangSys;
1446   int *lookup_indices;
1447   int i, n;
1448
1449   for (i = 0; i < gstring->used; i++)
1450     gstring->glyphs[i].positioning_type = 0;
1451
1452   if (OTF_get_table (otf, "GPOS") < 0)
1453     return errret;
1454   gpos = otf->gpos;
1455   if (gpos->FeatureList.FeatureCount == 0
1456       || gpos->LookupList.LookupCount == 0)
1457     return 0;
1458
1459   LangSys = get_langsys (&gpos->ScriptList, script, language);
1460   if (! LangSys)
1461     return errret;
1462
1463   /* One lookup may be used by multiple features.  */
1464   lookup_indices = alloca (sizeof (int)
1465                            * gpos->LookupList.LookupCount
1466                            * (gpos->FeatureList.FeatureCount + 1));
1467   if (! lookup_indices)
1468     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
1469   n = setup_lookup_indices (&gpos->LookupList, &gpos->FeatureList,
1470                             features, lookup_indices);
1471   if (n < 0)
1472     return errret;
1473
1474   for (i = 0; i < n; i++)
1475     {
1476       int index = lookup_indices[i];
1477       int gidx = 0;
1478
1479       while (gidx < gstring->used)
1480         {
1481           gidx = lookup_gpos (&gpos->LookupList, index, gstring, gidx);
1482           if (gidx < 0)
1483             return errret;
1484         }
1485     }
1486
1487   return 0;
1488 }
1489
1490 int
1491 OTF_drive_tables (OTF *otf, OTF_GlyphString *gstring,
1492                   const char *script, const char *language,
1493                   const char *gsub_features, const char *gpos_features)
1494 {
1495   if (OTF_drive_cmap (otf, gstring) < 0)
1496     return -1;
1497   if (OTF_drive_gdef (otf, gstring) < 0)
1498     return -1;
1499   if (gsub_features
1500       && OTF_drive_gsub (otf, gstring, script, language, gsub_features) < 0)
1501     return -1;
1502   if (gpos_features
1503       && OTF_drive_gpos (otf, gstring, script, language, gpos_features) < 0)
1504     return -1;
1505   return 0;
1506 }
1507
1508 int
1509 OTF_drive_gsub_alternate (OTF *otf, OTF_GlyphString *gstring,
1510                           const char *script, const char *language,
1511                           const char *features)
1512 {
1513   return OTF_drive_gsub_internal (otf, gstring, script, language, features, 1);
1514 }