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