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