95145d596cebc0a132d092b581d8133647626e78
[m17n/m17n-test.git] / flt.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <ft2build.h>
4 #include FT_FREETYPE_H
5 #include FT_TRUETYPE_TABLES_H
6 #include <fontconfig/fontconfig.h>
7 #include <fontconfig/fcfreetype.h>
8
9 #if defined (FLT_GUI)
10
11 #include <m17n-gui.h>
12 #define PROGNAME "flt-gui"
13
14 #elif defined (FLT_OTF)
15
16 #include <m17n-flt.h>
17 #include <otf.h>
18 #define PROGNAME "flt-otf"
19
20 #else  /* defined (FLT_HB) */
21
22 #include <m17n-flt.h>
23 #include <harfbuzz.h>
24 #define PROGNAME "flt-hb"
25
26 #endif
27
28 static FT_Library ft_library;
29
30 FT_Face
31 new_face (char *fontname, char **err)
32 {
33   FcPattern *pat;
34   FcChar8 *fam, *file;
35   double pixelsize;
36   FcFontSet *fs;
37   FcObjectSet *os;
38   FT_Face face;
39
40   pat = FcNameParse ((FcChar8 *) fontname);
41   if (! pat)
42     {
43       *err = "invalid name format";
44       return NULL;
45     }
46   if (FcPatternGetString (pat, FC_FAMILY, 0, &fam) != FcResultMatch)
47     {
48       *err = "no family name";
49       return NULL;
50     }
51   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &pixelsize) != FcResultMatch)
52     pixelsize = 20;
53   FcPatternAddBool (pat, FC_SCALABLE, FcTrue);
54   FcPatternDel (pat, FC_PIXEL_SIZE);
55   os = FcObjectSetBuild (FC_FILE, NULL);
56   fs = FcFontList (NULL, pat, os);
57   if (fs->nfont == 0)
58     {
59       *err = "no matching font";
60       return NULL;
61     }
62   FcPatternGetString (fs->fonts[0], FC_FILE, 0, &file);
63
64   if (FT_New_Face (ft_library, (char *) file, 0, &face))
65     {
66       FcFontSetDestroy (fs);
67       FcObjectSetDestroy (os);
68       FcPatternDestroy (pat);
69       *err = "font open fail";
70       return NULL;
71     }
72   FcFontSetDestroy (fs);
73   FcObjectSetDestroy (os);
74   FcPatternDestroy (pat);
75   if (FT_Set_Pixel_Sizes (face, pixelsize, pixelsize))
76     {
77       *err = "set pixelsize fail";
78       FT_Done_Face (face);
79       return NULL;
80     }
81   return face;
82 }
83
84 #ifdef FLT_GUI
85
86 typedef struct
87 {
88   MFont *font;
89   FT_Face face;
90 } MFLTFont;
91
92 MFrame *frame;
93
94 MFLTFont *
95 open_font (char *fontname, char **err)
96 {
97   FT_Face ft_face = new_face (fontname, err);
98   MFLTFont *font;
99   MFace *face;
100   MPlist *plist;
101   MFontset *fontset;
102
103   if (! ft_face)
104     return NULL;
105   face = mface ();
106   plist = mplist ();
107   fontset = mfontset ("generic");
108   mface_put_prop (face, Mfontset, fontset);
109   mplist_add (plist, Mface, face);
110   mplist_add (plist, Mdevice, Mnil);
111   frame = mframe (plist);
112   m17n_object_unref (plist);
113   m17n_object_unref (face);
114   m17n_object_unref (fontset);
115
116   font = calloc (1, sizeof (MFLTFont));
117   font->font = mfont_encapsulate (frame, Mfreetype, ft_face);
118   font->face = ft_face;
119   return font;
120 }
121
122 void
123 close_font (MFLTFont *font)
124 {
125   FT_Done_Face (font->face);
126   free (font);
127   m17n_object_unref (frame);
128 }
129
130 int
131 flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
132 {
133   mtext_put_prop (mt, from, to, Mfont, font->font);
134   mdraw_text_extents (frame, mt, from, to, NULL, NULL, NULL, NULL);
135   return 0;
136 }
137
138 #else  /* FLT_OTF or FLT_HB */
139
140 typedef struct {
141   MFLTFont font;
142   FT_Face face;
143 } FontInfo;
144
145 int
146 get_glyph_id (MFLTFont *font, MFLTGlyph *g)
147 {
148   FT_Face face = ((FontInfo *) font)->face;
149
150   g->code = FT_Get_Char_Index (face, g->code);
151
152   return (g->code ? 0 : -1);
153 }
154
155 int 
156 get_metric (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
157 {
158   FT_Face face = ((FontInfo *) font)->face;
159
160   for (; from < to; from++)
161     {
162       MFLTGlyph *g = gstring->glyphs + from;
163       FT_Glyph_Metrics *metrics;
164
165       if (FT_Load_Glyph (face, g->code, FT_LOAD_DEFAULT))
166         return -1;
167       metrics = &face->glyph->metrics;
168       g->lbearing = metrics->horiBearingX;
169       g->rbearing = metrics->horiBearingX + metrics->width;
170       g->xadv = metrics->horiAdvance;
171       g->yadv = metrics->vertAdvance;
172       g->ascent = metrics->horiBearingY;
173       g->descent = metrics->height - metrics->horiBearingY;
174     }
175   return 0;
176 }
177
178 int
179 flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
180 {
181   MFLTGlyphString gstring;
182   int len = to - from;
183   int i;
184
185   memset (&gstring, 0, sizeof (MFLTGlyphString));
186   gstring.glyph_size = sizeof (MFLTGlyph);
187   gstring.allocated = len * 2;
188   gstring.glyphs = alloca (sizeof (MFLTGlyph) * gstring.allocated);
189   for (i = 0; i < len; i++)
190     gstring.glyphs[i].c = mtext_ref_char (mt, from + i);
191   gstring.used = len;
192   return mflt_run (&gstring, 0, len, font, msymbol (flt_name));
193 }
194
195 #ifdef FLT_OTF
196
197 typedef struct {
198   MFLTFont font;
199   FT_Face face;
200   OTF *otf;
201 } FontInfoOTF;
202
203 #define DEVICE_DELTA(table, size)                               \
204   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
205    ? ((table).DeltaValue[(size) - (table).StartSize] << 6)      \
206    : 0)
207
208 static void
209 adjust_anchor (OTF_Anchor *anchor, FT_Face face,
210                unsigned code, unsigned x_ppem, unsigned y_ppem, int *x, int *y)
211 {
212   if (anchor->AnchorFormat == 2)
213     {
214       FT_Outline *outline;
215       int ap = anchor->f.f1.AnchorPoint;
216
217       FT_Load_Glyph (face, (FT_UInt) code, FT_LOAD_MONOCHROME);
218       outline = &face->glyph->outline;
219       if (ap < outline->n_points)
220         {
221           *x = outline->points[ap].x;
222           *y = outline->points[ap].y;
223         }
224     }
225   else if (anchor->AnchorFormat == 3)
226     {
227       if (anchor->f.f2.XDeviceTable.offset)
228         *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
229       if (anchor->f.f2.YDeviceTable.offset)
230         *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
231     }
232 }
233
234 char *
235 tag_name (char *str, unsigned tag)
236 {
237   *str++ = tag >> 24;
238   *str++ = (tag >> 16) & 0xFF;
239   *str++ = (tag >> 8) & 0xFF;
240   *str++ = tag & 0xFF;
241   return str;
242 }
243
244 void
245 encode_features (char *str, int count, unsigned *features)
246 {
247   int all = 0;
248   int i;
249
250   for (i = 0; i < count; i++)
251     {
252       unsigned tag = features[i];
253
254       if (tag == 0)
255         all = 1;
256       else
257         {
258           if (i > 0)
259             *str++ = ',';
260           if (all)
261             *str++ = '~';
262           str = tag_name (str, tag);
263         }
264     }
265   if (all)
266     {
267       if (i > 1)
268         *str++ = ',';
269       *str++ = '*';
270     }
271   *str = '\0';
272 }
273
274 int
275 drive_otf (MFLTFont *font, MFLT_OTF_Spec *spec,
276            MFLTGlyphString *in, int from, int to,
277            MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
278 {
279   int len = to - from;
280   int i, gidx;
281   OTF *otf = ((FontInfoOTF *) font)->otf;
282   OTF_GlyphString otf_gstring;
283   OTF_Glyph *otfg;
284   char script[4], langsys[4];
285   char *gsub_features = NULL, *gpos_features = NULL;
286
287   if (len == 0)
288     return from;
289
290   if (! otf)
291     goto simple_copy;
292   otf_gstring.glyphs = NULL;
293   if (OTF_get_table (otf, "head") < 0)
294     {
295       OTF_close (otf);
296       ((FontInfoOTF *) font)->otf = NULL;
297       goto simple_copy;
298     }
299
300   tag_name (script, spec->script);
301   tag_name (langsys, spec->langsys);
302
303   if (spec->gsub_count > 0)
304     {
305       gsub_features = alloca (6 * spec->gsub_count);
306       if (gsub_features)
307         {
308           if (OTF_check_table (otf, "GSUB") < 0)
309             gsub_features = NULL;
310           else
311             encode_features (gsub_features, spec->gsub_count, spec->gsub);
312         }
313     }
314   if (spec->gpos_count)
315     {
316       gpos_features = alloca (6 * spec->gpos_count);
317       if (gpos_features)
318         {
319           if (OTF_check_table (otf, "GPOS") < 0)
320             gpos_features = NULL;
321           else
322             encode_features (gpos_features, spec->gpos_count, spec->gpos);
323         }
324     }
325
326   otf_gstring.size = otf_gstring.used = len;
327   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
328   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
329   for (i = 0; i < len; i++)
330     {
331       otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
332       otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
333     }
334
335   OTF_drive_gdef (otf, &otf_gstring);
336   gidx = out->used;
337
338   if (gsub_features)
339     {
340       if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
341           < 0)
342         goto simple_copy;
343       if (out->allocated < out->used + otf_gstring.used)
344         return -2;
345       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
346         {
347           MFLTGlyph *g = out->glyphs + out->used;
348
349           *g = in->glyphs[from + otfg->f.index.from];
350           g->c = otfg->c;
351           g->code = otfg->glyph_id;
352           out->used++;
353         }
354     }
355   else
356     {
357       if (out->allocated < out->used + len)
358         return -2;
359       for (i = 0; i < len; i++)
360         out->glyphs[out->used++] = in->glyphs[from + i];
361     }
362
363   font->get_metric (font, out, gidx, out->used);
364
365   if (gpos_features)
366     {
367       FT_Face face;
368       MFLTGlyph *base = NULL, *mark = NULL, *g;
369       int x_ppem, y_ppem, x_scale, y_scale;
370
371       if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
372           < 0)
373         return to;
374
375       face = ((FontInfo *) font)->face;
376       x_ppem = face->size->metrics.x_ppem;
377       y_ppem = face->size->metrics.y_ppem;
378       x_scale = face->size->metrics.x_scale;
379       y_scale = face->size->metrics.y_scale;
380
381       for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
382            i < otf_gstring.used; i++, otfg++, g++)
383         {
384           MFLTGlyph *prev;
385
386           if (! otfg->glyph_id)
387             continue;
388           switch (otfg->positioning_type)
389             {
390             case 0:
391               break;
392             case 1: case 2:
393               {
394                 int format = otfg->f.f1.format;
395
396                 if (format & OTF_XPlacement)
397                   adjustment[i].xoff
398                     = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
399                 if (format & OTF_XPlaDevice)
400                   adjustment[i].xoff
401                     += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
402                 if (format & OTF_YPlacement)
403                   adjustment[i].yoff
404                     = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
405                 if (format & OTF_YPlaDevice)
406                   adjustment[i].yoff
407                     -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
408                 if (format & OTF_XAdvance)
409                   adjustment[i].xadv
410                     += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
411                 if (format & OTF_XAdvDevice)
412                   adjustment[i].xadv
413                     += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
414                 if (format & OTF_YAdvance)
415                   adjustment[i].yadv
416                     += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
417                 if (format & OTF_YAdvDevice)
418                   adjustment[i].yadv
419                     += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
420                 adjustment[i].set = 1;
421               }
422               break;
423             case 3:
424               /* Not yet supported.  */
425               break;
426             case 4: case 5:
427               if (! base)
428                 break;
429               prev = base;
430               goto label_adjust_anchor;
431             default:            /* i.e. case 6 */
432               if (! mark)
433                 break;
434               prev = mark;
435
436             label_adjust_anchor:
437               {
438                 int base_x, base_y, mark_x, mark_y;
439
440                 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
441                 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
442                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
443                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
444
445                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
446                   adjust_anchor (otfg->f.f4.base_anchor, face, prev->code,
447                                  x_ppem, y_ppem, &base_x, &base_y);
448                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
449                   adjust_anchor (otfg->f.f4.mark_anchor, face, g->code,
450                                  x_ppem, y_ppem, &mark_x, &mark_y);
451                 adjustment[i].xoff = (base_x - mark_x);
452                 adjustment[i].yoff = - (base_y - mark_y);
453                 adjustment[i].back = (g - prev);
454                 adjustment[i].set = 1;
455               }
456             }
457           if (otfg->GlyphClass == OTF_GlyphClass0)
458             base = mark = g;
459           else if (otfg->GlyphClass == OTF_GlyphClassMark)
460             mark = g;
461           else
462             base = g;
463         }
464     }
465   free (otf_gstring.glyphs);
466   return to;
467
468  simple_copy:
469   font->get_metric (font, in, from, to);
470   for (i = 0; i < len; i++)
471     {
472       MFLTGlyph *g = in->glyphs + (from + i);
473
474       out->glyphs[out->used++] = *g;
475     }
476   if (otf_gstring.glyphs)
477     free (otf_gstring.glyphs);
478   return to;
479 }
480
481 MFLTFont *
482 open_font (char *fontname, char **err)
483 {
484   FT_Face face = new_face (fontname, err);
485   FontInfoOTF *font_info;
486
487   if (! face)
488     return NULL;
489   font_info = malloc (sizeof (FontInfoOTF));
490   font_info->font.get_glyph_id = get_glyph_id;
491   font_info->font.get_metric = get_metric;
492   font_info->font.drive_otf = drive_otf;
493   font_info->face = face;
494   font_info->otf = OTF_open_ft_face (face);
495   return ((MFLTFont *) font_info);
496 }
497
498 void
499 close_font (MFLTFont *font)
500 {
501   FontInfoOTF *font_info = (FontInfoOTF *) font;
502
503   OTF_close (font_info->otf);
504   FT_Done_Face (font_info->face);
505   free (font_info);
506 }
507
508 #else  /* FLT_HB */
509
510 typedef struct {
511   HB_UShort count;
512   HB_UShort *indices;
513 } FeatureInfo;
514
515 typedef struct {
516   FeatureInfo gsub;
517   FeatureInfo gpos;
518 } GsubGposInfo;
519
520 typedef struct {
521   MFLTFont font;
522   FT_Face face;
523   HB_FontRec hb_font;
524   HB_StreamRec gdef_stream;
525   HB_GDEF gdef;
526   HB_GSUB gsub;
527   HB_GPOS gpos;
528   MPlist *otf_spec_cache;
529 } FontInfoHB;
530
531 HB_Bool
532 convertStringToGlyphIndices (HB_Font font, const HB_UChar16 *string,
533                              hb_uint32 length, HB_Glyph *glyphs,
534                              hb_uint32 *numGlyphs, HB_Bool rightToLeft)
535 {
536   return TRUE;
537 }
538
539 void
540 getGlyphAdvances (HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs,
541                   HB_Fixed *advances, int flags /*HB_ShaperFlag*/)
542 {
543   hb_uint32 i;
544
545   for (i = 0; i < numGlyphs; i++)
546     advances[i] =0;
547 }
548
549 HB_Bool
550 canRender (HB_Font font, const HB_UChar16 *string, hb_uint32 length)
551 {
552   return TRUE;
553 }
554
555 HB_Error
556 getPointInOutline (HB_Font font, HB_Glyph glyph, int flags /*HB_ShaperFlag*/,
557                    hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos,
558                    hb_uint32 *nPoints)
559 {
560   FT_Face face = font->faceData;
561   HB_Error error;
562
563   if ((error = (HB_Error) FT_Load_Glyph (face, glyph, flags)))
564     return error;
565   if (face->glyph->format != ft_glyph_format_outline)
566     return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
567   *nPoints = face->glyph->outline.n_points;
568   if (! *nPoints)
569     return HB_Err_Ok;
570   if (point > *nPoints)
571     return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
572
573   *xpos = face->glyph->outline.points[point].x;
574   *ypos = face->glyph->outline.points[point].y;
575
576   return HB_Err_Ok;
577 }
578
579 void
580 getGlyphMetrics (HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
581 {
582 }
583
584 HB_Fixed
585 getFontMetric (HB_Font font, HB_FontMetric metric)
586 {
587   return 0;
588 }
589
590 #define MAKE_TAG(name) ((((FT_ULong) (name)[0]) << 24)          \
591                         | (((FT_ULong) (name)[1]) << 16)        \
592                         | (((FT_ULong) (name)[2]) << 8)         \
593                         | (name)[3])
594
595 HB_Error
596 new_stream (FT_Face face, char *tagname, HB_Stream stream)
597 {
598   FT_ULong tag = MAKE_TAG (tagname);
599   FT_ULong len;
600   FT_Byte *buf;
601
602   if (! FT_IS_SFNT (face))
603     return HB_Err_Invalid_Argument;
604   len = 0;
605   if (FT_Load_Sfnt_Table (face, tag, 0, NULL, &len))
606     return HB_Err_Table_Missing;
607   buf = malloc (len);
608   if (! buf)
609     return HB_Err_Out_Of_Memory;
610   if (FT_Load_Sfnt_Table (face, tag, 0, buf, &len))
611     {
612       free (buf);
613       return HB_Err_Table_Missing;
614     }
615   stream->base = (HB_Byte *) buf;
616   stream->size = len;
617   stream->pos = 0;
618   stream->cursor = NULL;
619
620   return HB_Err_Ok;
621 }
622
623 HB_Error
624 load_gdef (FontInfoHB *font_info)
625 {
626   HB_Error err;
627
628   if (! font_info->gdef_stream.base)
629     {
630       err = new_stream ((FT_Face) font_info->hb_font.faceData, "GDEF",
631                         &font_info->gdef_stream);
632       if (err != HB_Err_Ok)
633         return err;
634     }
635   return HB_Load_GDEF_Table (&font_info->gdef_stream, &font_info->gdef);
636 }
637
638 HB_Error
639 load_gsub (FontInfoHB *font_info)
640 {
641   HB_Error err;
642   HB_StreamRec stream;
643   HB_LookupList *lookup_list;
644   int i;
645
646   if (! font_info->gdef)
647     {
648       if ((err = load_gdef (font_info)) != HB_Err_Ok)
649         return err;
650     }
651   err = new_stream ((FT_Face) font_info->hb_font.faceData, "GSUB", &stream);
652   if (err != HB_Err_Ok)
653     return err;
654   err = HB_Load_GSUB_Table (&stream, &font_info->gsub,
655                             font_info->gdef, &font_info->gdef_stream);
656   free (stream.base);
657   lookup_list = &font_info->gsub->LookupList;
658   for (i = 0; i < lookup_list->LookupCount; i++)
659     lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
660   return err;
661 }
662
663 HB_Error
664 load_gpos (FontInfoHB *font_info)
665 {
666   HB_Error err;
667   HB_StreamRec stream;
668   HB_LookupList *lookup_list;
669   int i;
670
671   if (! font_info->gdef)
672     {
673       if ((err = load_gdef (font_info)) != HB_Err_Ok)
674         return err;
675     }
676   err = new_stream ((FT_Face) font_info->hb_font.faceData, "GPOS", &stream);
677   if (err != HB_Err_Ok)
678     return err;
679   err = HB_Load_GPOS_Table (&stream, &font_info->gpos,
680                             font_info->gdef, &font_info->gdef_stream);
681   free (stream.base);
682   lookup_list = &font_info->gpos->LookupList;
683   for (i = 0; i < lookup_list->LookupCount; i++)
684     lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
685   return err;
686 }
687
688 const HB_FontClass hb_fontClass = {
689     convertStringToGlyphIndices, getGlyphAdvances, canRender,
690     getPointInOutline, getGlyphMetrics, getFontMetric
691 };
692
693 HB_Error
694 setup_features (int gsubp, FontInfoHB *font_info, MFLT_OTF_Spec *spec,
695                 FeatureInfo *info)
696 {
697   int count, preordered;
698   unsigned int *features;
699   FT_UShort script, langsys;
700   FT_UShort req_feature, index;
701   FT_UInt *feature_list;
702   int i, j, k;
703   HB_Error err;
704
705   if (gsubp)
706     {
707       if (! font_info->gsub)
708         {
709           if ((err = load_gsub (font_info)) != HB_Err_Ok)
710             return err;
711         }
712       if ((err = HB_GSUB_Select_Script (font_info->gsub, spec->script, &script))
713           != HB_Err_Ok)
714         return err;
715       if (spec->langsys)
716         {
717           if ((err = HB_GSUB_Select_Language (font_info->gsub, spec->langsys,
718                                               script, &langsys, &req_feature))
719               != HB_Err_Ok)
720             return err;
721         }
722       else
723         langsys = req_feature = 0xFFFF;
724       count = spec->gsub_count;
725       features = spec->gsub;
726     }
727   else
728     {
729       if (! font_info->gpos)
730         {
731           if ((err = load_gpos (font_info)) != HB_Err_Ok)
732             return err;
733         }
734       if ((err = HB_GPOS_Select_Script (font_info->gpos, spec->script, &script))
735           != HB_Err_Ok)
736         return err;
737       if (spec->langsys)
738         {
739           if ((err = HB_GPOS_Select_Language (font_info->gpos, spec->langsys,
740                                               script, &langsys, &req_feature))
741               != HB_Err_Ok)
742             return err;
743         }
744       else
745         langsys = req_feature = 0xFFFF;
746       count = spec->gpos_count;
747       features = spec->gpos;
748     }
749   feature_list = NULL;
750   for (preordered = 0; preordered < count; preordered++)
751     if (features[preordered] == 0)
752       {
753         if ((err = (gsubp
754                     ? HB_GSUB_Query_Features (font_info->gsub, script, langsys,
755                                               &feature_list)
756                     : HB_GPOS_Query_Features (font_info->gpos, script, langsys,
757                                               &feature_list)))
758             != HB_Err_Ok)
759           return err;
760         break;
761       }
762   if (feature_list)
763     for (i = 0; feature_list[i]; i++);
764   else
765     i = preordered;
766   info->indices = malloc (sizeof (FT_UShort) * ((req_feature != 0xFFFF) + i));
767   i = 0;
768   if (req_feature != 0xFFFF)
769     info->indices[i++] = req_feature;
770   for (j = 0; j < preordered; j++)
771     if ((err = (gsubp
772                 ? HB_GSUB_Select_Feature (font_info->gsub, features[j],
773                                           script, langsys, &index)
774                 : HB_GPOS_Select_Feature (font_info->gpos, features[j],
775                                           script, langsys, &index)))
776         == HB_Err_Ok)
777       info->indices[i++] = index;
778   if (feature_list)
779     for (j = 0; feature_list[j]; j++)
780       {
781         for (k = preordered + 1; k < count; k++)
782           if (feature_list[j] == features[k])
783             break;
784         if (k == count
785             && ((gsubp
786                  ? HB_GSUB_Select_Feature (font_info->gsub, feature_list[j],
787                                            script, langsys, &index)
788                  : HB_GPOS_Select_Feature (font_info->gpos, feature_list[j],
789                                            script, langsys, &index))
790                 == FT_Err_Ok))
791           info->indices[i++] = index;
792       }
793   info->count = i;
794   return HB_Err_Ok;
795 }
796
797 GsubGposInfo *
798 setup_otf_spec (MFLTFont *font, MFLT_OTF_Spec *spec)
799 {
800   FontInfoHB *font_info = (FontInfoHB *) font;
801   GsubGposInfo *ginfo;
802
803   if (spec->gsub_count + spec->gpos_count == 0)
804     return NULL;
805   ginfo = mplist_get (font_info->otf_spec_cache, spec->sym);
806   if (ginfo)
807     return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL);
808   ginfo = calloc (1, sizeof (GsubGposInfo));
809   mplist_push (font_info->otf_spec_cache, spec->sym, ginfo);
810   if (setup_features (1, font_info, spec, &(ginfo->gsub)) != HB_Err_Ok)
811     return NULL;
812   if (setup_features (0, font_info, spec, &(ginfo->gpos)) != HB_Err_Ok)
813     return NULL;
814   return ginfo;
815 }
816
817 int
818 drive_otf (MFLTFont *font, MFLT_OTF_Spec *spec,
819            MFLTGlyphString *in, int from, int to,
820            MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
821 {
822   FontInfoHB *font_info = (FontInfoHB *) font;
823   int len = to - from;
824   int i, gidx;
825   HB_Buffer buf;
826   GsubGposInfo *ginfo;
827   HB_UShort *apply_order_save;
828   HB_UShort apply_count_save;
829   int apply_saved = 0;
830   int gpos_applied = 0;
831   HB_Error err;
832
833   if (len == 0)
834     return from;
835
836   buf = NULL;
837   if (hb_buffer_new (&buf) != FT_Err_Ok)
838     goto simple_copy;
839   for (i = from; i < to; i++)
840     {
841       if (hb_buffer_add_glyph (buf, in->glyphs[i].code, 0, i) != FT_Err_Ok)
842         goto simple_copy;
843     }
844   ginfo = setup_otf_spec (font, spec);
845   if (! ginfo)
846     goto simple_copy;
847   if (ginfo->gsub.count > 0)
848     {
849       if (! font_info->gdef
850           && load_gdef (font_info) != HB_Err_Ok)
851         goto simple_copy;
852       apply_order_save = font_info->gsub->FeatureList.ApplyOrder;
853       apply_count_save = font_info->gsub->FeatureList.ApplyCount;
854       apply_saved = 1;
855       font_info->gsub->FeatureList.ApplyOrder = ginfo->gsub.indices;
856       font_info->gsub->FeatureList.ApplyCount = ginfo->gsub.count;
857       err = HB_GSUB_Apply_String (font_info->gsub, buf);
858       if (err != HB_Err_Ok && err != HB_Err_Not_Covered)
859         goto simple_copy;
860       if (out->used + buf->in_length > out->allocated)
861         return -2;
862     }
863
864   if (ginfo->gpos.count > 0
865       && (font_info->gpos || load_gpos (font_info) == HB_Err_Ok))
866     {
867       if (! apply_saved)
868         {
869           apply_order_save = font_info->gsub->FeatureList.ApplyOrder;
870           apply_count_save = font_info->gsub->FeatureList.ApplyCount;
871           apply_saved = 1;
872         }
873       font_info->gpos->FeatureList.ApplyOrder = ginfo->gpos.indices;
874       font_info->gpos->FeatureList.ApplyCount = ginfo->gpos.count;
875       err = HB_GPOS_Apply_String (&font_info->hb_font, font_info->gpos,
876                                   FT_LOAD_DEFAULT, buf, FALSE, FALSE);
877       if (err == HB_Err_Ok)
878         gpos_applied = 1;
879     }
880
881   if (apply_saved)
882     {
883       font_info->gsub->FeatureList.ApplyOrder = apply_order_save;
884       font_info->gsub->FeatureList.ApplyCount = apply_count_save;
885     }
886
887   gidx = out->used;
888
889   for (i = 0; i < buf->in_length; i++)
890     {
891       HB_GlyphItem hg = buf->in_string + i;
892       HB_Position pos = buf->positions + i;
893       MFLTGlyph *g;
894
895       out->glyphs[out->used] = in->glyphs[hg->cluster];
896       g = out->glyphs + out->used++;
897       if (g->code != hg->gindex)
898         g->c = 0, g->code = hg->gindex;
899       adjustment[i].set = gpos_applied;
900       if (gpos_applied)
901         {
902           adjustment[i].xadv = pos->x_advance;
903           adjustment[i].yadv = pos->y_advance;
904           adjustment[i].xoff = pos->x_pos;
905           adjustment[i].yoff = - pos->y_pos;
906           adjustment[i].back = pos->back;
907           adjustment[i].advance_is_absolute = pos->new_advance;
908         }
909     }
910   return to;
911
912  simple_copy:
913   if (buf)
914     hb_buffer_free (buf);
915   for (i = 0; i < len; i++)
916     out->glyphs[out->used++] = in->glyphs[from + i];
917   return to;
918 }
919
920 MFLTFont *
921 open_font (char *fontname, char **err)
922 {
923   FT_Face face = new_face (fontname, err);
924   FontInfoHB *font_info;
925
926   if (! face)
927     return NULL;
928   font_info = calloc (1, sizeof (FontInfoHB));
929   font_info->font.get_glyph_id = get_glyph_id;
930   font_info->font.get_metric = get_metric;
931   font_info->font.drive_otf = drive_otf;
932   font_info->face = face;
933   font_info->hb_font.klass = &hb_fontClass;
934   font_info->hb_font.faceData = face;
935   font_info->hb_font.userData = NULL;
936   font_info->hb_font.x_ppem = face->size->metrics.x_ppem;
937   font_info->hb_font.x_scale = face->size->metrics.x_scale;
938   font_info->hb_font.y_scale = face->size->metrics.y_scale;
939   font_info->hb_font.y_ppem = face->size->metrics.y_ppem;
940   font_info->otf_spec_cache = mplist ();
941   return ((MFLTFont *) font_info);
942 }
943
944 void
945 close_font (MFLTFont *font)
946 {
947   FontInfoHB *font_info = (FontInfoHB *) font;
948   MPlist *p;
949
950   if (font_info->gdef)
951     {
952       HB_Done_GDEF_Table (font_info->gdef);
953       free (font_info->gdef_stream.base);
954     }
955   if (font_info->gsub)
956     HB_Done_GSUB_Table (font_info->gsub);
957   if (font_info->gpos)
958     HB_Done_GPOS_Table (font_info->gpos);
959   FT_Done_Face ((FT_Face) (font_info->hb_font.faceData));
960   for (p = font_info->otf_spec_cache; mplist_key (p) != Mnil;
961        p = mplist_next (p))
962     {
963       GsubGposInfo *ginfo = mplist_value (p);
964
965       if (ginfo->gsub.count > 0)
966         free (ginfo->gsub.indices);
967       if (ginfo->gpos.count > 0)
968         free (ginfo->gpos.indices);
969     }
970   m17n_object_unref (font_info->otf_spec_cache);
971   free (font_info);
972 }
973
974 #endif
975 #endif
976
977 int
978 main (int argc, char **argv)
979 {
980   char *font_name, *flt_name;
981   char *err;
982   MText *mt;
983   MFLTFont *font;
984   int len, i, j;
985
986   if (argc < 3)
987     {
988       fprintf (stderr, "Usage: flt FONT-NAME FLT-NAME < TEXT-FILE\n");
989       exit (1);
990     }
991
992   font_name = argv[1];
993   flt_name = argv[2];
994
995   FT_Init_FreeType (&ft_library);
996   M17N_INIT ();
997   font = open_font (font_name, &err);
998   if (! font)
999     {
1000       fprintf (stderr, "Font error: %s: %s\n", argv[1], err);
1001       exit (1);
1002     }
1003
1004   mt = mconv_decode_stream (msymbol ("utf-8"), stdin);
1005   len = mtext_len (mt);
1006   for (i = 0, j = mtext_character (mt, i, len, '\n'); i < len;
1007        i = j + 1, j = mtext_character (mt, i, len, '\n'))
1008     {
1009       if (j < 0)
1010         j = len;
1011       if (flt (mt, i, j, font, flt_name) < 0)
1012         {
1013           fprintf (stderr, "Error in FLT processing.\n");
1014           exit (1);
1015         }
1016     }
1017   m17n_object_unref (mt);
1018   close_font (font);
1019   M17N_FINI ();
1020   return 0;
1021 }