*** empty log message ***
[m17n/libotf.git] / src / otfdrive.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "otf.h"
6 #include "otferror.h"
7
8 #define GSTRING_DELETE(gstring, from, len)                              \
9   do {                                                                  \
10     memmove (gstring->glyphs + from, gstring->glyphs + from + len,      \
11              sizeof (OTF_Glyph) * (gstring->used - from - len));        \
12     gstring->used -= len;                                               \
13   } while (0)
14
15
16 #define GSTRING_INSERT(gstring, pos, len)                               \
17   do {                                                                  \
18     if (gstring->used + len > gstring->size)                            \
19       {                                                                 \
20         char *errfmt = "GSTRING%s";                                     \
21                                                                         \
22         gstring->size = gstring->used + len;                            \
23         gstring->glyphs = (OTF_Glyph *) realloc (gstring->glyphs,       \
24                                                  gstring->size);        \
25         if (! gstring->glyphs)                                          \
26           OTF_ERROR (OTF_ERROR_MEMORY, "");                             \
27       }                                                                 \
28     memmove (gstring->glyphs + pos + len, gstring->glyphs + pos,        \
29              sizeof (OTF_Glyph) * (gstring->used - pos));               \
30     gstring->used += len;                                               \
31   } while (0)
32
33
34 static int
35 gstring_subst (OTF_GlyphString *gstring, int from, int to,
36                OTF_GlyphID *ids, int num)
37 {
38   int errret = -1;
39   int len = to - from;
40   int i;
41
42   if (len < num)
43     GSTRING_INSERT (gstring, from, (num - len));
44   else if (len > num)
45     GSTRING_DELETE (gstring, from, (len - num));
46   for (i = 0; i < num; i++)
47     gstring->glyphs[from + i].glyph_id = ids[i];
48   return 0;
49 }
50
51 \f
52 static int
53 get_coverage_index (OTF_Coverage *coverage, OTF_GlyphID id)
54 {
55   int i;
56
57   if (coverage->CoverageFormat == 1)
58     {
59       for (i = 0; i < coverage->Count; i++)
60         if (coverage->table.GlyphArray[i] == id)
61           return i;
62     }
63   else
64     {
65       for (i = 0; i < coverage->Count; i++)
66         if (coverage->table.RangeRecord[i].Start <= id
67             && coverage->table.RangeRecord[i].End >= id)
68           return (coverage->table.RangeRecord[i].StartCoverageIndex
69                   + (id - coverage->table.RangeRecord[i].Start));
70     }
71   return -1;
72 }
73
74 static unsigned
75 get_class_def (OTF_ClassDef *class_def, OTF_GlyphID glyph_id)
76 {
77   if (class_def->ClassFormat == 1)
78     {
79       int idx = (int) glyph_id - (int) class_def->f.f1.StartGlyph;
80
81       if (idx >= 0 && idx < class_def->f.f1.GlyphCount)
82         return class_def->f.f1.ClassValueArray[idx];
83     }
84   else
85     {
86       int i;
87
88       for (i = 0; i < class_def->f.f2.ClassRangeCount; i++)
89         if (glyph_id >= class_def->f.f2.ClassRangeRecord[i].Start
90             && glyph_id <= class_def->f.f2.ClassRangeRecord[i].End)
91           return class_def->f.f2.ClassRangeRecord[i].Class;
92     }
93   return 0;
94 }
95
96 static OTF_LangSys *
97 get_langsys (OTF_ScriptList *script_list, char *script, char *language)
98 {
99
100   OTF_Tag script_tag = OTF_tag (script);
101   OTF_Tag langsys_tag = OTF_tag (language);
102   int i, j;
103
104   for (i = 0; i < script_list->ScriptCount; i++)
105     if (script_list->Script[i].ScriptTag == script_tag)
106       {
107         OTF_Script *script = script_list->Script + i;
108
109         if (! langsys_tag)
110           return &script->DefaultLangSys;
111         for (j = 0; j < script->LangSysCount; j++)
112           if (script->LangSysRecord[j].LangSysTag == langsys_tag)
113             return script->LangSys + j;
114         return &script->DefaultLangSys; 
115       }
116
117   return NULL;
118 }
119
120 static int
121 get_feature_index (OTF_LangSys *LangSys, OTF_FeatureList *FeatureList,
122                    char *features, int *feature_index)
123 {
124   int nfeatures = 0;
125
126   if (features)
127     {
128       char *p0, *p1;
129       int len = strlen (features) + 1;
130
131       p0 = alloca (len);
132       for (p1 = p0; *p1; p1++)
133         if (*p1 == ',')
134           *p1 = '\0';
135       
136       while (len > 0)
137         {
138           int this_len = strlen (p0) + 1;
139           OTF_Tag tag = OTF_tag (p0);
140
141           if (tag)
142             {
143               int i;
144
145               for (i = 0; i < FeatureList->FeatureCount; i++)
146                 if (tag == FeatureList->Feature[i].FeatureTag)
147                   {
148                     feature_index[nfeatures++] = i;
149                     if (nfeatures == FeatureList->FeatureCount)
150                       break;
151                   }
152             }
153           p0 += this_len;
154           len -= this_len;
155         }
156     }
157   else
158     {
159       for (; nfeatures < LangSys->FeatureCount; nfeatures++)
160         feature_index[nfeatures] = LangSys->FeatureIndex[nfeatures];
161     }
162
163   return nfeatures;
164 }
165
166 static int
167 match_ids (OTF_GlyphString *gstring, int gidx, int count, OTF_GlyphID *ids)
168 {
169   int i;
170
171   if (gstring->used - gidx < count)
172     return -1;
173   for (i = 0; i < count; i++)
174     if (gstring->glyphs[gidx + i].glyph_id != ids[i])
175       return -1;
176   return 0;
177 }
178
179 static int
180 match_classes (OTF_ClassDef *class_def, OTF_GlyphString *gstring, int gidx,
181                int count, unsigned *classes)
182 {
183   int i;
184
185   if (gstring->used - gidx < count)
186     return -1;
187   for (i = 0; i < count; i++)
188     if (get_class_def (class_def, gstring->glyphs[gidx + i].glyph_id)
189         != classes[i])
190       return -1;
191   return 0;
192 }
193
194 static int
195 lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
196              OTF_GlyphString *gstring, int gidx)
197 {
198   char *errfmt = "GSUB Looking up%s";
199   int errret = -1;
200   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
201   unsigned int flag = lookup->LookupFlag;
202   int orig_gidx = gidx;
203   OTF_Glyph *g = gstring->glyphs + gidx;
204   int i;
205
206   if (! g->glyph_id
207       || (g->GlyphClass
208           && (flag & (1 << g->GlyphClass))))
209     return (gidx + 1);
210
211   /* Try all subtables until one of them handles the current glyph.  */
212   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
213     {
214       OTF_LookupSubTableGSUB *subtable = lookup->SubTable.gsub + i;
215       int coverage_idx;
216
217       if (subtable->Coverage.offset)
218         {
219           coverage_idx = get_coverage_index (&subtable->Coverage,
220                                              g->glyph_id);
221           if (coverage_idx < 0)
222             continue;
223         }
224
225       switch (lookup->LookupType)
226         {
227         case 1:
228           if (subtable->Format == 1)
229             g->glyph_id += subtable->u.single1.DeltaGlyphID;
230           else
231             g->glyph_id = subtable->u.single2.Substitute[coverage_idx];
232           gidx++;
233           break;
234
235         case 2:
236           {
237             OTF_GSUB_Multiple1 *multiple1 = &subtable->u.multiple1;
238             OTF_Sequence *seq = multiple1->Sequence + coverage_idx;
239
240             gstring_subst (gstring, gidx, gidx + 1,
241                            seq->Substitute, seq->GlyphCount);
242             gidx += seq->GlyphCount;
243           }
244           break;
245
246         case 3:
247           if (subtable->Format == 1)
248             {
249               OTF_GSUB_Alternate1 *alt1 = &subtable->u.alternate1;
250               OTF_AlternateSet *altset = alt1->AlternateSet + coverage_idx;
251
252               g->glyph_id = altset->Alternate[0];
253               gidx++;
254             }
255           else
256             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
257           break;
258
259         case 4:
260           if (subtable->Format == 1)
261             {
262               OTF_GSUB_Ligature1 *lig1 = &subtable->u.ligature1;
263               OTF_LigatureSet *ligset = lig1->LigatureSet + coverage_idx;
264               OTF_Ligature *lig;
265               int j;
266
267               for (j = 0; j < ligset->LigatureCount; j++)
268                 {
269                   lig = ligset->Ligature + j;
270                   if (match_ids (gstring, gidx + 1,
271                                  lig->CompCount - 1, lig->Component) < 0)
272                     continue;
273                   gstring_subst (gstring, gidx, gidx + lig->CompCount,
274                                  &lig->LigGlyph, 1);
275                   gidx++;
276                   break;
277                 }
278             }
279           else
280             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
281           break;
282               
283         case 5:
284           if (subtable->Format == 1)
285             {
286               OTF_GSUB_Context1 *context1 = &subtable->u.context1; 
287               OTF_RuleSet *set = context1->SubRuleSet + coverage_idx;
288               OTF_Rule *rule;
289               int orig_used;
290               int j, k;
291
292               for (j = 0; j < set->RuleCount; j++)
293                 {
294                   rule = set->Rule + j;
295                   if (match_ids (gstring, gidx + 1,
296                                  rule->GlyphCount - 1, rule->Input) < 0)
297                     continue;
298                   orig_used = gstring->used;
299                   for (k = 0; k < rule->LookupCount; k++)
300                     lookup_gsub (lookup_list,
301                                  rule->LookupRecord[k].LookupListIndex,
302                                  gstring,
303                                  gidx + rule->LookupRecord[k].SequenceIndex);
304                   gidx += rule->GlyphCount + (gstring->used - orig_used);
305                   break;
306                 }
307             }
308           else if (subtable->Format == 2)
309             {
310               OTF_GSUB_Context2 *context2 = &subtable->u.context2; 
311               OTF_ClassSet *set;
312               OTF_ClassRule *rule;
313               unsigned class;
314               int orig_used;
315               int j, k;
316
317               class = get_class_def (&context2->ClassDef, g->glyph_id);
318               set = context2->SubClassSet + class;
319               for (j = 0; j < set->ClassRuleCnt; j++)
320                 {
321                   rule = set->ClassRule + j;
322                   if (match_classes (&context2->ClassDef,
323                                      gstring, gidx + 1,
324                                      rule->GlyphCount - 1, rule->Class)
325                       < 0)
326                     continue;
327                   orig_used = gstring->used;
328                   for (k = 0; k < rule->LookupCount; k++)
329                     lookup_gsub (lookup_list,
330                                  rule->LookupRecord[k].LookupListIndex,
331                                  gstring,
332                                  gidx + rule->LookupRecord[k].SequenceIndex);
333                   gidx += rule->GlyphCount + (gstring->used - orig_used);
334                   break;
335                 }
336             }
337           else                  /* subtable->Format == 3 */
338             {
339               OTF_GSUB_Context3 *context3 = &subtable->u.context3; 
340               int orig_used;
341               int j, k;
342
343               if (gstring->used - gidx < context3->GlyphCount)
344                 continue;
345               /* Start from the secoding coverage_idx because the
346                  first one is the same as subtable->Coverage and thus
347                  already tested */
348               for (j = 1; j < context3->GlyphCount; j++)
349                 if (get_coverage_index (context3->Coverage + j,
350                                         gstring->glyphs[gidx + j].glyph_id)
351                     < 0)
352                   break;
353               if (j < context3->GlyphCount)
354                 continue;
355               orig_used = gstring->used;
356               for (k = 0; k < context3->SubstCount; k++)
357                 lookup_gsub (lookup_list,
358                              context3->LookupRecord[k].LookupListIndex,
359                              gstring,
360                              gidx + context3->LookupRecord[k].SequenceIndex);
361               gidx += context3->GlyphCount + (gstring->used - orig_used);
362             }
363           break;
364
365         case 6:
366           if (subtable->Format == 1)
367             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (not yet supported)");
368           else if (subtable->Format == 2)
369             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (not yet supported)");
370           else
371             {
372               OTF_GSUB_ChainContext3 *context3
373                 = &subtable->u.chain_context3;
374               int back_gidx = gidx - context3->BacktrackGlyphCount;
375               int fore_gidx = gidx + context3->InputGlyphCount;
376               int orig_used;
377               int j;
378
379               if (back_gidx < 0
380                   || fore_gidx + context3->LookaheadGlyphCount > gstring->used)
381                 break;
382
383               for (j = 0; j < context3->BacktrackGlyphCount; j++)
384                 if (get_coverage_index (context3->Backtrack + j,
385                                         gstring->glyphs[back_gidx + j].glyph_id)
386                     < 0)
387                   break;
388               if (j < context3->BacktrackGlyphCount)
389                 continue;
390
391               /* Start from the secode coverage_idx because the first
392                  one is the same as subtable->Coverage and thus
393                  already tested */
394               for (j = 1; j < context3->InputGlyphCount; j++)
395                 if (get_coverage_index (context3->Input + j,
396                                         gstring->glyphs[gidx + j].glyph_id)
397                     < 0)
398                   break;
399               if (j < context3->InputGlyphCount)
400                 continue;
401
402               for (j = 0; j < context3->LookaheadGlyphCount; j++)
403                 if (get_coverage_index (context3->LookAhead + j,
404                                         gstring->glyphs[fore_gidx + j].glyph_id)
405                     < 0)
406                   break;
407               if (j < context3->LookaheadGlyphCount)
408                 continue;
409
410               orig_used = gstring->used;
411               for (j = 0; j < context3->SubstCount; j++)
412                 lookup_gsub (lookup_list,
413                              context3->LookupRecord[j].LookupListIndex,
414                              gstring,
415                              gidx + context3->LookupRecord[j].SequenceIndex);
416               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
417             }
418           break;
419
420         default:
421           continue;
422         }
423     }
424   if (gidx == orig_gidx)
425     {
426       //printf ("not applied\n");
427       gidx++;
428     }
429   else
430     {
431       // printf ("done\n");
432     }
433   return gidx;
434 }
435
436 \f
437
438 /* GPOS */
439 unsigned
440 get_anchor (OTF_Anchor *anchor, OTF_ValueRecord *rec)
441 {
442   unsigned value_format = OTF_XPlacement | OTF_YPlacement;
443
444   rec->XPlacement = anchor->XCoordinate;
445   rec->YPlacement = anchor->YCoordinate;
446   if (anchor->AnchorFormat == 1)
447     /* Nothing to do */
448     ;
449   else if (anchor->AnchorFormat == 2)
450     /* Not yet implemented */
451     ;
452   else if (anchor->AnchorFormat == 3)
453     /* Not yet implemented */
454     ;
455   return value_format;
456 }
457
458
459 static int
460 lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
461              OTF_GlyphString *gstring, int gidx)
462 {
463   char *errfmt = "GPOS Looking up%s";
464   int errret = -1;
465   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
466   unsigned int flag = lookup->LookupFlag;
467   int orig_gidx = gidx;
468   OTF_Glyph *g = gstring->glyphs + gidx;
469   int i;
470
471   if (! g->glyph_id
472       || (g->GlyphClass
473           && (flag & (1 << g->GlyphClass))))
474     return (gidx + 1);
475
476   /* Try all subtables until one of them handles the current glyph.  */
477   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
478     {
479       OTF_LookupSubTableGPOS *subtable = lookup->SubTable.gpos + i;
480       int coverage_idx;
481
482       // printf ("subtype:%d ", subtable->Format);
483       if (subtable->Coverage.offset)
484         {
485           coverage_idx = get_coverage_index (&subtable->Coverage,
486                                              g->glyph_id);
487           if (coverage_idx < 0)
488             {
489               // printf ("not covererd ");
490               continue;
491             }
492         }
493
494       switch (lookup->LookupType)
495         {
496         case 1:
497           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
498
499         case 2:
500           if (gidx + 1 >= gstring->used)
501             continue;
502           if (subtable->Format == 1)
503             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
504           else if (subtable->Format == 2)
505             {
506               OTF_GPOS_Pair2 *pair2 = &subtable->u.pair2;
507               unsigned class1, class2;
508
509               printf ("GPOS 2-2: c:0x%x g:0x%x\n", g->c, g->glyph_id);
510               gidx++;
511               class1 = get_class_def (&pair2->ClassDef1, g->glyph_id);
512               class2 = get_class_def (&pair2->ClassDef2, g[1].glyph_id);
513               g->positioning_type = lookup->LookupType;
514               g->f.f2.format = pair2->ValueFormat1;
515               g->f.f2.value
516                 = &pair2->Class1Record[class1].Class2Record[class2].Value1;
517               if (pair2->ValueFormat2)
518                 {
519                   g++, gidx++;
520                   g->positioning_type = lookup->LookupType;
521                   g->f.f2.format = pair2->ValueFormat2;
522                   g->f.f2.value
523                     = &pair2->Class1Record[class1].Class2Record[class2].Value2;
524                 }
525             }
526           break;
527
528         case 3:
529           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
530
531         case 4:
532           if (gidx < 1)
533             continue;
534           if (subtable->Format == 1)
535             {
536               OTF_GPOS_MarkBase1 *mark_base1 = &subtable->u.mark_base1;
537               OTF_MarkRecord *mark_record;
538               OTF_AnchorRecord *base_record;
539               int coverage_idx_base
540                 = get_coverage_index (&mark_base1->BaseCoverage,
541                                       g[-1].glyph_id);
542
543               if (coverage_idx_base < 0)
544                 continue;
545               printf ("GPOS 4-1: c:0x%x g:0x%x\n", g->c, g->glyph_id);
546               mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx;
547               base_record
548                 = mark_base1->BaseArray.AnchorRecord + coverage_idx_base;
549               g->f.f4.mark_anchor = &mark_record->MarkAnchor;
550               g->f.f4.base_anchor
551                 = &base_record->Anchor[mark_record->Class];
552               g->positioning_type = lookup->LookupType;
553               break;
554             }
555           else
556             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
557           break;
558               
559         case 5:
560           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
561           break;
562
563         case 6:
564           if (gidx < 1)
565             continue;
566           if (subtable->Format == 1)
567             {
568               OTF_GPOS_MarkMark1 *mark_mark1 = &subtable->u.mark_mark1;
569               OTF_MarkRecord *mark1_record;
570               OTF_AnchorRecord *mark2_record;
571               int coverage_idx_base
572                 = get_coverage_index (&mark_mark1->Mark2Coverage,
573                                       g[-1].glyph_id);
574
575               if (coverage_idx_base < 0)
576                 continue;
577               printf ("GPOS 6-1: c:0x%x g:0x%x\n", g->c, g->glyph_id);
578               mark1_record = mark_mark1->Mark1Array.MarkRecord + coverage_idx;
579               mark2_record
580                 = mark_mark1->Mark2Array.AnchorRecord + coverage_idx_base;
581               g->f.f6.mark1_anchor = &mark1_record->MarkAnchor;
582               g->f.f6.mark2_anchor
583                 = &mark2_record->Anchor[mark1_record->Class];
584               g->positioning_type = lookup->LookupType;
585               break;
586             }
587           else
588             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
589           break;
590
591         case 7:
592           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
593           break;
594
595         case 8:
596           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
597           break;
598
599         case 9:
600           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
601           break;
602
603         default:
604           continue;
605         }
606     }
607   if (gidx == orig_gidx)
608     {
609       // printf ("not applied\n");
610       gidx++;
611     }
612   else
613     {
614       // printf ("done\n");
615     }
616   return gidx;
617 }
618
619 static int
620 lookup_cmap (OTF_cmap *cmap, int c)
621 {
622   int i;
623
624   if (! cmap || ! cmap->Unicode)
625     return 0;
626
627   switch (cmap->Unicode->subtable.format)
628     {
629     case 0:
630       break;
631
632     case 4:
633       {
634         OTF_EncodingSubtable4 *sub4 = cmap->Unicode->subtable.f.f4;
635         int segCount = sub4->segCountX2 / 2;
636
637         for (i = 0; i < segCount; i++)
638           if (c <= sub4->segments[i].endCount)
639             break;
640         if (i == segCount || c < sub4->segments[i].startCount)
641           return 0;
642         if (sub4->segments[i].idRangeOffset == 0xFFFF)
643           return c + sub4->segments[i].idDelta;
644         return sub4->glyphIdArray[sub4->segments[i].idRangeOffset
645                                   + (c - sub4->segments[i].startCount)];
646       }
647       break;
648     }
649   return 0;
650 }
651
652 \f
653
654 /* APIs */
655
656 int
657 OTF_drive_cmap (OTF *otf, OTF_GlyphString *gstring)
658 {
659   OTF_cmap *cmap;
660   int i;
661
662   if (! otf->cmap
663       && OTF_get_table (otf, "cmap") < 0)
664     return -1;
665
666   cmap = otf->cmap;
667   for (i = 0; i < gstring->used; i++)
668       gstring->glyphs[i].glyph_id = lookup_cmap (cmap, gstring->glyphs[i].c);
669
670   return 0;
671 }
672
673
674 int
675 OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring)
676 {
677   OTF_GDEF *gdef;
678   int i;
679
680   if (! otf->gdef
681       && OTF_get_table (otf, "GDEF") < 0)
682     return -1;
683   gdef = otf->gdef;
684
685   if (gdef->glyph_class_def.offset)
686     for (i = 0; i < gstring->used; i++)
687       gstring->glyphs[i].GlyphClass
688         = get_class_def (&gdef->glyph_class_def,
689                          gstring->glyphs[i].glyph_id);
690
691   if (gdef->mark_attach_class_def.offset)
692     for (i = 0; i < gstring->used; i++)
693       gstring->glyphs[i].MarkAttachClass
694         = get_class_def (&gdef->mark_attach_class_def,
695                          gstring->glyphs[i].glyph_id);
696
697   return 0;
698 }
699
700
701 int
702 OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring,
703                 char *script, char *language, char *features)
704 {
705   char *errfmt = "GSUB driving%s";
706   int errret = -1;
707   OTF_GSUB *gsub;
708   OTF_LangSys *LangSys;
709   int nfeatures;
710   int *feature_index;
711   int i, j;
712
713   if (! otf->gsub
714       && OTF_get_table (otf, "GSUB") < 0)
715     return -1;
716   gsub = otf->gsub;
717
718   LangSys = get_langsys (&gsub->ScriptList, script, language);
719   if (! LangSys)
720     return -1;
721
722   feature_index = alloca (sizeof (int) * gsub->FeatureList.FeatureCount);
723   if (! feature_index)
724     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
725
726   nfeatures = get_feature_index (LangSys, &gsub->FeatureList,
727                                  features, feature_index);
728   if (nfeatures == 0)
729     OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " no feature");
730
731   for (i = 0; i < nfeatures; i++)
732     {
733       OTF_Feature *feature = gsub->FeatureList.Feature + feature_index[i];
734
735       for (j = 0; j < feature->LookupCount; j++)
736         {
737           int gidx = 0;
738
739           while (gidx < gstring->used)
740             gidx = lookup_gsub (&gsub->LookupList, feature->LookupListIndex[j],
741                                 gstring, gidx);
742         }
743     }
744
745   return 0;
746 }
747
748 int
749 OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring,
750                 char *script, char *language, char *features)
751 {
752   char *errfmt = "GPOS driving%s";
753   int errret = -1;
754   OTF_GPOS *gpos;
755   OTF_LangSys *LangSys;
756   int nfeatures;
757   int *feature_index;
758   int i, j;
759
760   if (! otf->gpos
761       && OTF_get_table (otf, "GPOS") < 0)
762     return -1;
763   gpos = otf->gpos;
764
765   LangSys = get_langsys (&gpos->ScriptList, script, language);
766   if (! LangSys)
767     return -1;
768
769   feature_index = alloca (sizeof (int) * gpos->FeatureList.FeatureCount);
770   if (! feature_index)
771     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
772
773   nfeatures = get_feature_index (LangSys, &gpos->FeatureList,
774                                  features, feature_index);
775   if (nfeatures == 0)
776     OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " no feature");
777
778   for (i = 0; i < nfeatures; i++)
779     {
780       OTF_Feature *feature = gpos->FeatureList.Feature + feature_index[i];
781
782       for (j = 0; j < feature->LookupCount; j++)
783         {
784           int gidx = 0;
785
786           while (gidx < gstring->used)
787             gidx = lookup_gpos (&gpos->LookupList, feature->LookupListIndex[j],
788                                 gstring, gidx);
789         }
790     }
791
792   return 0;
793 }
794
795 int
796 OTF_drive_tables (OTF *otf, OTF_GlyphString *gstring,
797                   char *script, char *language,
798                   char *gsub_features, char *gpos_features)
799 {
800   if (OTF_drive_cmap (otf, gstring) < 0)
801     return -1;
802   if (OTF_drive_gdef (otf, gstring) < 0)
803     return -1;
804   if ((! gsub_features || gsub_features[0])
805       && OTF_drive_gsub (otf, gstring, script, language, gsub_features) < 0)
806     return -1;
807   if ((! gpos_features || gpos_features[0])
808       && OTF_drive_gpos (otf, gstring, script, language, gpos_features) < 0)
809     return -1;
810   return 0;
811 }