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