*** empty log message ***
[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 setup_lookup_indices (OTF_LangSys *LangSys, OTF_FeatureList *FeatureList,
145                       char *features, int *lookup_indices)
146 {
147   int i, j, n = 0;
148   OTF_Feature *feature;
149   int *feature_table = alloca (sizeof (int) * FeatureList->FeatureCount);
150
151   for (i = 0; i < FeatureList->FeatureCount; i++)
152     feature_table[i] = 0;
153
154   while (*features)
155     {
156       char tagname[4];
157       OTF_Tag tag;
158       int negate = 0;
159
160       if (*features == '*')
161         {
162           /* Consume all remaining features.  */
163           for (i = 0; i < FeatureList->FeatureCount; i++)
164             if (! feature_table[i])
165               {
166                 feature = FeatureList->Feature + i;
167                 for (j = 0; j < feature->LookupCount; j++)
168                   lookup_indices[n++] = feature->LookupListIndex[j];
169               }
170           break;
171         }
172
173       if (*features == '~')
174         negate = 1, features++;
175       for (i = 0; *features && *features != ','; i++, features++)
176         tagname[i] = *features;
177       if (*features)
178         /* Skip ',' */
179         features++;
180       for (; i < 4; i++)
181         tagname[i] = '\0';
182       tag = OTF_tag (tagname);
183       for (i = 0; i < FeatureList->FeatureCount; i++)
184         {
185           feature = FeatureList->Feature + i;
186           if (tag == feature->FeatureTag)
187             {
188               if (! negate)
189                 for (j = 0; j < feature->LookupCount; j++)
190                   lookup_indices[n++] = feature->LookupListIndex[j];
191               feature_table[i] = 1;
192               break;
193             }
194         }
195     }
196
197   return n;
198 }
199
200 static int
201 match_ids (OTF_GlyphString *gstring, int gidx, int count, OTF_GlyphID *ids)
202 {
203   OTF_Glyph *gbeg = gstring->glyphs + gidx;
204   OTF_Glyph *gend = gstring->glyphs + gstring->used;
205   OTF_Glyph *g;
206   int i;
207
208   for (g = gbeg, i = 0; g < gend && i < count; g++)
209     if (g->glyph_id && g->glyph_id != ids[i++])
210       return -1;
211   return (i < count ? -1 : g - gbeg);
212 }
213
214 static int
215 match_chain_ids (OTF_GlyphString *gstring, int gidx, OTF_ChainRule *rule)
216 {
217   int i, j;
218
219   for (i = rule->BacktrackGlyphCount, j = gidx - 1; j >= 0 && i > 0; j--)
220     if (gstring->glyphs[j].glyph_id)
221       i--;
222   if (i > 0)
223     return -1;
224
225   i = match_ids (gstring, j, rule->BacktrackGlyphCount, rule->Backtrack);
226   if (i < 0)
227     return -1;
228   gidx++;
229   i = match_ids (gstring, gidx, rule->InputGlyphCount - 1, rule->Input);
230   if (i < 0)
231     return -1;
232   gidx += i;
233   i = match_ids (gstring, gidx, rule->LookaheadGlyphCount, rule->LookAhead);
234   if (i < 0)
235     return -1;
236   return 0;
237 }
238
239 static int
240 match_classes (OTF_ClassDef *class_def, OTF_GlyphString *gstring, int gidx,
241                int count, unsigned *classes)
242 {
243   OTF_Glyph *gbeg = gstring->glyphs + gidx;
244   OTF_Glyph *gend = gstring->glyphs + gstring->used;
245   OTF_Glyph *g;
246   int i;
247
248   for (g = gbeg, i = 0; g < gend && i < count; g++)
249     if (g->glyph_id
250         && get_class_def (class_def, g->glyph_id) != classes[i++])
251       return -1;
252   return (i < count ? -1 : g - gbeg);
253 }
254
255 static int
256 match_chain_classes (OTF_GlyphString *gstring, int gidx,
257                      OTF_ClassDef *BacktrackClassDef,
258                      OTF_ClassDef *InputClassDef,
259                      OTF_ClassDef *LookaheadClassDef,
260                      OTF_ChainClassRule *rule)
261 {
262   int i, j;
263
264   for (i = rule->BacktrackGlyphCount, j = gidx - 1; j >= 0 && i > 0; j--)
265     if (gstring->glyphs[j].glyph_id)
266       i--;
267   if (i > 0)
268     return -1;
269
270   i = match_classes (BacktrackClassDef, gstring, j,
271                      rule->BacktrackGlyphCount, rule->Backtrack);
272   if (i < 0)
273     return -1;
274   gidx++;
275   i = match_classes (InputClassDef, gstring, gidx,
276                      rule->InputGlyphCount - 1, rule->Input);
277   if (i < 0)
278     return -1;
279   gidx += i;
280   i = match_classes (LookaheadClassDef, gstring, gidx,
281                      rule->LookaheadGlyphCount, rule->LookAhead);
282   if (i < 0)
283     return -1;
284   return 0;
285 }
286
287
288 static int
289 match_coverages (OTF_GlyphString *gstring, int gidx, int count,
290                  OTF_Coverage *coverages)
291 {
292   OTF_Glyph *gbeg = gstring->glyphs + gidx;
293   OTF_Glyph *gend = gstring->glyphs + gstring->used;
294   OTF_Glyph *g;
295   int i;
296
297   for (g = gbeg, i = 0; g < gend && i < count; g++)
298     if (g->glyph_id
299         && get_coverage_index (coverages + i, g->glyph_id) < 0)
300       return -1;
301   return (i < count ? -1 : g - gbeg);
302 }
303
304 static int
305 match_chain_coverages (OTF_GlyphString *gstring, int gidx,
306                        OTF_GSUB_ChainContext3 *context3)
307 {
308   int i, j;
309
310   if (gidx < context3->BacktrackGlyphCount
311       || (gidx + context3->InputGlyphCount
312           + context3->LookaheadGlyphCount) >= gstring->used)
313     return -1;
314
315   for (i = context3->BacktrackGlyphCount, j = gidx - 1; j >= 0 && i > 0; j--)
316     if (gstring->glyphs[j].glyph_id)
317       i--;
318   if (i > 0)
319     return -1;
320
321   i = match_coverages (gstring, j, context3->BacktrackGlyphCount,
322                        context3->Backtrack);
323   if (i < 0)
324     return -1;
325   gidx++;
326   i = match_coverages (gstring, gidx, context3->InputGlyphCount - 1,
327                        context3->Input + 1);
328   if (i < 0)
329     return -1;
330   gidx += i;
331   i = match_coverages (gstring, gidx, context3->LookaheadGlyphCount,
332                        context3->LookAhead);
333   if (i < 0)
334     return -1;
335   return 0;
336 }
337
338 static int
339 lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
340              OTF_GlyphString *gstring, int gidx)
341 {
342   char *errfmt = "GSUB Looking up%s";
343   int errret = -1;
344   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
345   unsigned int flag = lookup->LookupFlag;
346   int orig_gidx = gidx;
347   OTF_Glyph *g = gstring->glyphs + gidx;
348   int i;
349
350   if (! g->glyph_id
351       || (g->GlyphClass
352           && (flag & (1 << g->GlyphClass))))
353     return (gidx + 1);
354
355   /* Try all subtables until one of them handles the current glyph.  */
356   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
357     {
358       unsigned lookup_type = lookup->LookupType;
359       OTF_LookupSubTableGSUB *subtable = lookup->SubTable.gsub + i;
360       int coverage_idx;
361
362       if (lookup_type == 7)
363         {
364           OTF_GSUB_Extension1 *extension1 = &subtable->u.extension1;
365
366           lookup_type = extension1->ExtensionLookupType;
367           subtable = extension1->ExtensionSubtable;
368         }
369
370       if (subtable->Coverage.offset)
371         {
372           coverage_idx = get_coverage_index (&subtable->Coverage,
373                                              g->glyph_id);
374           if (coverage_idx < 0)
375             continue;
376         }
377
378       switch (lookup->LookupType)
379         {
380         case 1:
381           if (subtable->Format == 1)
382             g->glyph_id += subtable->u.single1.DeltaGlyphID;
383           else
384             g->glyph_id = subtable->u.single2.Substitute[coverage_idx];
385           gidx++;
386           break;
387
388         case 2:
389           {
390             OTF_GSUB_Multiple1 *multiple1 = &subtable->u.multiple1;
391             OTF_Sequence *seq = multiple1->Sequence + coverage_idx;
392
393             gstring_subst (gstring, gidx, gidx + 1,
394                            seq->Substitute, seq->GlyphCount);
395             gidx += seq->GlyphCount;
396           }
397           break;
398
399         case 3:
400           if (subtable->Format == 1)
401             {
402               OTF_GSUB_Alternate1 *alt1 = &subtable->u.alternate1;
403               OTF_AlternateSet *altset = alt1->AlternateSet + coverage_idx;
404
405               g->glyph_id = altset->Alternate[0];
406               gidx++;
407             }
408           else
409             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
410           break;
411
412         case 4:
413           if (subtable->Format == 1)
414             {
415               OTF_GSUB_Ligature1 *lig1 = &subtable->u.ligature1;
416               OTF_LigatureSet *ligset = lig1->LigatureSet + coverage_idx;
417               OTF_Ligature *lig;
418               int j;
419
420               for (j = 0; j < ligset->LigatureCount; j++)
421                 {
422                   int n;
423
424                   lig = ligset->Ligature + j;
425                   n = match_ids (gstring, gidx + 1,
426                                  lig->CompCount - 1, lig->Component);
427                   if (n < 0)
428                     continue;
429                   gstring_subst (gstring, gidx, gidx + 1 + n,
430                                  &lig->LigGlyph, 1);
431                   gidx++;
432                   break;
433                 }
434             }
435           else
436             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
437           break;
438
439         case 5:
440           if (subtable->Format == 1)
441             {
442               OTF_GSUB_Context1 *context1 = &subtable->u.context1;
443               OTF_RuleSet *set = context1->RuleSet + coverage_idx;
444               OTF_Rule *rule;
445               int orig_used;
446               int j, k;
447
448               for (j = 0; j < set->RuleCount; j++)
449                 {
450                   rule = set->Rule + j;
451                   if (match_ids (gstring, gidx + 1,
452                                  rule->GlyphCount - 1, rule->Input) < 0)
453                     continue;
454                   orig_used = gstring->used;
455                   for (k = 0; k < rule->LookupCount; k++)
456                     lookup_gsub (lookup_list,
457                                  rule->LookupRecord[k].LookupListIndex,
458                                  gstring,
459                                  gidx + rule->LookupRecord[k].SequenceIndex);
460                   gidx += rule->GlyphCount + (gstring->used - orig_used);
461                   break;
462                 }
463             }
464           else if (subtable->Format == 2)
465             {
466               OTF_GSUB_Context2 *context2 = &subtable->u.context2;
467               OTF_ClassSet *set;
468               OTF_ClassRule *rule;
469               unsigned class;
470               int orig_used;
471               int j, k;
472
473               class = get_class_def (&context2->ClassDef, g->glyph_id);
474               set = context2->ClassSet + class;
475               for (j = 0; j < set->ClassRuleCnt; j++)
476                 {
477                   rule = set->ClassRule + j;
478                   if (match_classes (&context2->ClassDef,
479                                      gstring, gidx + 1,
480                                      rule->GlyphCount - 1, rule->Class)
481                       < 0)
482                     continue;
483                   orig_used = gstring->used;
484                   for (k = 0; k < rule->LookupCount; k++)
485                     lookup_gsub (lookup_list,
486                                  rule->LookupRecord[k].LookupListIndex,
487                                  gstring,
488                                  gidx + rule->LookupRecord[k].SequenceIndex);
489                   gidx += rule->GlyphCount + (gstring->used - orig_used);
490                   break;
491                 }
492             }
493           else                  /* subtable->Format == 3 */
494             {
495               OTF_GSUB_Context3 *context3 = &subtable->u.context3;
496               int orig_used;
497               int j;
498
499               if (match_coverages (gstring, gidx + 1, context3->GlyphCount - 1,
500                                    context3->Coverage + 1) < 0)
501                 continue;
502               orig_used = gstring->used;
503               for (j = 0; j < context3->LookupCount; j++)
504                 lookup_gsub (lookup_list,
505                              context3->LookupRecord[j].LookupListIndex,
506                              gstring,
507                              gidx + context3->LookupRecord[j].SequenceIndex);
508               gidx += context3->GlyphCount + (gstring->used - orig_used);
509             }
510           break;
511
512         case 6:
513           if (subtable->Format == 1)
514             {
515               OTF_GSUB_ChainContext1 *context1 = &subtable->u.chain_context1;
516               OTF_ChainRuleSet *set = context1->ChainRuleSet + coverage_idx;
517               int orig_used;
518               int j, k;
519               
520               for (j = 0; j < set->ChainRuleCount; j++)
521                 {
522                   OTF_ChainRule *rule = set->ChainRule + j;
523
524                   if (gidx < rule->BacktrackGlyphCount
525                       || (gidx + rule->InputGlyphCount
526                           + rule->LookaheadGlyphCount) >= gstring->used)
527                     continue;
528                   if (match_chain_ids (gstring, gidx, rule) < 0)
529                     continue;
530                   orig_used = gstring->used;
531                   for (k = 0; k < rule->LookupCount; k++)
532                     lookup_gsub (lookup_list,
533                                  rule->LookupRecord[k].LookupListIndex,
534                                  gstring,
535                                  gidx + rule->LookupRecord[k].SequenceIndex);
536                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
537                   break;
538                 }
539             }
540           else if (subtable->Format == 2)
541             {
542               OTF_GSUB_ChainContext2 *context2 = &subtable->u.chain_context2;
543               OTF_ChainClassSet *set;
544               unsigned class;
545               int j;
546               int orig_used;
547
548               // printf ("GSUB 6-2: c:0x%x g:0x%x\n", g->c, g->glyph_id);
549               class = get_class_def (&context2->InputClassDef, g->glyph_id);
550               set = context2->ChainClassSet + class;
551               for (j = 0; j < set->ChainClassRuleCnt; j++)
552                 {
553                   OTF_ChainClassRule *rule = set->ChainClassRule + j;
554                   int k;
555
556                   if (gidx < rule->BacktrackGlyphCount
557                       || (gidx + rule->InputGlyphCount
558                           + rule->LookaheadGlyphCount) >= gstring->used)
559                     continue;
560                   if (match_chain_classes (gstring, gidx,
561                                            &context2->BacktrackClassDef,
562                                            &context2->InputClassDef,
563                                            &context2->LookaheadClassDef,
564                                            rule) < 0)
565                     continue;
566                   orig_used = gstring->used;
567                   for (k = 0; k < rule->LookupCount; k++)
568                     lookup_gsub (lookup_list,
569                                  rule->LookupRecord[k].LookupListIndex,
570                                  gstring,
571                                  gidx + rule->LookupRecord[k].SequenceIndex);
572                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
573                   break;
574                 }
575             }
576           else
577             {
578               OTF_GSUB_ChainContext3 *context3 = &subtable->u.chain_context3;
579               int orig_used;
580               int j;
581
582               if (match_chain_coverages (gstring, gidx, context3) < 0)
583                 continue;
584               orig_used = gstring->used;
585               for (j = 0; j < context3->LookupCount; j++)
586                 lookup_gsub (lookup_list,
587                              context3->LookupRecord[j].LookupListIndex,
588                              gstring,
589                              gidx + context3->LookupRecord[j].SequenceIndex);
590               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
591             }
592           break;
593
594         case 8:
595           {
596             OTF_GSUB_ReverseChain1 *reverse = &subtable->u.reverse_chain1;
597             int back_gidx = gidx + 1 + reverse->BacktrackGlyphCount;
598             int ahead_gidx = gidx - reverse->LookaheadGlyphCount;
599             int j;
600
601             if (back_gidx > gstring->used || ahead_gidx < 0)
602               break;
603
604             for (j = 0; j < reverse->BacktrackGlyphCount; j++)
605               if (get_coverage_index (reverse->Backtrack + j,
606                                       gstring->glyphs[gidx + 1 + j].glyph_id)
607                   < 0)
608                 break;
609             if (j < reverse->BacktrackGlyphCount)
610               continue;
611             for (j = 0; j < reverse->LookaheadGlyphCount; j++)
612               if (get_coverage_index (reverse->LookAhead + j,
613                                       gstring->glyphs[gidx - 1 - j].glyph_id)
614                   < 0)
615                 break;
616             if (j < reverse->LookaheadGlyphCount)
617               continue;
618             g->glyph_id = reverse->Substitute[coverage_idx];
619             gidx--;
620           }
621
622         default:
623           continue;
624         }
625     }
626   if (gidx == orig_gidx)
627     {
628       //printf ("not applied\n");
629       gidx++;
630     }
631   else
632     {
633       // printf ("done\n");
634     }
635   return gidx;
636 }
637
638 \f
639
640 /* GPOS */
641 unsigned
642 get_anchor (OTF_Anchor *anchor, OTF_ValueRecord *rec)
643 {
644   unsigned value_format = OTF_XPlacement | OTF_YPlacement;
645
646   rec->XPlacement = anchor->XCoordinate;
647   rec->YPlacement = anchor->YCoordinate;
648   if (anchor->AnchorFormat == 1)
649     /* Nothing to do */
650     ;
651   else if (anchor->AnchorFormat == 2)
652     /* Not yet implemented */
653     ;
654   else if (anchor->AnchorFormat == 3)
655     /* Not yet implemented */
656     ;
657   return value_format;
658 }
659
660
661 static int
662 lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
663              OTF_GlyphString *gstring, int gidx)
664 {
665   char *errfmt = "GPOS Looking up%s";
666   int errret = -1;
667   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
668   unsigned int flag = lookup->LookupFlag;
669   int orig_gidx = gidx;
670   OTF_Glyph *g = gstring->glyphs + gidx;
671   int i;
672
673   if (! g->glyph_id
674       || (g->GlyphClass
675           && (flag & (1 << g->GlyphClass))))
676     return (gidx + 1);
677
678   /* Try all subtables until one of them handles the current glyph.  */
679   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
680     {
681       OTF_LookupSubTableGPOS *subtable = lookup->SubTable.gpos + i;
682       int coverage_idx;
683
684       // printf ("subtype:%d ", subtable->Format);
685       if (subtable->Coverage.offset)
686         {
687           coverage_idx = get_coverage_index (&subtable->Coverage,
688                                              g->glyph_id);
689           if (coverage_idx < 0)
690             {
691               // printf ("not covererd ");
692               continue;
693             }
694         }
695
696       switch (lookup->LookupType)
697         {
698         case 1:
699           g->positioning_type = lookup->LookupType;
700           if (subtable->Format == 1)
701             {
702               OTF_GPOS_Single1 *single1 = &subtable->u.single1;
703
704               g->f.f1.format = single1->ValueFormat;
705               g->f.f1.value = &single1->Value;
706             }
707           else if (subtable->Format == 2)
708             {
709               OTF_GPOS_Single2 *single2 = &subtable->u.single2;
710
711               g->f.f1.format = single2->ValueFormat;
712               g->f.f1.value = single2->Value + coverage_idx;
713             }
714           break;
715
716         case 2:
717           if (gidx + 1 >= gstring->used)
718             continue;
719           if (subtable->Format == 1)
720             {
721               OTF_GPOS_Pair1 *pair1 = &subtable->u.pair1;
722               OTF_PairSet *set = pair1->PairSet + coverage_idx;
723               int j;
724
725               for (j = 0; j < set->PairValueCount; j++)
726                 {
727                   if (set->PairValueRecord[j].SecondGlyph != g[1].glyph_id)
728                     continue;
729                   gidx++;
730                   g->positioning_type = lookup->LookupType;
731                   g->f.f2.format = pair1->ValueFormat1;
732                   g->f.f2.value = &set->PairValueRecord[j].Value1;
733                   if (pair1->ValueFormat2)
734                     {
735                       g++, gidx++;
736                       g->positioning_type = lookup->LookupType;
737                       g->f.f2.format = pair1->ValueFormat2;
738                       g->f.f2.value = &set->PairValueRecord[j].Value2;
739                     }
740                 }
741             }
742           else if (subtable->Format == 2)
743             {
744               OTF_GPOS_Pair2 *pair2 = &subtable->u.pair2;
745               unsigned class1, class2;
746
747               // printf ("GPOS 2-2: c:0x%x g:0x%x\n", g->c, g->glyph_id);
748               gidx++;
749               class1 = get_class_def (&pair2->ClassDef1, g->glyph_id);
750               class2 = get_class_def (&pair2->ClassDef2, g[1].glyph_id);
751               g->positioning_type = lookup->LookupType;
752               g->f.f2.format = pair2->ValueFormat1;
753               g->f.f2.value
754                 = &pair2->Class1Record[class1].Class2Record[class2].Value1;
755               if (pair2->ValueFormat2)
756                 {
757                   g++, gidx++;
758                   g->positioning_type = lookup->LookupType;
759                   g->f.f2.format = pair2->ValueFormat2;
760                   g->f.f2.value
761                     = &pair2->Class1Record[class1].Class2Record[class2].Value2;
762                 }
763             }
764           break;
765
766         case 3:
767           {
768             OTF_GPOS_Cursive1 *cursive1 = &subtable->u.cursive1;
769           
770             g->positioning_type = lookup->LookupType;
771             g->f.f3.entry_anchor
772               = &cursive1->EntryExitRecord[coverage_idx].EntryAnchor;
773             g->f.f3.exit_anchor
774               = &cursive1->EntryExitRecord[coverage_idx].ExitAnchor;
775           }
776           break;
777
778         case 4:
779           if (gidx < 1)
780             continue;
781           if (subtable->Format == 1)
782             {
783               OTF_GPOS_MarkBase1 *mark_base1 = &subtable->u.mark_base1;
784               OTF_MarkRecord *mark_record;
785               OTF_AnchorRecord *base_record;
786               int coverage_idx_base
787                 = get_coverage_index (&mark_base1->BaseCoverage,
788                                       g[-1].glyph_id);
789
790               if (coverage_idx_base < 0)
791                 continue;
792               // printf ("GPOS 4-1: c:0x%x g:0x%x\n", g->c, g->glyph_id);
793               mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx;
794               base_record
795                 = mark_base1->BaseArray.AnchorRecord + coverage_idx_base;
796               g->f.f4.mark_anchor = &mark_record->MarkAnchor;
797               g->f.f4.base_anchor
798                 = &base_record->Anchor[mark_record->Class];
799               g->positioning_type = lookup->LookupType;
800               break;
801             }
802           break;
803
804         case 5:
805           if (gidx < 1)
806             continue;
807           if (subtable->Format == 1)
808             {
809               /* As the document of this lookup type is quite
810                  ambiguous, and we can't know the exact procedure to
811                  handle it?!?  */
812               OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
813             }
814           break;
815
816         case 6:
817           if (gidx < 1)
818             continue;
819           if (subtable->Format == 1)
820             {
821               OTF_GPOS_MarkMark1 *mark_mark1 = &subtable->u.mark_mark1;
822               OTF_MarkRecord *mark1_record;
823               OTF_AnchorRecord *mark2_record;
824               int coverage_idx_base
825                 = get_coverage_index (&mark_mark1->Mark2Coverage,
826                                       g[-1].glyph_id);
827
828               if (coverage_idx_base < 0)
829                 continue;
830               // printf ("GPOS 6-1: c:0x%x g:0x%x\n", g->c, g->glyph_id);
831               mark1_record = mark_mark1->Mark1Array.MarkRecord + coverage_idx;
832               mark2_record
833                 = mark_mark1->Mark2Array.AnchorRecord + coverage_idx_base;
834               g->f.f6.mark1_anchor = &mark1_record->MarkAnchor;
835               g->f.f6.mark2_anchor
836                 = &mark2_record->Anchor[mark1_record->Class];
837               g->positioning_type = lookup->LookupType;
838               break;
839             }
840           break;
841
842         case 7:
843           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
844           break;
845
846         case 8:
847           if (subtable->Format == 1)
848             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
849           else if (subtable->Format == 2)
850             {
851               OTF_GPOS_ChainContext2 *context2 = &subtable->u.chain_context2;
852               OTF_ChainClassSet *set;
853               unsigned class;
854               int j;
855               int orig_used;
856
857               // printf ("GPOS 8-2: c:0x%x g:0x%x\n", g->c, g->glyph_id);
858               class = get_class_def (&context2->InputClassDef, g->glyph_id);
859               set = context2->ChainClassSet + class;
860               for (j = 0; j < set->ChainClassRuleCnt; j++)
861                 {
862                   OTF_ChainClassRule *rule = set->ChainClassRule + j;
863                   int fore_idx = gidx + rule->InputGlyphCount;
864                   int k;
865
866                   if (gidx < rule->BacktrackGlyphCount
867                       || (gidx + rule->InputGlyphCount
868                           + rule->LookaheadGlyphCount) >= gstring->used)
869                     continue;
870                   for (k = 0; k < rule->BacktrackGlyphCount; k++)
871                     if (get_class_def (&context2->BacktrackClassDef,
872                                        gstring->glyphs[gidx - 1 - k].glyph_id)
873                         != rule->Backtrack[k])
874                       break;
875                   if (k < rule->BacktrackGlyphCount)
876                     continue;
877                   for (k = 1; k < rule->InputGlyphCount; k++)
878                     if (get_class_def (&context2->InputClassDef,
879                                        gstring->glyphs[gidx + k].glyph_id)
880                         != rule->Input[k - 1])
881                       break;
882                   if (k < rule->InputGlyphCount)
883                     continue;
884                   for (k = 0; k < rule->LookaheadGlyphCount; k++)
885                     if (get_class_def (&context2->LookaheadClassDef,
886                                        gstring->glyphs[fore_idx + k].glyph_id)
887                         != rule->LookAhead[k])
888                       break;
889                   if (k < rule->LookaheadGlyphCount)
890                     continue;
891
892                   orig_used = gstring->used;
893                   for (k = 0; k < rule->LookupCount; k++)
894                     lookup_gpos (lookup_list,
895                                  rule->LookupRecord[k].LookupListIndex,
896                                  gstring,
897                                  gidx + rule->LookupRecord[k].SequenceIndex);
898                   gidx += rule->InputGlyphCount + (gstring->used - orig_used);
899                   break;
900                 }
901             }
902           else if (subtable->Format == 3)
903             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
904           else
905             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (invalid subformat)");
906           break;
907
908         case 9:
909           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
910           break;
911
912         default:
913           continue;
914         }
915     }
916   if (gidx == orig_gidx)
917     {
918       // printf ("not applied\n");
919       gidx++;
920     }
921   else
922     {
923       // printf ("done\n");
924     }
925   return gidx;
926 }
927
928 \f
929
930 /* API */
931
932 int
933 OTF_drive_cmap (OTF *otf, OTF_GlyphString *gstring)
934 {
935   OTF_cmap *cmap;
936   int i;
937
938   if (! otf->cmap
939       && OTF_get_table (otf, "cmap") < 0)
940     return -1;
941
942   cmap = otf->cmap;
943   for (i = 0; i < gstring->used; i++)
944     if (! gstring->glyphs[i].glyph_id)
945       {
946         int c = gstring->glyphs[i].c;
947         if (c < 32 || ! cmap->unicode_table)
948           gstring->glyphs[i].glyph_id = 0;
949         else
950           gstring->glyphs[i].glyph_id = cmap->unicode_table[c];
951       }
952   return 0;
953 }
954
955 int
956 OTF_get_unicode (OTF *otf, OTF_GlyphID code)
957 {
958   if (! otf->cmap
959       && OTF_get_table (otf, "cmap") < 0)
960     return 0;
961   if (code == 0
962       || code > otf->cmap->max_glyph_id
963       || ! otf->cmap->decode_table)
964     return 0;
965   return otf->cmap->decode_table[code];
966 }
967
968 int
969 OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring)
970 {
971   OTF_GDEF *gdef;
972   int i;
973
974   if (! otf->gdef
975       && OTF_get_table (otf, "GDEF") < 0)
976     return -1;
977   gdef = otf->gdef;
978
979   if (gdef->glyph_class_def.offset)
980     for (i = 0; i < gstring->used; i++)
981       gstring->glyphs[i].GlyphClass
982         = get_class_def (&gdef->glyph_class_def,
983                          gstring->glyphs[i].glyph_id);
984
985   if (gdef->mark_attach_class_def.offset)
986     for (i = 0; i < gstring->used; i++)
987       gstring->glyphs[i].MarkAttachClass
988         = get_class_def (&gdef->mark_attach_class_def,
989                          gstring->glyphs[i].glyph_id);
990
991   return 0;
992 }
993
994
995 int
996 OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring,
997                 char *script, char *language, char *features)
998 {
999   char *errfmt = "GSUB driving%s";
1000   int errret = -1;
1001   OTF_GSUB *gsub;
1002   OTF_LangSys *LangSys;
1003   int *lookup_indices;
1004   int i, n;
1005
1006   if (! otf->gsub
1007       && OTF_get_table (otf, "GSUB") < 0)
1008     return errret;
1009   gsub = otf->gsub;
1010   if (gsub->FeatureList.FeatureCount == 0
1011       || gsub->LookupList.LookupCount == 0)
1012     return 0;
1013
1014   LangSys = get_langsys (&gsub->ScriptList, script, language);
1015   if (! LangSys)
1016     return errret;
1017
1018   /* One lookup may be used by multiple features.  */
1019   lookup_indices = alloca (sizeof (int)
1020                            * gsub->LookupList.LookupCount
1021                            * gsub->FeatureList.FeatureCount);
1022   if (! lookup_indices)
1023     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
1024   n = setup_lookup_indices (LangSys, &gsub->FeatureList,
1025                             features, lookup_indices);
1026   if (n < 0)
1027     return errret;
1028
1029   for (i = 0; i < n; i++)
1030     {
1031       int index = lookup_indices[i];
1032       int gidx;
1033
1034       if (gsub->LookupList.Lookup[index].LookupType != 8)
1035         {
1036           gidx = 0;
1037           while (gidx < gstring->used)
1038             {
1039               gidx = lookup_gsub (&gsub->LookupList, index, gstring, gidx);
1040               if (gidx < 0)
1041                 return errret;
1042             }
1043         }
1044       else
1045         {
1046           gidx = gstring->used - 1;
1047           while (gidx >= 0)
1048             {
1049               gidx = lookup_gsub (&gsub->LookupList, index, gstring, gidx);
1050               if (gidx < 0)
1051                 return errret;
1052             }
1053         }
1054     }
1055
1056   return 0;
1057 }
1058
1059 int
1060 OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring,
1061                 char *script, char *language, char *features)
1062 {
1063   char *errfmt = "GPOS driving%s";
1064   int errret = -1;
1065   OTF_GPOS *gpos;
1066   OTF_LangSys *LangSys;
1067   int *lookup_indices;
1068   int i, n;
1069
1070   if (! otf->gpos
1071       && OTF_get_table (otf, "GPOS") < 0)
1072     return errret;
1073   gpos = otf->gpos;
1074   if (gpos->FeatureList.FeatureCount == 0
1075       || gpos->LookupList.LookupCount == 0)
1076     return 0;
1077
1078   LangSys = get_langsys (&gpos->ScriptList, script, language);
1079   if (! LangSys)
1080     return errret;
1081
1082   /* One lookup may be used by multiple features.  */
1083   lookup_indices = alloca (sizeof (int)
1084                            * gpos->LookupList.LookupCount
1085                            * gpos->FeatureList.FeatureCount);
1086   if (! lookup_indices)
1087     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
1088   n = setup_lookup_indices (LangSys, &gpos->FeatureList,
1089                             features, lookup_indices);
1090   if (n < 0)
1091     return errret;
1092
1093   for (i = 0; i < n; i++)
1094     {
1095       int index = lookup_indices[i];
1096       int gidx = 0;
1097
1098       while (gidx < gstring->used)
1099         {
1100           gidx = lookup_gpos (&gpos->LookupList, index, gstring, gidx);
1101           if (gidx < 0)
1102             return errret;
1103         }
1104     }
1105
1106   return 0;
1107 }
1108
1109 int
1110 OTF_drive_tables (OTF *otf, OTF_GlyphString *gstring,
1111                   char *script, char *language,
1112                   char *gsub_features, char *gpos_features)
1113 {
1114   if (OTF_drive_cmap (otf, gstring) < 0)
1115     return -1;
1116   if (OTF_drive_gdef (otf, gstring) < 0)
1117     return -1;
1118   if (gsub_features
1119       && OTF_drive_gsub (otf, gstring, script, language, gsub_features) < 0)
1120     return -1;
1121   if (gpos_features
1122       && OTF_drive_gpos (otf, gstring, script, language, gpos_features) < 0)
1123     return -1;
1124   return 0;
1125 }