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