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