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