6df60a864fde4b3fb8d6b753574b72e52b153095
[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_check_features (otf, 1,
372                               spec->script, spec->langsys,
373                               spec->gpos, spec->gpos_count) != 1
374           || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
375                               gpos_features) < 0))
376         return to;
377
378       face = ((FontInfo *) font)->face;
379       x_ppem = face->size->metrics.x_ppem;
380       y_ppem = face->size->metrics.y_ppem;
381       x_scale = face->size->metrics.x_scale;
382       y_scale = face->size->metrics.y_scale;
383
384       for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
385            i < otf_gstring.used; i++, otfg++, g++)
386         {
387           MFLTGlyph *prev;
388
389           if (! otfg->glyph_id)
390             continue;
391           switch (otfg->positioning_type)
392             {
393             case 0:
394               break;
395             case 1: case 2:
396               {
397                 int format = otfg->f.f1.format;
398
399                 if (format & OTF_XPlacement)
400                   adjustment[i].xoff
401                     = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
402                 if (format & OTF_XPlaDevice)
403                   adjustment[i].xoff
404                     += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
405                 if (format & OTF_YPlacement)
406                   adjustment[i].yoff
407                     = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
408                 if (format & OTF_YPlaDevice)
409                   adjustment[i].yoff
410                     -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
411                 if (format & OTF_XAdvance)
412                   adjustment[i].xadv
413                     += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
414                 if (format & OTF_XAdvDevice)
415                   adjustment[i].xadv
416                     += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
417                 if (format & OTF_YAdvance)
418                   adjustment[i].yadv
419                     += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
420                 if (format & OTF_YAdvDevice)
421                   adjustment[i].xadv
422                     += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
423                 adjustment[i].set = 1;
424               }
425               break;
426             case 3:
427               /* Not yet supported.  */
428               break;
429             case 4: case 5:
430               if (! base)
431                 break;
432               prev = base;
433               goto label_adjust_anchor;
434             default:            /* i.e. case 6 */
435               if (! mark)
436                 break;
437               prev = mark;
438
439             label_adjust_anchor:
440               {
441                 int base_x, base_y, mark_x, mark_y;
442
443                 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
444                 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
445                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
446                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
447
448                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
449                   adjust_anchor (otfg->f.f4.base_anchor, face, prev->code,
450                                  x_ppem, y_ppem, &base_x, &base_y);
451                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
452                   adjust_anchor (otfg->f.f4.mark_anchor, face, g->code,
453                                  x_ppem, y_ppem, &mark_x, &mark_y);
454                 adjustment[i].xoff = (base_x - mark_x);
455                 adjustment[i].yoff = - (base_y - mark_y);
456                 adjustment[i].back = (g - prev);
457                 adjustment[i].set = 1;
458               }
459             }
460           if (otfg->GlyphClass == OTF_GlyphClass0)
461             base = mark = g;
462           else if (otfg->GlyphClass == OTF_GlyphClassMark)
463             mark = g;
464           else
465             base = g;
466         }
467     }
468   free (otf_gstring.glyphs);
469   return to;
470
471  simple_copy:
472   font->get_metric (font, in, from, to);
473   for (i = 0; i < len; i++)
474     {
475       MFLTGlyph *g = in->glyphs + (from + i);
476
477       out->glyphs[out->used++] = *g;
478     }
479   if (otf_gstring.glyphs)
480     free (otf_gstring.glyphs);
481   return to;
482 }
483
484 MFLTFont *
485 open_font (char *fontname, char **err)
486 {
487   FT_Face face = new_face (fontname, err);
488   FontInfoOTF *font_info;
489
490   if (! face)
491     return NULL;
492   font_info = malloc (sizeof (FontInfoOTF));
493   font_info->font.get_glyph_id = get_glyph_id;
494   font_info->font.get_metric = get_metric;
495   font_info->font.drive_otf = drive_otf;
496   font_info->face = face;
497   font_info->otf = OTF_open_ft_face (face);
498   return ((MFLTFont *) font_info);
499 }
500
501 void
502 close_font (MFLTFont *font)
503 {
504   FontInfoOTF *font_info = (FontInfoOTF *) font;
505
506   OTF_close (font_info->otf);
507   FT_Done_Face (font_info->face);
508   free (font_info);
509 }
510
511 #else  /* FLT_HB */
512
513 typedef struct {
514   HB_UShort count;
515   HB_UShort *indices;
516 } FeatureInfo;
517
518 typedef struct {
519   FeatureInfo gsub;
520   FeatureInfo gpos;
521 } GsubGposInfo;
522
523 typedef struct {
524   MFLTFont font;
525   FT_Face face;
526   HB_FontRec hb_font;
527   HB_StreamRec gdef_stream;
528   HB_GDEF gdef;
529   HB_GSUB gsub;
530   HB_GPOS gpos;
531   MPlist *otf_spec_cache;
532 } FontInfoHB;
533
534 HB_Bool
535 convertStringToGlyphIndices (HB_Font font, const HB_UChar16 *string,
536                              hb_uint32 length, HB_Glyph *glyphs,
537                              hb_uint32 *numGlyphs, HB_Bool rightToLeft)
538 {
539   return TRUE;
540 }
541
542 void
543 getGlyphAdvances (HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs,
544                   HB_Fixed *advances, int flags /*HB_ShaperFlag*/)
545 {
546   hb_uint32 i;
547
548   for (i = 0; i < numGlyphs; i++)
549     advances[i] =0;
550 }
551
552 HB_Bool
553 canRender (HB_Font font, const HB_UChar16 *string, hb_uint32 length)
554 {
555   return TRUE;
556 }
557
558 HB_Error
559 getPointInOutline (HB_Font font, HB_Glyph glyph, int flags /*HB_ShaperFlag*/,
560                    hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos,
561                    hb_uint32 *nPoints)
562 {
563   FT_Face face = font->faceData;
564   HB_Error error;
565
566   if ((error = (HB_Error) FT_Load_Glyph (face, glyph, flags)))
567     return error;
568   if (face->glyph->format != ft_glyph_format_outline)
569     return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
570   *nPoints = face->glyph->outline.n_points;
571   if (! *nPoints)
572     return HB_Err_Ok;
573   if (point > *nPoints)
574     return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
575
576   *xpos = face->glyph->outline.points[point].x;
577   *ypos = face->glyph->outline.points[point].y;
578
579   return HB_Err_Ok;
580 }
581
582 void
583 getGlyphMetrics (HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
584 {
585 }
586
587 HB_Fixed
588 getFontMetric (HB_Font font, HB_FontMetric metric)
589 {
590   return 0;
591 }
592
593 #define MAKE_TAG(name) ((((FT_ULong) (name)[0]) << 24)          \
594                         | (((FT_ULong) (name)[1]) << 16)        \
595                         | (((FT_ULong) (name)[2]) << 8)         \
596                         | (name)[3])
597
598 HB_Error
599 new_stream (FT_Face face, char *tagname, HB_Stream stream)
600 {
601   FT_ULong tag = MAKE_TAG (tagname);
602   FT_ULong len;
603   FT_Byte *buf;
604
605   if (! FT_IS_SFNT (face))
606     return HB_Err_Invalid_Argument;
607   len = 0;
608   if (FT_Load_Sfnt_Table (face, tag, 0, NULL, &len))
609     return HB_Err_Table_Missing;
610   buf = malloc (len);
611   if (! buf)
612     return HB_Err_Out_Of_Memory;
613   if (FT_Load_Sfnt_Table (face, tag, 0, buf, &len))
614     {
615       free (buf);
616       return HB_Err_Table_Missing;
617     }
618   stream->base = (HB_Byte *) buf;
619   stream->size = len;
620   stream->pos = 0;
621   stream->cursor = NULL;
622
623   return HB_Err_Ok;
624 }
625
626 HB_Error
627 load_gdef (FontInfoHB *font_info)
628 {
629   HB_Error err;
630
631   if (! font_info->gdef_stream.base)
632     {
633       err = new_stream ((FT_Face) font_info->hb_font.faceData, "GDEF",
634                         &font_info->gdef_stream);
635       if (err != HB_Err_Ok)
636         return err;
637     }
638   return HB_Load_GDEF_Table (&font_info->gdef_stream, &font_info->gdef);
639 }
640
641 HB_Error
642 load_gsub (FontInfoHB *font_info)
643 {
644   HB_Error err;
645   HB_StreamRec stream;
646   HB_LookupList *lookup_list;
647   int i;
648
649   if (! font_info->gdef)
650     {
651       if ((err = load_gdef (font_info)) != HB_Err_Ok)
652         return err;
653     }
654   err = new_stream ((FT_Face) font_info->hb_font.faceData, "GSUB", &stream);
655   if (err != HB_Err_Ok)
656     return err;
657   err = HB_Load_GSUB_Table (&stream, &font_info->gsub,
658                             font_info->gdef, &font_info->gdef_stream);
659   free (stream.base);
660   lookup_list = &font_info->gsub->LookupList;
661   for (i = 0; i < lookup_list->LookupCount; i++)
662     lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
663   return err;
664 }
665
666 HB_Error
667 load_gpos (FontInfoHB *font_info)
668 {
669   HB_Error err;
670   HB_StreamRec stream;
671   HB_LookupList *lookup_list;
672   int i;
673
674   if (! font_info->gdef)
675     {
676       if ((err = load_gdef (font_info)) != HB_Err_Ok)
677         return err;
678     }
679   err = new_stream ((FT_Face) font_info->hb_font.faceData, "GPOS", &stream);
680   if (err != HB_Err_Ok)
681     return err;
682   err = HB_Load_GPOS_Table (&stream, &font_info->gpos,
683                             font_info->gdef, &font_info->gdef_stream);
684   free (stream.base);
685   lookup_list = &font_info->gpos->LookupList;
686   for (i = 0; i < lookup_list->LookupCount; i++)
687     lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
688   return err;
689 }
690
691 const HB_FontClass hb_fontClass = {
692     convertStringToGlyphIndices, getGlyphAdvances, canRender,
693     getPointInOutline, getGlyphMetrics, getFontMetric
694 };
695
696 HB_Error
697 setup_features (int gsubp, FontInfoHB *font_info, MFLT_OTF_Spec *spec,
698                 FeatureInfo *info)
699 {
700   int count, preordered;
701   unsigned int *features;
702   FT_UShort script, langsys;
703   FT_UShort req_feature, index;
704   FT_UInt *feature_list;
705   int i, j, k;
706   HB_Error err;
707
708   if (gsubp)
709     {
710       if (! font_info->gsub)
711         {
712           if ((err = load_gsub (font_info)) != HB_Err_Ok)
713             return err;
714         }
715       if ((err = HB_GSUB_Select_Script (font_info->gsub, spec->script, &script))
716           != HB_Err_Ok)
717         return err;
718       if (spec->langsys)
719         {
720           if ((err = HB_GSUB_Select_Language (font_info->gsub, spec->langsys,
721                                               script, &langsys, &req_feature))
722               != HB_Err_Ok)
723             return err;
724         }
725       else
726         langsys = req_feature = 0xFFFF;
727       count = spec->gsub_count;
728       features = spec->gsub;
729     }
730   else
731     {
732       if (! font_info->gpos)
733         {
734           if ((err = load_gpos (font_info)) != HB_Err_Ok)
735             return err;
736         }
737       if ((err = HB_GPOS_Select_Script (font_info->gpos, spec->script, &script))
738           != HB_Err_Ok)
739         return err;
740       if (spec->langsys)
741         {
742           if ((err = HB_GPOS_Select_Language (font_info->gpos, spec->langsys,
743                                               script, &langsys, &req_feature))
744               != HB_Err_Ok)
745             return err;
746         }
747       else
748         langsys = req_feature = 0xFFFF;
749       count = spec->gpos_count;
750       features = spec->gpos;
751     }
752   feature_list = NULL;
753   for (preordered = 0; preordered < count; preordered++)
754     if (features[preordered] == 0)
755       {
756         if ((err = (gsubp
757                     ? HB_GSUB_Query_Features (font_info->gsub, script, langsys,
758                                               &feature_list)
759                     : HB_GPOS_Query_Features (font_info->gpos, script, langsys,
760                                               &feature_list)))
761             != HB_Err_Ok)
762           return err;
763         break;
764       }
765   if (feature_list)
766     for (i = 0; feature_list[i]; i++);
767   else
768     i = preordered;
769   info->indices = malloc (sizeof (FT_UShort) * ((req_feature != 0xFFFF) + i));
770   i = 0;
771   if (req_feature != 0xFFFF)
772     info->indices[i++] = req_feature;
773   for (j = 0; j < preordered; j++)
774     if ((err = (gsubp
775                 ? HB_GSUB_Select_Feature (font_info->gsub, features[j],
776                                           script, langsys, &index)
777                 : HB_GPOS_Select_Feature (font_info->gpos, features[j],
778                                           script, langsys, &index)))
779         == HB_Err_Ok)
780       info->indices[i++] = index;
781   if (feature_list)
782     for (j = 0; feature_list[j]; j++)
783       {
784         for (k = preordered + 1; k < count; k++)
785           if (feature_list[j] == features[k])
786             break;
787         if (k == count
788             && ((gsubp
789                  ? HB_GSUB_Select_Feature (font_info->gsub, feature_list[j],
790                                            script, langsys, &index)
791                  : HB_GPOS_Select_Feature (font_info->gpos, feature_list[j],
792                                            script, langsys, &index))
793                 == FT_Err_Ok))
794           info->indices[i++] = index;
795       }
796   info->count = i;
797   return HB_Err_Ok;
798 }
799
800 GsubGposInfo *
801 setup_otf_spec (MFLTFont *font, MFLT_OTF_Spec *spec)
802 {
803   FontInfoHB *font_info = (FontInfoHB *) font;
804   GsubGposInfo *ginfo;
805
806   if (spec->gsub_count + spec->gpos_count == 0)
807     return NULL;
808   ginfo = mplist_get (font_info->otf_spec_cache, spec->sym);
809   if (ginfo)
810     return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL);
811   ginfo = calloc (1, sizeof (GsubGposInfo));
812   mplist_push (font_info->otf_spec_cache, spec->sym, ginfo);
813   if (setup_features (1, font_info, spec, &(ginfo->gsub)) != HB_Err_Ok)
814     return NULL;
815   if (setup_features (0, font_info, spec, &(ginfo->gpos)) != HB_Err_Ok)
816     return NULL;
817   return ginfo;
818 }
819
820 int
821 drive_otf (MFLTFont *font, MFLT_OTF_Spec *spec,
822            MFLTGlyphString *in, int from, int to,
823            MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
824 {
825   FontInfoHB *font_info = (FontInfoHB *) font;
826   int len = to - from;
827   int i, gidx;
828   HB_Buffer buf;
829   GsubGposInfo *ginfo;
830   HB_UShort *apply_order_save;
831   HB_UShort apply_count_save;
832   int apply_saved = 0;
833   int gpos_applied = 0;
834   HB_Error err;
835
836   if (len == 0)
837     return from;
838
839   buf = NULL;
840   if (hb_buffer_new (&buf) != FT_Err_Ok)
841     goto simple_copy;
842   for (i = from; i < to; i++)
843     {
844       if (hb_buffer_add_glyph (buf, in->glyphs[i].code, 0, i) != FT_Err_Ok)
845         goto simple_copy;
846     }
847   ginfo = setup_otf_spec (font, spec);
848   if (! ginfo)
849     goto simple_copy;
850   if (ginfo->gsub.count > 0)
851     {
852       if (! font_info->gdef
853           && load_gdef (font_info) != HB_Err_Ok)
854         goto simple_copy;
855       apply_order_save = font_info->gsub->FeatureList.ApplyOrder;
856       apply_count_save = font_info->gsub->FeatureList.ApplyCount;
857       apply_saved = 1;
858       font_info->gsub->FeatureList.ApplyOrder = ginfo->gsub.indices;
859       font_info->gsub->FeatureList.ApplyCount = ginfo->gsub.count;
860       err = HB_GSUB_Apply_String (font_info->gsub, buf);
861       if (err != HB_Err_Ok && err != HB_Err_Not_Covered)
862         goto simple_copy;
863       if (out->used + buf->in_length > out->allocated)
864         return -2;
865     }
866
867   if (ginfo->gpos.count > 0
868       && (font_info->gpos || load_gpos (font_info) == HB_Err_Ok))
869     {
870       if (! apply_saved)
871         {
872           apply_order_save = font_info->gsub->FeatureList.ApplyOrder;
873           apply_count_save = font_info->gsub->FeatureList.ApplyCount;
874           apply_saved = 1;
875         }
876       font_info->gpos->FeatureList.ApplyOrder = ginfo->gpos.indices;
877       font_info->gpos->FeatureList.ApplyCount = ginfo->gpos.count;
878       err = HB_GPOS_Apply_String (&font_info->hb_font, font_info->gpos,
879                                   FT_LOAD_DEFAULT, buf, FALSE, FALSE);
880       if (err == HB_Err_Ok)
881         gpos_applied = 1;
882     }
883
884   if (apply_saved)
885     {
886       font_info->gsub->FeatureList.ApplyOrder = apply_order_save;
887       font_info->gsub->FeatureList.ApplyCount = apply_count_save;
888     }
889
890   gidx = out->used;
891
892   for (i = 0; i < buf->in_length; i++)
893     {
894       HB_GlyphItem hg = buf->in_string + i;
895       HB_Position pos = buf->positions + i;
896       MFLTGlyph *g;
897
898       out->glyphs[out->used] = in->glyphs[hg->cluster];
899       g = out->glyphs + out->used++;
900       if (g->code != hg->gindex)
901         g->c = 0, g->code = hg->gindex;
902       adjustment[i].set = gpos_applied;
903       if (gpos_applied)
904         {
905           adjustment[i].xadv = pos->x_advance;
906           adjustment[i].yadv = pos->y_advance;
907           adjustment[i].xoff = pos->x_pos;
908           adjustment[i].yoff = - pos->y_pos;
909           adjustment[i].back = pos->back;
910           adjustment[i].advance_is_absolute = pos->new_advance;
911         }
912     }
913   return to;
914
915  simple_copy:
916   if (buf)
917     hb_buffer_free (buf);
918   for (i = 0; i < len; i++)
919     out->glyphs[out->used++] = in->glyphs[from + i];
920   return to;
921 }
922
923 MFLTFont *
924 open_font (char *fontname, char **err)
925 {
926   FT_Face face = new_face (fontname, err);
927   FontInfoHB *font_info;
928
929   if (! face)
930     return NULL;
931   font_info = calloc (1, sizeof (FontInfoHB));
932   font_info->font.get_glyph_id = get_glyph_id;
933   font_info->font.get_metric = get_metric;
934   font_info->font.drive_otf = drive_otf;
935   font_info->face = face;
936   font_info->hb_font.klass = &hb_fontClass;
937   font_info->hb_font.faceData = face;
938   font_info->hb_font.userData = NULL;
939   font_info->hb_font.x_ppem = face->size->metrics.x_ppem;
940   font_info->hb_font.x_scale = face->size->metrics.x_scale;
941   font_info->hb_font.y_scale = face->size->metrics.y_scale;
942   font_info->hb_font.y_ppem = face->size->metrics.y_ppem;
943   font_info->otf_spec_cache = mplist ();
944   return ((MFLTFont *) font_info);
945 }
946
947 void
948 close_font (MFLTFont *font)
949 {
950   FontInfoHB *font_info = (FontInfoHB *) font;
951   MPlist *p;
952
953   if (font_info->gdef)
954     {
955       HB_Done_GDEF_Table (font_info->gdef);
956       free (font_info->gdef_stream.base);
957     }
958   if (font_info->gsub)
959     HB_Done_GSUB_Table (font_info->gsub);
960   if (font_info->gpos)
961     HB_Done_GPOS_Table (font_info->gpos);
962   FT_Done_Face ((FT_Face) (font_info->hb_font.faceData));
963   for (p = font_info->otf_spec_cache; mplist_key (p) != Mnil;
964        p = mplist_next (p))
965     {
966       GsubGposInfo *ginfo = mplist_value (p);
967
968       if (ginfo->gsub.count > 0)
969         free (ginfo->gsub.indices);
970       if (ginfo->gpos.count > 0)
971         free (ginfo->gpos.indices);
972     }
973   m17n_object_unref (font_info->otf_spec_cache);
974   free (font_info);
975 }
976
977 #endif
978 #endif
979
980 int
981 main (int argc, char **argv)
982 {
983   char *font_name, *flt_name;
984   char *err;
985   MText *mt;
986   MFLTFont *font;
987   int len, i, j;
988
989   if (argc < 3)
990     {
991       fprintf (stderr, "Usage: flt FONT-NAME FLT-NAME < TEXT-FILE\n");
992       exit (1);
993     }
994
995   font_name = argv[1];
996   flt_name = argv[2];
997
998   FT_Init_FreeType (&ft_library);
999   M17N_INIT ();
1000   font = open_font (font_name, &err);
1001   if (! font)
1002     {
1003       fprintf (stderr, "Font error: %s: %s\n", argv[1], err);
1004       exit (1);
1005     }
1006
1007   mt = mconv_decode_stream (msymbol ("utf-8"), stdin);
1008   len = mtext_len (mt);
1009   for (i = 0, j = mtext_character (mt, i, len, '\n'); i < len;
1010        i = j + 1, j = mtext_character (mt, i, len, '\n'))
1011     {
1012       if (j < 0)
1013         j = len;
1014       if (flt (mt, i, j, font, flt_name) < 0)
1015         {
1016           fprintf (stderr, "Error in FLT processing.\n");
1017           exit (1);
1018         }
1019     }
1020   m17n_object_unref (mt);
1021   close_font (font);
1022   M17N_FINI ();
1023   return 0;
1024 }