*** 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 lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
168              OTF_GlyphString *gstring, int gidx)
169 {
170   char *errfmt = "GSUB Looking up%s";
171   int errret = -1;
172   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
173   unsigned int flag = lookup->LookupFlag;
174   int orig_gidx = gidx;
175   OTF_Glyph *g = gstring->glyphs + gidx;
176   int i;
177
178   if (! g->glyph_id
179       || (g->GlyphClass
180           && (flag & (1 << g->GlyphClass))))
181     return (gidx + 1);
182
183   /* Try all subtables until one of them handles the current glyph.  */
184   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
185     {
186       OTF_LookupSubTableGSUB *subtable = lookup->SubTable.gsub + i;
187       int coverage_idx;
188
189       if (subtable->Coverage.offset)
190         {
191           coverage_idx = get_coverage_index (&subtable->Coverage,
192                                              g->glyph_id);
193           if (coverage_idx < 0)
194             continue;
195         }
196
197       switch (lookup->LookupType)
198         {
199         case 1:
200           if (subtable->Format == 1)
201             g->glyph_id += subtable->u.single1.DeltaGlyphID;
202           else
203             g->glyph_id = subtable->u.single2.Substitute[coverage_idx];
204           gidx++;
205           break;
206
207         case 2:
208           {
209             OTF_GSUB_Multiple1 *multiple1 = &subtable->u.multiple1;
210             OTF_Sequence *seq = multiple1->Sequence + coverage_idx;
211
212             gstring_subst (gstring, gidx, gidx + 1,
213                            seq->Substitute, seq->GlyphCount);
214             gidx += seq->GlyphCount;
215           }
216           break;
217
218         case 3:
219           OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (LookupType not yet supported)");
220
221         case 4:
222           if (subtable->Format == 1)
223             {
224               OTF_GSUB_Ligature1 *lig1 = &subtable->u.ligature1;
225               OTF_LigatureSet *ligset = lig1->LigatureSet + coverage_idx;
226               int j;
227
228               for (j = 0; j < ligset->LigatureCount; j++)
229                 {
230                   OTF_Ligature *lig = ligset->Ligature + j;
231                   int k;
232
233                   if (gstring->used - gidx < lig->CompCount)
234                     continue;
235                   for (k = 1; k < lig->CompCount; k++)
236                     if (gstring->glyphs[gidx + k].glyph_id
237                         != lig->Component[k - 1])
238                       break;
239                   if (k < lig->CompCount)
240                     continue;
241                   gstring_subst (gstring, gidx, gidx + lig->CompCount,
242                                  &lig->LigGlyph, 1);
243                   gidx++;
244                   break;
245                 }
246             }
247           else
248             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
249           break;
250               
251         case 6:
252           if (subtable->Format == 1)
253             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (not yet supported)");
254           else if (subtable->Format == 2)
255             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (not yet supported)");
256           else
257             {
258               OTF_GSUB_ChainContext3 *context3
259                 = &subtable->u.chain_context3;
260               int back_gidx = gidx - context3->BacktrackGlyphCount;
261               int fore_gidx = gidx + context3->InputGlyphCount;
262               int orig_used;
263               int j;
264
265               if (back_gidx < 0
266                   || fore_gidx + context3->LookaheadGlyphCount > gstring->used)
267                 break;
268
269               for (j = 0; j < context3->BacktrackGlyphCount; j++)
270                 if (get_coverage_index (context3->Backtrack + j,
271                                         gstring->glyphs[back_gidx + j].glyph_id)
272                     < 0)
273                   break;
274               if (j < context3->BacktrackGlyphCount)
275                 continue;
276
277               /* Start from the secoding coverage_idx because the
278                  first one is the same as subtable->Coverage and thus
279                  already tested */
280               for (j = 1; j < context3->InputGlyphCount; j++)
281                 if (get_coverage_index (context3->Input + j - 1,
282                                         gstring->glyphs[gidx + j].glyph_id)
283                     < 0)
284                   break;
285               if (j < context3->InputGlyphCount)
286                 continue;
287
288               for (j = 0; j < context3->LookaheadGlyphCount; j++)
289                 if (get_coverage_index (context3->LookAhead + j,
290                                         gstring->glyphs[fore_gidx + j].glyph_id)
291                     < 0)
292                   break;
293               if (j < context3->LookaheadGlyphCount)
294                 continue;
295
296               orig_used = gstring->used;
297               for (j = 0; j < context3->SubstCount; j++)
298                 lookup_gsub (lookup_list,
299                              context3->SubstLookupRecord[j].LookupListIndex,
300                              gstring,
301                              gidx + context3->SubstLookupRecord[j].SequenceIndex);
302               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
303             }
304           break;
305
306         default:
307           continue;
308         }
309     }
310   if (gidx == orig_gidx)
311     {
312       //printf ("not applied\n");
313       gidx++;
314     }
315   else
316     {
317       // printf ("done\n");
318     }
319   return gidx;
320 }
321
322 \f
323
324 /* GPOS */
325 unsigned
326 get_anchor (OTF_Anchor *anchor, OTF_ValueRecord *rec)
327 {
328   unsigned value_format = OTF_XPlacement | OTF_YPlacement;
329
330   rec->XPlacement = anchor->XCoordinate;
331   rec->YPlacement = anchor->YCoordinate;
332   if (anchor->AnchorFormat == 1)
333     /* Nothing to do */
334     ;
335   else if (anchor->AnchorFormat == 2)
336     /* Not yet implemented */
337     ;
338   else if (anchor->AnchorFormat == 3)
339     /* Not yet implemented */
340     ;
341   return value_format;
342 }
343
344
345 static int
346 lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
347              OTF_GlyphString *gstring, int gidx)
348 {
349   char *errfmt = "GPOS Looking up%s";
350   int errret = -1;
351   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
352   unsigned int flag = lookup->LookupFlag;
353   int orig_gidx = gidx;
354   OTF_Glyph *g = gstring->glyphs + gidx;
355   int i;
356
357   if (! g->glyph_id
358       || (g->GlyphClass
359           && (flag & (1 << g->GlyphClass))))
360     return (gidx + 1);
361
362   /* Try all subtables until one of them handles the current glyph.  */
363   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
364     {
365       OTF_LookupSubTableGPOS *subtable = lookup->SubTable.gpos + i;
366       int coverage_idx;
367
368       // printf ("subtype:%d ", subtable->Format);
369       if (subtable->Coverage.offset)
370         {
371           coverage_idx = get_coverage_index (&subtable->Coverage,
372                                              g->glyph_id);
373           if (coverage_idx < 0)
374             {
375               // printf ("not covererd ");
376               continue;
377             }
378         }
379
380       switch (lookup->LookupType)
381         {
382         case 1:
383           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
384
385         case 2:
386           if (gidx + 1 >= gstring->used)
387             continue;
388           if (subtable->Format == 1)
389             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
390           else if (subtable->Format == 2)
391             {
392               OTF_GPOS_Pair2 *pair2 = &subtable->u.pair2;
393               unsigned class1, class2;
394
395               printf ("GPOS 2-2: c:0x%x g:0x%x\n", g->c, g->glyph_id);
396               gidx++;
397               class1 = get_class_def (&pair2->ClassDef1, g->glyph_id);
398               class2 = get_class_def (&pair2->ClassDef2, g[1].glyph_id);
399               g->positioning_type = lookup->LookupType;
400               g->f.f2.format = pair2->ValueFormat1;
401               g->f.f2.value
402                 = &pair2->Class1Record[class1].Class2Record[class2].Value1;
403               if (pair2->ValueFormat2)
404                 {
405                   g++, gidx++;
406                   g->positioning_type = lookup->LookupType;
407                   g->f.f2.format = pair2->ValueFormat2;
408                   g->f.f2.value
409                     = &pair2->Class1Record[class1].Class2Record[class2].Value2;
410                 }
411             }
412           break;
413
414         case 3:
415           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
416
417         case 4:
418           if (gidx < 1)
419             continue;
420           if (subtable->Format == 1)
421             {
422               OTF_GPOS_MarkBase1 *mark_base1 = &subtable->u.mark_base1;
423               OTF_MarkRecord *mark_record;
424               OTF_BaseRecord *base_record;
425               int coverage_idx_base
426                 = get_coverage_index (&mark_base1->BaseCoverage,
427                                       g[-1].glyph_id);
428
429               if (coverage_idx_base < 0)
430                 continue;
431               printf ("GPOS 4-1: c:0x%x g:0x%x\n", g->c, g->glyph_id);
432               mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx;
433               base_record
434                 = mark_base1->BaseArray.BaseRecord + coverage_idx_base;
435               g->f.f4.mark_anchor = &mark_record->MarkAnchor;
436               g->f.f4.base_anchor
437                 = &base_record->BaseAnchor[mark_record->Class];
438               g->positioning_type = lookup->LookupType;
439               break;
440             }
441           else
442             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
443           break;
444               
445         case 6:
446           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
447           break;
448
449         default:
450           continue;
451         }
452     }
453   if (gidx == orig_gidx)
454     {
455       // printf ("not applied\n");
456       gidx++;
457     }
458   else
459     {
460       // printf ("done\n");
461     }
462   return gidx;
463 }
464
465 static int
466 lookup_cmap (OTF_cmap *cmap, int c)
467 {
468   int i;
469
470   if (! cmap || ! cmap->Unicode)
471     return 0;
472
473   switch (cmap->Unicode->subtable.format)
474     {
475     case 0:
476       break;
477
478     case 4:
479       {
480         OTF_EncodingSubtable4 *sub4 = cmap->Unicode->subtable.f.f4;
481         int segCount = sub4->segCountX2 / 2;
482
483         for (i = 0; i < segCount; i++)
484           if (c <= sub4->segments[i].endCount)
485             break;
486         if (i == segCount || c < sub4->segments[i].startCount)
487           return 0;
488         if (sub4->segments[i].idRangeOffset == 0xFFFF)
489           return c + sub4->segments[i].idDelta;
490         return sub4->glyphIdArray[sub4->segments[i].idRangeOffset
491                                   + (c - sub4->segments[i].startCount)];
492       }
493       break;
494     }
495   return 0;
496 }
497
498 \f
499
500 /* APIs */
501
502 int
503 OTF_drive_cmap (OTF *otf, OTF_GlyphString *gstring)
504 {
505   OTF_cmap *cmap;
506   int i;
507
508   if (! otf->cmap
509       && OTF_get_table (otf, "cmap") < 0)
510     return -1;
511
512   cmap = otf->cmap;
513   for (i = 0; i < gstring->used; i++)
514       gstring->glyphs[i].glyph_id = lookup_cmap (cmap, gstring->glyphs[i].c);
515
516   return 0;
517 }
518
519
520 int
521 OTF_drive_gdef (OTF *otf, OTF_GlyphString *gstring)
522 {
523   OTF_GDEF *gdef;
524   int i;
525
526   if (! otf->gdef
527       && OTF_get_table (otf, "GDEF") < 0)
528     return -1;
529   gdef = otf->gdef;
530
531   if (gdef->glyph_class_def.offset)
532     for (i = 0; i < gstring->used; i++)
533       gstring->glyphs[i].GlyphClass
534         = get_class_def (&gdef->glyph_class_def,
535                          gstring->glyphs[i].glyph_id);
536
537   if (gdef->mark_attach_class_def.offset)
538     for (i = 0; i < gstring->used; i++)
539       gstring->glyphs[i].MarkAttachClass
540         = get_class_def (&gdef->mark_attach_class_def,
541                          gstring->glyphs[i].glyph_id);
542
543   return 0;
544 }
545
546
547 int
548 OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring,
549                 char *script, char *language, char *features)
550 {
551   char *errfmt = "GSUB driving%s";
552   int errret = -1;
553   OTF_GSUB *gsub;
554   OTF_LangSys *LangSys;
555   int nfeatures;
556   int *feature_index;
557   int i, j;
558
559   if (! otf->gsub
560       && OTF_get_table (otf, "GSUB") < 0)
561     return -1;
562   gsub = otf->gsub;
563
564   LangSys = get_langsys (&gsub->ScriptList, script, language);
565   if (! LangSys)
566     return -1;
567
568   feature_index = alloca (sizeof (int) * gsub->FeatureList.FeatureCount);
569   if (! feature_index)
570     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
571
572   nfeatures = get_feature_index (LangSys, &gsub->FeatureList,
573                                  features, feature_index);
574   if (nfeatures == 0)
575     OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " no feature");
576
577   for (i = 0; i < nfeatures; i++)
578     {
579       OTF_Feature *feature = gsub->FeatureList.Feature + feature_index[i];
580
581       for (j = 0; j < feature->LookupCount; j++)
582         {
583           int gidx = 0;
584
585           while (gidx < gstring->used)
586             gidx = lookup_gsub (&gsub->LookupList, feature->LookupListIndex[j],
587                                 gstring, gidx);
588         }
589     }
590
591   return 0;
592 }
593
594 int
595 OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring,
596                 char *script, char *language, char *features)
597 {
598   char *errfmt = "GPOS driving%s";
599   int errret = -1;
600   OTF_GPOS *gpos;
601   OTF_LangSys *LangSys;
602   int nfeatures;
603   int *feature_index;
604   int i, j;
605
606   if (! otf->gpos
607       && OTF_get_table (otf, "GPOS") < 0)
608     return -1;
609   gpos = otf->gpos;
610
611   LangSys = get_langsys (&gpos->ScriptList, script, language);
612   if (! LangSys)
613     return -1;
614
615   feature_index = alloca (sizeof (int) * gpos->FeatureList.FeatureCount);
616   if (! feature_index)
617     OTF_ERROR (OTF_ERROR_MEMORY, " feature list");
618
619   nfeatures = get_feature_index (LangSys, &gpos->FeatureList,
620                                  features, feature_index);
621   if (nfeatures == 0)
622     OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " no feature");
623
624   for (i = 0; i < nfeatures; i++)
625     {
626       OTF_Feature *feature = gpos->FeatureList.Feature + feature_index[i];
627
628       for (j = 0; j < feature->LookupCount; j++)
629         {
630           int gidx = 0;
631
632           while (gidx < gstring->used)
633             gidx = lookup_gpos (&gpos->LookupList, feature->LookupListIndex[j],
634                                 gstring, gidx);
635         }
636     }
637
638   return 0;
639 }
640
641 int
642 OTF_drive_tables (OTF *otf, OTF_GlyphString *gstring,
643                   char *script, char *language,
644                   char *gsub_features, char *gpos_features)
645 {
646   if (OTF_drive_cmap (otf, gstring) < 0)
647     return -1;
648   if (OTF_drive_gdef (otf, gstring) < 0)
649     return -1;
650   if ((! gsub_features || gsub_features[0])
651       && OTF_drive_gsub (otf, gstring, script, language, gsub_features) < 0)
652     return -1;
653   if ((! gpos_features || gpos_features[0])
654       && OTF_drive_gpos (otf, gstring, script, language, gpos_features) < 0)
655     return -1;
656   return 0;
657 }