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