f7b86b5935e795bb2a82e3422674b5e8ffb22b58
[m17n/libotf.git] / src / otfdrive.c
1 /* otfdrive.c -- OpenType font driver.
2
3 Copyright (C) 2003
4   by AIST (National Institute of Advanced Industrial Science and Technology)
5   Registration Number H15PRO???
6
7 This file is part of the OTF library.
8
9 The OTF library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2, or (at
12 your option) any later version.
13
14 The OTF library is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with the OTF library; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "otf.h"
29 #include "otferror.h"
30
31 #define GSTRING_DELETE(gstring, from, len)                              \
32   do {                                                                  \
33     memmove (gstring->glyphs + from, gstring->glyphs + from + len,      \
34              sizeof (OTF_Glyph) * (gstring->used - from - len));        \
35     gstring->used -= len;                                               \
36   } while (0)
37
38
39 #define GSTRING_INSERT(gstring, pos, len)                               \
40   do {                                                                  \
41     if (gstring->used + len > gstring->size)                            \
42       {                                                                 \
43         char *errfmt = "GSTRING%s";                                     \
44                                                                         \
45         gstring->size = gstring->used + len;                            \
46         gstring->glyphs = (OTF_Glyph *) realloc (gstring->glyphs,       \
47                                                  gstring->size);        \
48         if (! gstring->glyphs)                                          \
49           OTF_ERROR (OTF_ERROR_MEMORY, "");                             \
50       }                                                                 \
51     memmove (gstring->glyphs + pos + len, gstring->glyphs + pos,        \
52              sizeof (OTF_Glyph) * (gstring->used - pos));               \
53     gstring->used += len;                                               \
54   } while (0)
55
56
57 static int
58 gstring_subst (OTF_GlyphString *gstring, int from, int to,
59                OTF_GlyphID *ids, int num)
60 {
61   int errret = -1;
62   int len = to - from;
63   int i;
64
65   if (len < num)
66     GSTRING_INSERT (gstring, from, (num - len));
67   else if (len > num)
68     GSTRING_DELETE (gstring, from, (len - num));
69   for (i = 0; i < num; i++)
70     gstring->glyphs[from + i].glyph_id = ids[i];
71   return 0;
72 }
73
74 \f
75 static int
76 get_coverage_index (OTF_Coverage *coverage, OTF_GlyphID id)
77 {
78   int i;
79
80   if (coverage->CoverageFormat == 1)
81     {
82       for (i = 0; i < coverage->Count; i++)
83         if (coverage->table.GlyphArray[i] == id)
84           return i;
85     }
86   else
87     {
88       for (i = 0; i < coverage->Count; i++)
89         if (coverage->table.RangeRecord[i].Start <= id
90             && coverage->table.RangeRecord[i].End >= id)
91           return (coverage->table.RangeRecord[i].StartCoverageIndex
92                   + (id - coverage->table.RangeRecord[i].Start));
93     }
94   return -1;
95 }
96
97 static unsigned
98 get_class_def (OTF_ClassDef *class_def, OTF_GlyphID glyph_id)
99 {
100   if (class_def->ClassFormat == 1)
101     {
102       int idx = (int) glyph_id - (int) class_def->f.f1.StartGlyph;
103
104       if (idx >= 0 && idx < class_def->f.f1.GlyphCount)
105         return class_def->f.f1.ClassValueArray[idx];
106     }
107   else
108     {
109       int i;
110
111       for (i = 0; i < class_def->f.f2.ClassRangeCount; i++)
112         if (glyph_id >= class_def->f.f2.ClassRangeRecord[i].Start
113             && glyph_id <= class_def->f.f2.ClassRangeRecord[i].End)
114           return class_def->f.f2.ClassRangeRecord[i].Class;
115     }
116   return 0;
117 }
118
119 static OTF_LangSys *
120 get_langsys (OTF_ScriptList *script_list, char *script, char *language)
121 {
122
123   OTF_Tag script_tag = OTF_tag (script);
124   OTF_Tag langsys_tag = OTF_tag (language);
125   int i, j;
126
127   for (i = 0; i < script_list->ScriptCount; i++)
128     if (script_list->Script[i].ScriptTag == script_tag)
129       {
130         OTF_Script *script = script_list->Script + i;
131
132         if (! langsys_tag)
133           return &script->DefaultLangSys;
134         for (j = 0; j < script->LangSysCount; j++)
135           if (script->LangSysRecord[j].LangSysTag == langsys_tag)
136             return script->LangSys + j;
137         return &script->DefaultLangSys; 
138       }
139
140   return NULL;
141 }
142
143 static int
144 get_feature_index (OTF_LangSys *LangSys, OTF_FeatureList *FeatureList,
145                    char *features, int *feature_index)
146 {
147   int nfeatures = 0;
148
149   if (features)
150     {
151       char *p0, *p1;
152       int len = strlen (features) + 1;
153
154       p0 = alloca (len);
155       for (p1 = p0; *p1; p1++)
156         if (*p1 == ',')
157           *p1 = '\0';
158       
159       while (len > 0)
160         {
161           int this_len = strlen (p0) + 1;
162           OTF_Tag tag = OTF_tag (p0);
163
164           if (tag)
165             {
166               int i;
167
168               for (i = 0; i < FeatureList->FeatureCount; i++)
169                 if (tag == FeatureList->Feature[i].FeatureTag)
170                   {
171                     feature_index[nfeatures++] = i;
172                     if (nfeatures == FeatureList->FeatureCount)
173                       break;
174                   }
175             }
176           p0 += this_len;
177           len -= this_len;
178         }
179     }
180   else
181     {
182       for (; nfeatures < LangSys->FeatureCount; nfeatures++)
183         feature_index[nfeatures] = LangSys->FeatureIndex[nfeatures];
184     }
185
186   return nfeatures;
187 }
188
189 static int
190 match_ids (OTF_GlyphString *gstring, int gidx, int count, OTF_GlyphID *ids)
191 {
192   int i;
193
194   if (gstring->used - gidx < count)
195     return -1;
196   for (i = 0; i < count; i++)
197     if (gstring->glyphs[gidx + i].glyph_id != ids[i])
198       return -1;
199   return 0;
200 }
201
202 static int
203 match_classes (OTF_ClassDef *class_def, OTF_GlyphString *gstring, int gidx,
204                int count, unsigned *classes)
205 {
206   int i;
207
208   if (gstring->used - gidx < count)
209     return -1;
210   for (i = 0; i < count; i++)
211     if (get_class_def (class_def, gstring->glyphs[gidx + i].glyph_id)
212         != classes[i])
213       return -1;
214   return 0;
215 }
216
217 static int
218 lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
219              OTF_GlyphString *gstring, int gidx)
220 {
221   char *errfmt = "GSUB Looking up%s";
222   int errret = -1;
223   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
224   unsigned int flag = lookup->LookupFlag;
225   int orig_gidx = gidx;
226   OTF_Glyph *g = gstring->glyphs + gidx;
227   int i;
228
229   if (! g->glyph_id
230       || (g->GlyphClass
231           && (flag & (1 << g->GlyphClass))))
232     return (gidx + 1);
233
234   /* Try all subtables until one of them handles the current glyph.  */
235   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
236     {
237       OTF_LookupSubTableGSUB *subtable = lookup->SubTable.gsub + i;
238       int coverage_idx;
239
240       if (subtable->Coverage.offset)
241         {
242           coverage_idx = get_coverage_index (&subtable->Coverage,
243                                              g->glyph_id);
244           if (coverage_idx < 0)
245             continue;
246         }
247
248       switch (lookup->LookupType)
249         {
250         case 1:
251           if (subtable->Format == 1)
252             g->glyph_id += subtable->u.single1.DeltaGlyphID;
253           else
254             g->glyph_id = subtable->u.single2.Substitute[coverage_idx];
255           gidx++;
256           break;
257
258         case 2:
259           {
260             OTF_GSUB_Multiple1 *multiple1 = &subtable->u.multiple1;
261             OTF_Sequence *seq = multiple1->Sequence + coverage_idx;
262
263             gstring_subst (gstring, gidx, gidx + 1,
264                            seq->Substitute, seq->GlyphCount);
265             gidx += seq->GlyphCount;
266           }
267           break;
268
269         case 3:
270           if (subtable->Format == 1)
271             {
272               OTF_GSUB_Alternate1 *alt1 = &subtable->u.alternate1;
273               OTF_AlternateSet *altset = alt1->AlternateSet + coverage_idx;
274
275               g->glyph_id = altset->Alternate[0];
276               gidx++;
277             }
278           else
279             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
280           break;
281
282         case 4:
283           if (subtable->Format == 1)
284             {
285               OTF_GSUB_Ligature1 *lig1 = &subtable->u.ligature1;
286               OTF_LigatureSet *ligset = lig1->LigatureSet + coverage_idx;
287               OTF_Ligature *lig;
288               int j;
289
290               for (j = 0; j < ligset->LigatureCount; j++)
291                 {
292                   lig = ligset->Ligature + j;
293                   if (match_ids (gstring, gidx + 1,
294                                  lig->CompCount - 1, lig->Component) < 0)
295                     continue;
296                   gstring_subst (gstring, gidx, gidx + lig->CompCount,
297                                  &lig->LigGlyph, 1);
298                   gidx++;
299                   break;
300                 }
301             }
302           else
303             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
304           break;
305               
306         case 5:
307           if (subtable->Format == 1)
308             {
309               OTF_GSUB_Context1 *context1 = &subtable->u.context1; 
310               OTF_RuleSet *set = context1->RuleSet + coverage_idx;
311               OTF_Rule *rule;
312               int orig_used;
313               int j, k;
314
315               for (j = 0; j < set->RuleCount; j++)
316                 {
317                   rule = set->Rule + j;
318                   if (match_ids (gstring, gidx + 1,
319                                  rule->GlyphCount - 1, rule->Input) < 0)
320                     continue;
321                   orig_used = gstring->used;
322                   for (k = 0; k < rule->LookupCount; k++)
323                     lookup_gsub (lookup_list,
324                                  rule->LookupRecord[k].LookupListIndex,
325                                  gstring,
326                                  gidx + rule->LookupRecord[k].SequenceIndex);
327                   gidx += rule->GlyphCount + (gstring->used - orig_used);
328                   break;
329                 }
330             }
331           else if (subtable->Format == 2)
332             {
333               OTF_GSUB_Context2 *context2 = &subtable->u.context2; 
334               OTF_ClassSet *set;
335               OTF_ClassRule *rule;
336               unsigned class;
337               int orig_used;
338               int j, k;
339
340               class = get_class_def (&context2->ClassDef, g->glyph_id);
341               set = context2->ClassSet + class;
342               for (j = 0; j < set->ClassRuleCnt; j++)
343                 {
344                   rule = set->ClassRule + j;
345                   if (match_classes (&context2->ClassDef,
346                                      gstring, gidx + 1,
347                                      rule->GlyphCount - 1, rule->Class)
348                       < 0)
349                     continue;
350                   orig_used = gstring->used;
351                   for (k = 0; k < rule->LookupCount; k++)
352                     lookup_gsub (lookup_list,
353                                  rule->LookupRecord[k].LookupListIndex,
354                                  gstring,
355                                  gidx + rule->LookupRecord[k].SequenceIndex);
356                   gidx += rule->GlyphCount + (gstring->used - orig_used);
357                   break;
358                 }
359             }
360           else                  /* subtable->Format == 3 */
361             {
362               OTF_GSUB_Context3 *context3 = &subtable->u.context3; 
363               int orig_used;
364               int j, k;
365
366               if (gstring->used - gidx < context3->GlyphCount)
367                 continue;
368               /* Start from the secoding coverage_idx because the
369                  first one is the same as subtable->Coverage and thus
370                  already tested */
371               for (j = 1; j < context3->GlyphCount; j++)
372                 if (get_coverage_index (context3->Coverage + j,
373                                         gstring->glyphs[gidx + j].glyph_id)
374                     < 0)
375                   break;
376               if (j < context3->GlyphCount)
377                 continue;
378               orig_used = gstring->used;
379               for (k = 0; k < context3->LookupCount; k++)
380                 lookup_gsub (lookup_list,
381                              context3->LookupRecord[k].LookupListIndex,
382                              gstring,
383                              gidx + context3->LookupRecord[k].SequenceIndex);
384               gidx += context3->GlyphCount + (gstring->used - orig_used);
385             }
386           break;
387
388         case 6:
389           if (subtable->Format == 1)
390             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (not yet supported)");
391           else if (subtable->Format == 2)
392             {
393               OTF_GSUB_ChainContext2 *context2 = &subtable->u.chain_context2;
394               OTF_ChainClassSet *set;
395               unsigned class;
396               int j;
397               int orig_used;
398
399               // printf ("GSUB 6-2: c:0x%x g:0x%x\n", g->c, g->glyph_id);
400               class = get_class_def (&context2->InputClassDef, g->glyph_id);
401               set = context2->ChainClassSet + class;
402               for (j = 0; j < set->ChainClassRuleCnt; j++)
403                 {
404                   OTF_ChainClassRule *rule = set->ChainClassRule + j;
405                   int fore_idx = gidx + rule->InputGlyphCount;
406                   int k;
407
408                   if (gidx < rule->BacktrackGlyphCount
409                       || (gidx + rule->InputGlyphCount
410                           + rule->LookaheadGlyphCount) >= gstring->used)
411                     continue;
412                   for (k = 0; k < rule->BacktrackGlyphCount; k++)
413                     if (get_class_def (&context2->BacktrackClassDef,
414                                        gstring->glyphs[gidx - 1 - k].glyph_id)
415                         != rule->Backtrack[k])
416                       break;
417                   if (k < rule->BacktrackGlyphCount)
418                     continue;
419                   for (k = 1; k < rule->InputGlyphCount; k++)
420                     if (get_class_def (&context2->InputClassDef,
421                                        gstring->glyphs[gidx + k].glyph_id)
422                         != rule->Input[k - 1])
423                       break;
424                   if (k < rule->InputGlyphCount)
425                     continue;
426                   for (k = 0; k < rule->LookaheadGlyphCount; k++)
427                     if (get_class_def (&context2->LookaheadClassDef,
428                                        gstring->glyphs[fore_idx + k].glyph_id)
429                         != rule->LookAhead[k])
430                       break;
431                   if (k < rule->LookaheadGlyphCount)
432                     continue;
433
434                   orig_used = gstring->used;
435                   for (k = 0; k < rule->LookupCount; k++)
436                     lookup_gsub (lookup_list,
437                                  rule->LookupRecord[k].LookupListIndex,
438                                  gstring,
439                                  gidx + rule->LookupRecord[k].SequenceIndex);
440                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
441                   break;
442                 }
443             }
444           else
445             {
446               OTF_GSUB_ChainContext3 *context3 = &subtable->u.chain_context3;
447               int back_gidx = gidx - context3->BacktrackGlyphCount;
448               int fore_gidx = gidx + context3->InputGlyphCount;
449               int orig_used;
450               int j;
451
452               if (back_gidx < 0
453                   || fore_gidx + context3->LookaheadGlyphCount > gstring->used)
454                 break;
455
456               for (j = 0; j < context3->BacktrackGlyphCount; j++)
457                 if (get_coverage_index (context3->Backtrack + j,
458                                         gstring->glyphs[gidx - 1 - j].glyph_id)
459                     < 0)
460                   break;
461               if (j < context3->BacktrackGlyphCount)
462                 continue;
463
464               /* Start from the secode coverage_idx because the first
465                  one is the same as subtable->Coverage and thus
466                  already tested */
467               for (j = 1; j < context3->InputGlyphCount; j++)
468                 if (get_coverage_index (context3->Input + j,
469                                         gstring->glyphs[gidx + j].glyph_id)
470                     < 0)
471                   break;
472               if (j < context3->InputGlyphCount)
473                 continue;
474
475               for (j = 0; j < context3->LookaheadGlyphCount; j++)
476                 if (get_coverage_index (context3->LookAhead + j,
477                                         gstring->glyphs[fore_gidx + j].glyph_id)
478                     < 0)
479                   break;
480               if (j < context3->LookaheadGlyphCount)
481                 continue;
482
483               orig_used = gstring->used;
484               for (j = 0; j < context3->LookupCount; j++)
485                 lookup_gsub (lookup_list,
486                              context3->LookupRecord[j].LookupListIndex,
487                              gstring,
488                              gidx + context3->LookupRecord[j].SequenceIndex);
489               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
490             }
491           break;
492
493         default:
494           continue;
495         }
496     }
497   if (gidx == orig_gidx)
498     {
499       //printf ("not applied\n");
500       gidx++;
501     }
502   else
503     {
504       // printf ("done\n");
505     }
506   return gidx;
507 }
508
509 \f
510
511 /* GPOS */
512 unsigned
513 get_anchor (OTF_Anchor *anchor, OTF_ValueRecord *rec)
514 {
515   unsigned value_format = OTF_XPlacement | OTF_YPlacement;
516
517   rec->XPlacement = anchor->XCoordinate;
518   rec->YPlacement = anchor->YCoordinate;
519   if (anchor->AnchorFormat == 1)
520     /* Nothing to do */
521     ;
522   else if (anchor->AnchorFormat == 2)
523     /* Not yet implemented */
524     ;
525   else if (anchor->AnchorFormat == 3)
526     /* Not yet implemented */
527     ;
528   return value_format;
529 }
530
531
532 static int
533 lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
534              OTF_GlyphString *gstring, int gidx)
535 {
536   char *errfmt = "GPOS Looking up%s";
537   int errret = -1;
538   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
539   unsigned int flag = lookup->LookupFlag;
540   int orig_gidx = gidx;
541   OTF_Glyph *g = gstring->glyphs + gidx;
542   int i;
543
544   if (! g->glyph_id
545       || (g->GlyphClass
546           && (flag & (1 << g->GlyphClass))))
547     return (gidx + 1);
548
549   /* Try all subtables until one of them handles the current glyph.  */
550   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
551     {
552       OTF_LookupSubTableGPOS *subtable = lookup->SubTable.gpos + i;
553       int coverage_idx;
554
555       // printf ("subtype:%d ", subtable->Format);
556       if (subtable->Coverage.offset)
557         {
558           coverage_idx = get_coverage_index (&subtable->Coverage,
559                                              g->glyph_id);
560           if (coverage_idx < 0)
561             {
562               // printf ("not covererd ");
563               continue;
564             }
565         }
566
567       switch (lookup->LookupType)
568         {
569         case 1:
570           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
571
572         case 2:
573           if (gidx + 1 >= gstring->used)
574             continue;
575           if (subtable->Format == 1)
576             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
577           else if (subtable->Format == 2)
578             {
579               OTF_GPOS_Pair2 *pair2 = &subtable->u.pair2;
580               unsigned class1, class2;
581
582               // printf ("GPOS 2-2: c:0x%x g:0x%x\n", g->c, g->glyph_id);
583               gidx++;
584               class1 = get_class_def (&pair2->ClassDef1, g->glyph_id);
585               class2 = get_class_def (&pair2->ClassDef2, g[1].glyph_id);
586               g->positioning_type = lookup->LookupType;
587               g->f.f2.format = pair2->ValueFormat1;
588               g->f.f2.value
589                 = &pair2->Class1Record[class1].Class2Record[class2].Value1;
590               if (pair2->ValueFormat2)
591                 {
592                   g++, gidx++;
593                   g->positioning_type = lookup->LookupType;
594                   g->f.f2.format = pair2->ValueFormat2;
595                   g->f.f2.value
596                     = &pair2->Class1Record[class1].Class2Record[class2].Value2;
597                 }
598             }
599           break;
600
601         case 3:
602           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
603
604         case 4:
605           if (gidx < 1)
606             continue;
607           if (subtable->Format == 1)
608             {
609               OTF_GPOS_MarkBase1 *mark_base1 = &subtable->u.mark_base1;
610               OTF_MarkRecord *mark_record;
611               OTF_AnchorRecord *base_record;
612               int coverage_idx_base
613                 = get_coverage_index (&mark_base1->BaseCoverage,
614                                       g[-1].glyph_id);
615
616               if (coverage_idx_base < 0)
617                 continue;
618               // printf ("GPOS 4-1: c:0x%x g:0x%x\n", g->c, g->glyph_id);
619               mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx;
620               base_record
621                 = mark_base1->BaseArray.AnchorRecord + coverage_idx_base;
622               g->f.f4.mark_anchor = &mark_record->MarkAnchor;
623               g->f.f4.base_anchor
624                 = &base_record->Anchor[mark_record->Class];
625               g->positioning_type = lookup->LookupType;
626               break;
627             }
628           else
629             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
630           break;
631               
632         case 5:
633           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
634           break;
635
636         case 6:
637           if (gidx < 1)
638             continue;
639           if (subtable->Format == 1)
640             {
641               OTF_GPOS_MarkMark1 *mark_mark1 = &subtable->u.mark_mark1;
642               OTF_MarkRecord *mark1_record;
643               OTF_AnchorRecord *mark2_record;
644               int coverage_idx_base
645                 = get_coverage_index (&mark_mark1->Mark2Coverage,
646                                       g[-1].glyph_id);
647
648               if (coverage_idx_base < 0)
649                 continue;
650               // printf ("GPOS 6-1: c:0x%x g:0x%x\n", g->c, g->glyph_id);
651               mark1_record = mark_mark1->Mark1Array.MarkRecord + coverage_idx;
652               mark2_record
653                 = mark_mark1->Mark2Array.AnchorRecord + coverage_idx_base;
654               g->f.f6.mark1_anchor = &mark1_record->MarkAnchor;
655               g->f.f6.mark2_anchor
656                 = &mark2_record->Anchor[mark1_record->Class];
657               g->positioning_type = lookup->LookupType;
658               break;
659             }
660           else
661             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
662           break;
663
664         case 7:
665           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
666           break;
667
668         case 8:
669           if (subtable->Format == 1)
670             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
671           else if (subtable->Format == 2)
672             {
673               OTF_GPOS_ChainContext2 *context2 = &subtable->u.chain_context2;
674               OTF_ChainClassSet *set;
675               unsigned class;
676               int j;
677               int orig_used;
678
679               // printf ("GPOS 8-2: c:0x%x g:0x%x\n", g->c, g->glyph_id);
680               class = get_class_def (&context2->InputClassDef, g->glyph_id);
681               set = context2->ChainClassSet + class;
682               for (j = 0; j < set->ChainClassRuleCnt; j++)
683                 {
684                   OTF_ChainClassRule *rule = set->ChainClassRule + j;
685                   int fore_idx = gidx + rule->InputGlyphCount;
686                   int k;
687
688                   if (gidx < rule->BacktrackGlyphCount
689                       || (gidx + rule->InputGlyphCount
690                           + rule->LookaheadGlyphCount) >= gstring->used)
691                     continue;
692                   for (k = 0; k < rule->BacktrackGlyphCount; k++)
693                     if (get_class_def (&context2->BacktrackClassDef,
694                                        gstring->glyphs[gidx - 1 - k].glyph_id)
695                         != rule->Backtrack[k])
696                       break;
697                   if (k < rule->BacktrackGlyphCount)
698                     continue;
699                   for (k = 1; k < rule->InputGlyphCount; k++)
700                     if (get_class_def (&context2->InputClassDef,
701                                        gstring->glyphs[gidx + k].glyph_id)
702                         != rule->Input[k - 1])
703                       break;
704                   if (k < rule->InputGlyphCount)
705                     continue;
706                   for (k = 0; k < rule->LookaheadGlyphCount; k++)
707                     if (get_class_def (&context2->LookaheadClassDef,
708                                        gstring->glyphs[fore_idx + k].glyph_id)
709                         != rule->LookAhead[k])
710                       break;
711                   if (k < rule->LookaheadGlyphCount)
712                     continue;
713
714                   orig_used = gstring->used;
715                   for (k = 0; k < rule->LookupCount; k++)
716                     lookup_gpos (lookup_list,
717                                  rule->LookupRecord[k].LookupListIndex,
718                                  gstring,
719                                  gidx + rule->LookupRecord[k].SequenceIndex);
720                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
721                   break;
722                 }
723             }
724           else if (subtable->Format == 3)
725             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
726           else
727             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (invalid subformat)");
728           break;
729
730         case 9:
731           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
732           break;
733
734         default:
735           continue;
736         }
737     }
738   if (gidx == orig_gidx)
739     {
740       // printf ("not applied\n");
741       gidx++;
742     }
743   else
744     {
745       // printf ("done\n");
746     }
747   return gidx;
748 }
749
750 static int
751 lookup_cmap (OTF_cmap *cmap, int c)
752 {
753   char *errfmt = "cmap driving%s";
754   int errret = -1;
755   int i;
756
757   if (! cmap || ! cmap->Unicode)
758     return 0;
759
760   switch (cmap->Unicode->subtable.format)
761     {
762     case 4:
763       {
764         OTF_EncodingSubtable4 *sub4 = cmap->Unicode->subtable.f.f4;
765         int segCount = sub4->segCountX2 / 2;
766
767         for (i = 0; i < segCount; i++)
768           if (c <= sub4->segments[i].endCount)
769             break;
770         if (i == segCount || c < sub4->segments[i].startCount)
771           return 0;
772         if (sub4->segments[i].idRangeOffset == 0xFFFF)
773           return c + sub4->segments[i].idDelta;
774         if (c == 0xFFFF)
775           return 0;
776         return sub4->glyphIdArray[sub4->segments[i].idRangeOffset
777                                   + (c - sub4->segments[i].startCount)];
778       }
779       break;
780
781     default:
782       OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (not yet supported)");
783       break;
784     }
785
786   return 0;
787 }
788
789 \f
790
791 /* API */
792
793 int
794 OTF_drive_cmap (OTF *otf, OTF_GlyphString *gstring)
795 {
796   OTF_cmap *cmap;
797   int i;
798
799   if (! otf->cmap
800       && OTF_get_table (otf, "cmap") < 0)
801     return -1;
802
803   cmap = otf->cmap;
804   for (i = 0; i < gstring->used; i++)
805     {
806       gstring->glyphs[i].glyph_id = lookup_cmap (cmap, gstring->glyphs[i].c);
807       if (gstring->glyphs[i].glyph_id < 0)
808         return -1;
809     }
810   return 0;
811 }
812
813
814 int
815 OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring)
816 {
817   OTF_GDEF *gdef;
818   int i;
819
820   if (! otf->gdef
821       && OTF_get_table (otf, "GDEF") < 0)
822     return -1;
823   gdef = otf->gdef;
824
825   if (gdef->glyph_class_def.offset)
826     for (i = 0; i < gstring->used; i++)
827       gstring->glyphs[i].GlyphClass
828         = get_class_def (&gdef->glyph_class_def,
829                          gstring->glyphs[i].glyph_id);
830
831   if (gdef->mark_attach_class_def.offset)
832     for (i = 0; i < gstring->used; i++)
833       gstring->glyphs[i].MarkAttachClass
834         = get_class_def (&gdef->mark_attach_class_def,
835                          gstring->glyphs[i].glyph_id);
836
837   return 0;
838 }
839
840
841 int
842 OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring,
843                 char *script, char *language, char *features)
844 {
845   char *errfmt = "GSUB driving%s";
846   int errret = -1;
847   OTF_GSUB *gsub;
848   OTF_LangSys *LangSys;
849   int nfeatures;
850   int *feature_index;
851   int i, j;
852
853   if (! otf->gsub
854       && OTF_get_table (otf, "GSUB") < 0)
855     return errret;
856   gsub = otf->gsub;
857
858   LangSys = get_langsys (&gsub->ScriptList, script, language);
859   if (! LangSys)
860     return errret;
861
862   feature_index = alloca (sizeof (int) * gsub->FeatureList.FeatureCount);
863   if (! feature_index)
864     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
865
866   nfeatures = get_feature_index (LangSys, &gsub->FeatureList,
867                                  features, feature_index);
868   if (nfeatures == 0)
869     OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " no feature");
870
871   for (i = 0; i < nfeatures; i++)
872     {
873       OTF_Feature *feature = gsub->FeatureList.Feature + feature_index[i];
874
875       for (j = 0; j < feature->LookupCount; j++)
876         {
877           int gidx = 0;
878
879           while (gidx < gstring->used)
880             {
881               gidx = lookup_gsub (&gsub->LookupList,
882                                   feature->LookupListIndex[j], gstring, gidx);
883               if (gidx < 0)
884                 return errret;
885             }
886         }
887     }
888
889   return 0;
890 }
891
892 int
893 OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring,
894                 char *script, char *language, char *features)
895 {
896   char *errfmt = "GPOS driving%s";
897   int errret = -1;
898   OTF_GPOS *gpos;
899   OTF_LangSys *LangSys;
900   int nfeatures;
901   int *feature_index;
902   int i, j;
903
904   if (! otf->gpos
905       && OTF_get_table (otf, "GPOS") < 0)
906     return errret;
907   gpos = otf->gpos;
908
909   LangSys = get_langsys (&gpos->ScriptList, script, language);
910   if (! LangSys)
911     return errret;
912
913   feature_index = alloca (sizeof (int) * gpos->FeatureList.FeatureCount);
914   if (! feature_index)
915     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
916
917   nfeatures = get_feature_index (LangSys, &gpos->FeatureList,
918                                  features, feature_index);
919   if (nfeatures == 0)
920     OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " no feature");
921
922   for (i = 0; i < nfeatures; i++)
923     {
924       OTF_Feature *feature = gpos->FeatureList.Feature + feature_index[i];
925
926       for (j = 0; j < feature->LookupCount; j++)
927         {
928           int gidx = 0;
929
930           while (gidx < gstring->used)
931             {
932               gidx = lookup_gpos (&gpos->LookupList,
933                                   feature->LookupListIndex[j], gstring, gidx);
934               if (gidx < 0)
935                 return errret;
936             }
937         }
938     }
939
940   return 0;
941 }
942
943 int
944 OTF_drive_tables (OTF *otf, OTF_GlyphString *gstring,
945                   char *script, char *language,
946                   char *gsub_features, char *gpos_features)
947 {
948   if (OTF_drive_cmap (otf, gstring) < 0)
949     return -1;
950   if (OTF_drive_gdef (otf, gstring) < 0)
951     return -1;
952   if ((! gsub_features || gsub_features[0])
953       && OTF_drive_gsub (otf, gstring, script, language, gsub_features) < 0)
954     return -1;
955   if ((! gpos_features || gpos_features[0])
956       && OTF_drive_gpos (otf, gstring, script, language, gpos_features) < 0)
957     return -1;
958   return 0;
959 }