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