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