*** 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 "otfutil.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 OTF_LangSys *
75 get_langsys (OTF_ScriptList *script_list,
76              OTF_Tag script_tag, OTF_Tag langsys_tag)
77 {
78   int i, j;
79
80   for (i = 0; i < script_list->ScriptCount; i++)
81     if (script_list->Script[i].ScriptTag == script_tag)
82       {
83         OTF_Script *script = script_list->Script + i;
84
85         if (! langsys_tag)
86           return &script->DefaultLangSys;
87         for (j = 0; j < script->LangSysCount; j++)
88           if (script->LangSysRecord[j].LangSysTag == langsys_tag)
89             return script->LangSys + j;
90         return &script->DefaultLangSys; 
91       }
92
93   return NULL;
94 }
95
96 static unsigned
97 get_class_def (OTF_ClassDef *class_def, OTF_GlyphID glyph_id)
98 {
99   if (class_def->ClassFormat == 1)
100     {
101       int idx = (int) glyph_id - (int) class_def->f.f1.StartGlyph;
102
103       if (idx >= 0 && idx < class_def->f.f1.GlyphCount)
104         return class_def->f.f1.ClassValueArray[idx];
105     }
106   else
107     {
108       int i;
109
110       for (i = 0; i < class_def->f.f2.ClassRangeCount; i++)
111         if (glyph_id >= class_def->f.f2.ClassRangeRecord[i].Start
112             && glyph_id >= class_def->f.f2.ClassRangeRecord[i].End)
113           return class_def->f.f2.ClassRangeRecord[i].Class;
114     }
115   return 0;
116 }
117
118
119 static int
120 lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
121              OTF_GlyphString *gstring, int gidx)
122 {
123   char *errfmt = "GSUB Looking up%s";
124   int errret = -1;
125   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
126   unsigned int flag = lookup->LookupFlag;
127   int orig_gidx = gidx;
128   OTF_Glyph *g = gstring->glyphs + gidx;
129   int i;
130
131   if (! g->glyph_id
132       || (g->GlyphClass
133           && (flag & (1 << g->GlyphClass))))
134     {
135       // printf ("type %d at %d skiped\n", lookup->LookupType, gidx);
136       return (gidx + 1);
137     }
138
139   //printf ("@%d idx:%d type:%d...",
140   //gidx, lookup_list_index, lookup->LookupType);
141
142   /* Try all subtables until one of them handles the current glyph.  */
143   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
144     {
145       OTF_LookupSubTable *subtable = lookup->SubTable + i;
146       int coverage_idx;
147
148       // printf ("subtype:%d ", subtable->Format);
149       if (subtable->Coverage.offset)
150         {
151           coverage_idx = get_coverage_index (&subtable->Coverage,
152                                              g->glyph_id);
153           if (coverage_idx < 0)
154             {
155               // printf ("not covererd ");
156               continue;
157             }
158         }
159
160       switch (lookup->LookupType)
161         {
162         case 1:
163           if (subtable->Format == 1)
164             g->glyph_id += subtable->sub.gsub.single1.DeltaGlyphID;
165           else
166             g->glyph_id = subtable->sub.gsub.single2.Substitute[coverage_idx];
167           gidx++;
168           break;
169
170         case 2:
171           {
172             OTF_GSUB_Multiple1 *multiple1 = &subtable->sub.gsub.multiple1;
173             OTF_Sequence *seq = multiple1->Sequence + coverage_idx;
174
175             gstring_subst (gstring, gidx, gidx + 1,
176                            seq->Substitute, seq->GlyphCount);
177             gidx += seq->GlyphCount;
178           }
179           break;
180
181         case 3:
182           OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (LookupType not yet supported)");
183
184         case 4:
185           if (subtable->Format == 1)
186             {
187               OTF_GSUB_Ligature1 *lig1 = &subtable->sub.gsub.ligature1;
188               OTF_LigatureSet *ligset = lig1->LigatureSet + coverage_idx;
189               int j;
190
191               for (j = 0; j < ligset->LigatureCount; j++)
192                 {
193                   OTF_Ligature *lig = ligset->Ligature + j;
194                   int k;
195
196                   if (gstring->used - gidx < lig->CompCount)
197                     continue;
198                   for (k = 1; k < lig->CompCount; k++)
199                     if (gstring->glyphs[gidx + k].glyph_id
200                         != lig->Component[k - 1])
201                       break;
202                   if (k < lig->CompCount)
203                     continue;
204                   gstring_subst (gstring, gidx, gidx + lig->CompCount,
205                                  &lig->LigGlyph, 1);
206                   gidx++;
207                   break;
208                 }
209             }
210           else
211             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
212           break;
213               
214         case 6:
215           if (subtable->Format == 1)
216             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (not yet supported)");
217           else if (subtable->Format == 2)
218             OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (not yet supported)");
219           else
220             {
221               OTF_GSUB_ChainContext3 *context3
222                 = &subtable->sub.gsub.chain_context3;
223               int back_gidx = gidx - context3->BacktrackGlyphCount;
224               int fore_gidx = gidx + context3->InputGlyphCount;
225               int orig_used;
226               int j;
227
228               if (back_gidx < 0
229                   || fore_gidx + context3->LookaheadGlyphCount > gstring->used)
230                 break;
231
232               for (j = 0; j < context3->BacktrackGlyphCount; j++)
233                 if (get_coverage_index (context3->Backtrack + j,
234                                         gstring->glyphs[back_gidx + j].glyph_id)
235                     < 0)
236                   break;
237               /* Start from the secoding coverage_idx because the
238                  first one is the same as subtable->Coverage and thus
239                  already tested */
240               for (j = 1; j < context3->InputGlyphCount; j++)
241                 if (get_coverage_index (context3->Input + j - 1,
242                                         gstring->glyphs[gidx + j].glyph_id)
243                     < 0)
244                   break;
245               for (j = 0; j < context3->LookaheadGlyphCount; j++)
246                 if (get_coverage_index (context3->LookAhead + j,
247                                         gstring->glyphs[fore_gidx + j].glyph_id)
248                     < 0)
249                   break;
250
251               orig_used = gstring->used;
252               for (j = 0; j < context3->SubstCount; j++)
253                 lookup_gsub (lookup_list,
254                              context3->SubstLookupRecord[j].LookupListIndex,
255                              gstring,
256                              gidx + context3->SubstLookupRecord[j].SequenceIndex);
257               gidx += context3->InputGlyphCount + (gstring->used - orig_used);
258             }
259           break;
260
261         default:
262           continue;
263         }
264     }
265   if (gidx == orig_gidx)
266     {
267       //printf ("not applied\n");
268       gidx++;
269     }
270   else
271     {
272       // printf ("done\n");
273     }
274   return gidx;
275 }
276
277 \f
278
279 /* GPOS */
280 unsigned
281 get_anchor (OTF_Anchor *anchor, OTF_ValueRecord *rec)
282 {
283   unsigned value_format = OTF_XPlacement | OTF_YPlacement;
284
285   rec->XPlacement = anchor->XCoordinate;
286   rec->YPlacement = anchor->YCoordinate;
287   if (anchor->AnchorFormat == 1)
288     /* Nothing to do */
289     ;
290   else if (anchor->AnchorFormat == 2)
291     /* Not yet implemented */
292     ;
293   else if (anchor->AnchorFormat == 3)
294     /* Not yet implemented */
295     ;
296   return value_format;
297 }
298
299
300 static int
301 lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
302              OTF_GlyphString *gstring, int gidx)
303 {
304   char *errfmt = "GPOS Looking up%s";
305   int errret = -1;
306   OTF_Lookup *lookup = lookup_list->Lookup + lookup_list_index;
307   unsigned int flag = lookup->LookupFlag;
308   int orig_gidx = gidx;
309   OTF_Glyph *g = gstring->glyphs + gidx;
310   int i;
311
312   if (! g->glyph_id
313       || (g->GlyphClass
314           && (flag & (1 << g->GlyphClass))))
315     {
316       // printf ("type %d at %d skiped\n", lookup->LookupType, gidx);
317       return (gidx + 1);
318     }
319
320   // printf ("0x%04X@%d idx:%d type:%d...",
321   // g->glyph_id, gidx, lookup_list_index, lookup->LookupType);
322
323   /* Try all subtables until one of them handles the current glyph.  */
324   for (i = 0; i < lookup->SubTableCount && gidx == orig_gidx; i++)
325     {
326       OTF_LookupSubTable *subtable = lookup->SubTable + i;
327       int coverage_idx;
328
329       // printf ("subtype:%d ", subtable->Format);
330       if (subtable->Coverage.offset)
331         {
332           coverage_idx = get_coverage_index (&subtable->Coverage,
333                                              g->glyph_id);
334           if (coverage_idx < 0)
335             {
336               // printf ("not covererd ");
337               continue;
338             }
339         }
340
341       switch (lookup->LookupType)
342         {
343         case 1:
344           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
345
346         case 2:
347           if (gidx + 1 >= gstring->used)
348             continue;
349           if (subtable->Format == 1)
350             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
351           else if (subtable->Format == 2)
352             {
353               OTF_GPOS_Pair2 *pair2 = &subtable->sub.gpos.pair2;
354               unsigned class1, class2;
355
356               printf ("GPOS 2-2: c:0x%x g:0x%x\n", g->c, g->glyph_id);
357               gidx++;
358               class1 = get_class_def (&pair2->ClassDef1, g->glyph_id);
359               class2 = get_class_def (&pair2->ClassDef2, g[1].glyph_id);
360               g->positioning_type = lookup->LookupType;
361               g->f.f2.format = pair2->ValueFormat1;
362               g->f.f2.value
363                 = &pair2->Class1Record[class1].Class2Record[class2].Value1;
364               if (pair2->ValueFormat2)
365                 {
366                   g++, gidx++;
367                   g->positioning_type = lookup->LookupType;
368                   g->f.f2.format = pair2->ValueFormat2;
369                   g->f.f2.value
370                     = &pair2->Class1Record[class1].Class2Record[class2].Value2;
371                 }
372             }
373           break;
374
375         case 3:
376           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
377
378         case 4:
379           if (gidx < 1)
380             continue;
381           if (subtable->Format == 1)
382             {
383               OTF_GPOS_MarkBase1 *mark_base1 = &subtable->sub.gpos.mark_base1;
384               OTF_MarkRecord *mark_record;
385               OTF_BaseRecord *base_record;
386               OTF_Anchor *anchor1, *anchor2;
387               int coverage_idx_base
388                 = get_coverage_index (&mark_base1->BaseCoverage,
389                                       g[-1].glyph_id);
390
391               if (coverage_idx_base < 0)
392                 continue;
393               printf ("GPOS 4-1: c:0x%x g:0x%x\n", g->c, g->glyph_id);
394               mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx;
395               base_record
396                 = mark_base1->BaseArray.BaseRecord + coverage_idx_base;
397               anchor1 = &mark_record->MarkAnchor;
398               anchor2 = &base_record->BaseAnchor[mark_record->Class];
399               g->positioning_type = lookup->LookupType;
400               g->f.f4.mark_anchor = anchor1;
401               g->f.f4.base_anchor = anchor2;
402               break;
403             }
404           else
405             OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
406           break;
407               
408         case 6:
409           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
410           break;
411
412         default:
413           continue;
414         }
415     }
416   if (gidx == orig_gidx)
417     {
418       // printf ("not applied\n");
419       gidx++;
420     }
421   else
422     {
423       // printf ("done\n");
424     }
425   return gidx;
426 }
427
428 static int
429 lookup_cmap (OTF_cmap *cmap, int c)
430 {
431   int i;
432
433   if (! cmap || ! cmap->Unicode)
434     return 0;
435
436   switch (cmap->Unicode->subtable.format)
437     {
438     case 0:
439       break;
440
441     case 4:
442       {
443         OTF_EncodingSubtable4 *sub4 = cmap->Unicode->subtable.f.f4;
444         int segCount = sub4->segCountX2 / 2;
445
446         for (i = 0; i < segCount; i++)
447           if (c <= sub4->segments[i].endCount)
448             break;
449         if (i == segCount || c < sub4->segments[i].startCount)
450           return 0;
451         if (sub4->segments[i].idRangeOffset == 0xFFFF)
452           return c + sub4->segments[i].idDelta;
453         return sub4->glyphIdArray[sub4->segments[i].idRangeOffset
454                                   + (c - sub4->segments[i].startCount)];
455       }
456       break;
457     }
458   return 0;
459 }
460
461 \f
462
463 /* APIs */
464
465 int
466 otf_drive_cmap (OTF *otf, OTF_GlyphString *gstring)
467 {
468   OTF_cmap *cmap;
469   int i;
470
471   if (! otf->cmap
472       && otf_get_table (otf, "cmap") < 0)
473     return -1;
474
475   cmap = otf->cmap;
476   for (i = 0; i < gstring->used; i++)
477       gstring->glyphs[i].glyph_id = lookup_cmap (cmap, gstring->glyphs[i].c);
478
479   return 0;
480 }
481
482
483 int
484 otf_drive_gdef (OTF *otf, OTF_GlyphString *gstring)
485 {
486   OTF_GDEF *gdef;
487   int i;
488
489   if (! otf->gdef
490       && otf_get_table (otf, "GDEF") < 0)
491     return -1;
492   gdef = otf->gdef;
493
494   if (gdef->glyph_class_def.offset)
495     for (i = 0; i < gstring->used; i++)
496       gstring->glyphs[i].GlyphClass
497         = get_class_def (&gdef->glyph_class_def,
498                          gstring->glyphs[i].glyph_id);
499
500   if (gdef->mark_attach_class_def.offset)
501     for (i = 0; i < gstring->used; i++)
502       gstring->glyphs[i].MarkAttachClass
503         = get_class_def (&gdef->mark_attach_class_def,
504                          gstring->glyphs[i].glyph_id);
505
506   return 0;
507 }
508
509
510 int
511 otf_drive_gsub (OTF *otf, OTF_Tag script_tag, OTF_Tag langsys_tag,
512                 OTF_GlyphString *gstring)
513 {
514   OTF_GSUB *gsub;
515   OTF_LangSys *langsys;
516   int i, j;
517
518   if (! otf->gsub
519       && otf_get_table (otf, "GSUB") < 0)
520     return -1;
521   gsub = otf->gsub;
522
523   langsys = get_langsys (&gsub->ScriptList, script_tag, langsys_tag);
524   if (! langsys)
525     return -1;
526
527   for (i = 0; i < langsys->FeatureCount; i++)
528     {
529       OTF_Feature *feature
530         = gsub->FeatureList.Feature + langsys->FeatureIndex[i];
531
532       for (j = 0; j < feature->LookupCount; j++)
533         {
534           int gidx = 0;
535
536           while (gidx < gstring->used)
537             gidx = lookup_gsub (&gsub->LookupList, feature->LookupListIndex[j],
538                                 gstring, gidx);
539         }
540     }
541
542   return 0;
543 }
544
545 int
546 otf_drive_gpos (OTF *otf, OTF_Tag script_tag, OTF_Tag langsys_tag,
547           OTF_GlyphString *gstring)
548 {
549   OTF_GPOS *gpos;
550   OTF_LangSys *langsys;
551   int i, j;
552
553   if (! otf->gpos
554       && otf_get_table (otf, "GPOS") < 0)
555     return -1;
556   gpos = otf->gpos;
557
558   langsys = get_langsys (&gpos->ScriptList, script_tag, langsys_tag);
559   if (! langsys)
560     return -1;
561
562   for (i = 0; i < langsys->FeatureCount; i++)
563     {
564       OTF_Feature *feature
565         = gpos->FeatureList.Feature + langsys->FeatureIndex[i];
566
567       for (j = 0; j < feature->LookupCount; j++)
568         {
569           int gidx = 0;
570
571           while (gidx < gstring->used)
572             gidx = lookup_gpos (&gpos->LookupList, feature->LookupListIndex[j],
573                                 gstring, gidx);
574         }
575     }
576
577   return 0;
578 }
579
580 int
581 otf_drive_table (OTF *otf, OTF_Tag script, OTF_Tag langsys,
582                  OTF_GlyphString *gstring)
583 {
584   if (otf_drive_cmap (otf, gstring) < 0)
585     return -1;
586   if (otf_drive_gdef (otf, gstring) < 0)
587     return -1;
588   if (otf_drive_gsub (otf, script, langsys, gstring) < 0)
589     return -1;
590   if (otf_drive_gpos (otf, script, langsys, gstring) < 0)
591     return -1;
592   return 0;
593 }