23d894a9a9727c2b5497172b5e14a7bb332d7c0e
[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 #define PANGO_ENABLE_ENGINE
30 #define PANGO_ENABLE_BACKEND
31 #include <pango/pango.h>
32 #include <pango/pango-ot.h>
33 #include <pango/pangoft2.h>
34 #include <pango/pangofc-font.h>
35
36 #endif
37
38 #include <m17n-misc.h>
39
40 static FT_Library ft_library;
41
42 int
43 parse_font_name (char *fontname, char **family, int *size, char **err)
44 {
45   FcPattern *pat;
46   FcChar8 *fam;
47   double pixelsize;
48
49   pat = FcNameParse ((FcChar8 *) fontname);
50   if (! pat)
51     {
52       *err = "invalid name format";
53       return -1;
54     }
55   if (FcPatternGetString (pat, FC_FAMILY, 0, &fam) != FcResultMatch)
56     {
57       FcPatternDestroy (pat);
58       *err = "no family name";
59       return -1;
60     }
61   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &pixelsize) != FcResultMatch)
62     pixelsize = 20;
63   *family = strdup ((char *) fam);
64   *size = pixelsize;
65   FcPatternDestroy (pat);
66   return 0;
67 }
68
69 FT_Face
70 new_face (char *fontname, char **err)
71 {
72   FcPattern *pat;
73   FcChar8 *fam, *file;
74   int size;
75   double pixelsize;
76   FcFontSet *fs;
77   FcObjectSet *os;
78   FT_Face face;
79
80   if (parse_font_name (fontname, (char **) &fam, &size, err) < 0)
81     return NULL;
82   pixelsize = size;
83   pat = FcPatternBuild (0,
84                         FC_FAMILY, FcTypeString, fam,
85                         FC_SCALABLE, FcTypeBool, FcTrue,
86                         NULL);
87   free (fam);
88   os = FcObjectSetBuild (FC_FILE, NULL);
89   fs = FcFontList (NULL, pat, os);
90   if (fs->nfont == 0)
91     {
92       *err = "no matching font";
93       return NULL;
94     }
95   FcPatternGetString (fs->fonts[0], FC_FILE, 0, &file);
96
97   if (FT_New_Face (ft_library, (char *) file, 0, &face))
98     {
99       FcFontSetDestroy (fs);
100       FcObjectSetDestroy (os);
101       FcPatternDestroy (pat);
102       *err = "font open fail";
103       return NULL;
104     }
105   FcFontSetDestroy (fs);
106   FcObjectSetDestroy (os);
107   FcPatternDestroy (pat);
108   if (FT_Set_Pixel_Sizes (face, pixelsize, pixelsize))
109     {
110       *err = "set pixelsize fail";
111       FT_Done_Face (face);
112       return NULL;
113     }
114   return face;
115 }
116
117 #ifdef FLT_GUI
118
119 typedef struct _MFLTFont MFLTFont;
120
121 struct _MFLTFont
122 {
123   int x_ppem, y_ppem;
124   void (*get_glyph_id) (void);
125   void (*get_metrics) (void);
126   void (*suitable_p) (void);
127   void (*drive_otf) (void);
128   MFont *font;
129   FT_Face face;
130 };
131
132 void get_glyph_id (void) {}
133 void get_metrics (void) {}
134 void suitable_p (void) {}
135 void drive_otf (void) {}
136
137 MFrame *frame;
138
139 MFLTFont *
140 open_font (char *fontname, char **err)
141 {
142   FT_Face ft_face = new_face (fontname, err);
143   MFLTFont *font;
144   MFace *face;
145   MPlist *plist;
146   MFontset *fontset;
147
148   if (! ft_face)
149     return NULL;
150   face = mface ();
151   plist = mplist ();
152   fontset = mfontset ("generic");
153   mface_put_prop (face, Mfontset, fontset);
154   mplist_add (plist, Mface, face);
155   mplist_add (plist, Mdevice, Mnil);
156   frame = mframe (plist);
157   m17n_object_unref (plist);
158   m17n_object_unref (face);
159   m17n_object_unref (fontset);
160
161   font = calloc (1, sizeof (MFLTFont));
162   font->font = mfont_encapsulate (frame, Mfreetype, ft_face);
163   font->face = ft_face;
164   return font;
165 }
166
167 void
168 close_font (MFLTFont *font)
169 {
170   FT_Done_Face (font->face);
171   free (font);
172   m17n_object_unref (frame);
173 }
174
175 #elif defined (FLT_OTF) || defined (FLT_HB)
176
177 typedef struct {
178   MFLTFont font;
179   FT_Face face;
180 } FontInfo;
181
182 int
183 get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
184 {
185   FT_Face face = ((FontInfo *) font)->face;
186
187   for (; from < to; from++)
188     {
189       MFLTGlyph *g = gstring->glyphs + from;
190
191       if (! g->encoded
192           && ! (g->code = FT_Get_Char_Index (face, g->code)))
193         return -1;
194       g->encoded = 1;
195     }
196   return 0;
197 }
198
199 int 
200 get_metrics (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
201 {
202   FT_Face face = ((FontInfo *) font)->face;
203
204   for (; from < to; from++)
205     {
206       MFLTGlyph *g = gstring->glyphs + from;
207
208       if (! g->measured)
209         {
210           FT_Glyph_Metrics *metrics;
211
212           if (FT_Load_Glyph (face, g->code, FT_LOAD_DEFAULT))
213             return -1;
214           metrics = &face->glyph->metrics;
215           g->lbearing = metrics->horiBearingX;
216           g->rbearing = metrics->horiBearingX + metrics->width;
217           g->xadv = metrics->horiAdvance;
218           g->yadv = metrics->vertAdvance;
219           g->ascent = metrics->horiBearingY;
220           g->descent = metrics->height - metrics->horiBearingY;
221           g->measured = 1;
222         }
223     }
224   return 0;
225 }
226
227 #ifdef FLT_OTF
228
229 typedef struct {
230   MFLTFont font;
231   FT_Face face;
232   OTF *otf;
233 } FontInfoOTF;
234
235 #define DEVICE_DELTA(table, size)                               \
236   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
237    ? ((table).DeltaValue[(size) - (table).StartSize] << 6)      \
238    : 0)
239
240 static void
241 adjust_anchor (OTF_Anchor *anchor, FT_Face face,
242                unsigned code, unsigned x_ppem, unsigned y_ppem, int *x, int *y)
243 {
244   if (anchor->AnchorFormat == 2)
245     {
246       FT_Outline *outline;
247       int ap = anchor->f.f1.AnchorPoint;
248
249       FT_Load_Glyph (face, (FT_UInt) code, FT_LOAD_MONOCHROME);
250       outline = &face->glyph->outline;
251       if (ap < outline->n_points)
252         {
253           *x = outline->points[ap].x;
254           *y = outline->points[ap].y;
255         }
256     }
257   else if (anchor->AnchorFormat == 3)
258     {
259       if (anchor->f.f2.XDeviceTable.offset)
260         *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
261       if (anchor->f.f2.YDeviceTable.offset)
262         *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
263     }
264 }
265
266 char *
267 tag_name (char *str, unsigned tag)
268 {
269   *str++ = tag >> 24;
270   *str++ = (tag >> 16) & 0xFF;
271   *str++ = (tag >> 8) & 0xFF;
272   *str++ = tag & 0xFF;
273   return str;
274 }
275
276 void
277 encode_features (char *str, int count, unsigned *features)
278 {
279   int all = 0;
280   int i;
281
282   for (i = 0; i < count; i++)
283     {
284       unsigned tag = features[i];
285
286       if (tag == 0)
287         all = 1;
288       else
289         {
290           if (i > 0)
291             *str++ = ',';
292           if (all)
293             *str++ = '~';
294           str = tag_name (str, tag);
295         }
296     }
297   if (all)
298     {
299       if (i > 1)
300         *str++ = ',';
301       *str++ = '*';
302     }
303   *str = '\0';
304 }
305
306 int
307 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
308            MFLTGlyphString *in, int from, int to,
309            MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
310 {
311   int len = to - from;
312   int i, gidx;
313   OTF *otf = ((FontInfoOTF *) font)->otf;
314   OTF_GlyphString otf_gstring;
315   OTF_Glyph *otfg;
316   char script[4], langsys[4];
317   char *gsub_features = NULL, *gpos_features = NULL;
318
319   if (len == 0)
320     return from;
321
322   if (! otf)
323     goto simple_copy;
324   otf_gstring.glyphs = NULL;
325   if (OTF_get_table (otf, "head") < 0)
326     {
327       OTF_close (otf);
328       ((FontInfoOTF *) font)->otf = NULL;
329       goto simple_copy;
330     }
331
332   tag_name (script, spec->script);
333   tag_name (langsys, spec->langsys);
334
335   if (spec->gsub_count > 0)
336     {
337       gsub_features = alloca (6 * spec->gsub_count);
338       if (gsub_features)
339         {
340           if (OTF_check_table (otf, "GSUB") < 0)
341             gsub_features = NULL;
342           else
343             encode_features (gsub_features, spec->gsub_count, spec->gsub);
344         }
345     }
346   if (spec->gpos_count)
347     {
348       gpos_features = alloca (6 * spec->gpos_count);
349       if (gpos_features)
350         {
351           if (OTF_check_table (otf, "GPOS") < 0)
352             gpos_features = NULL;
353           else
354             encode_features (gpos_features, spec->gpos_count, spec->gpos);
355         }
356     }
357
358   otf_gstring.size = otf_gstring.used = len;
359   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
360   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
361   for (i = 0; i < len; i++)
362     {
363       otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
364       otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
365     }
366
367   OTF_drive_gdef (otf, &otf_gstring);
368   gidx = out->used;
369
370   if (gsub_features)
371     {
372       if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
373           < 0)
374         goto simple_copy;
375       if (out->allocated < out->used + otf_gstring.used)
376         return -2;
377       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
378         {
379           MFLTGlyph *g = out->glyphs + out->used;
380           int j;
381
382           *g = in->glyphs[from + otfg->f.index.from];
383           g->c = 0;
384           for (j = from + otfg->f.index.from; j <= from + otfg->f.index.to; j++)
385             if (in->glyphs[j].code == otfg->glyph_id)
386               {
387                 g->c = in->glyphs[j].c;
388                 break;
389               }
390           if (g->code != otfg->glyph_id)
391             {
392               g->code = otfg->glyph_id;
393               g->measured = 0;
394             }
395           out->used++;
396         }
397     }
398   else
399     {
400       if (out->allocated < out->used + len)
401         return -2;
402       for (i = 0; i < len; i++)
403         out->glyphs[out->used++] = in->glyphs[from + i];
404     }
405
406   if (gpos_features)
407     {
408       FT_Face face;
409       MFLTGlyph *base = NULL, *mark = NULL, *g;
410       int x_ppem, y_ppem, x_scale, y_scale;
411
412       if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
413           < 0)
414         return to;
415
416       face = ((FontInfo *) font)->face;
417       x_ppem = face->size->metrics.x_ppem;
418       y_ppem = face->size->metrics.y_ppem;
419       x_scale = face->size->metrics.x_scale;
420       y_scale = face->size->metrics.y_scale;
421
422       for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
423            i < otf_gstring.used; i++, otfg++, g++)
424         {
425           MFLTGlyph *prev;
426
427           if (! otfg->glyph_id)
428             continue;
429           switch (otfg->positioning_type)
430             {
431             case 0:
432               break;
433             case 1: case 2:
434               {
435                 int format = otfg->f.f1.format;
436
437                 if (format & OTF_XPlacement)
438                   adjustment[i].xoff
439                     = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
440                 if (format & OTF_XPlaDevice)
441                   adjustment[i].xoff
442                     += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
443                 if (format & OTF_YPlacement)
444                   adjustment[i].yoff
445                     = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
446                 if (format & OTF_YPlaDevice)
447                   adjustment[i].yoff
448                     -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
449                 if (format & OTF_XAdvance)
450                   adjustment[i].xadv
451                     += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
452                 if (format & OTF_XAdvDevice)
453                   adjustment[i].xadv
454                     += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
455                 if (format & OTF_YAdvance)
456                   adjustment[i].yadv
457                     += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
458                 if (format & OTF_YAdvDevice)
459                   adjustment[i].yadv
460                     += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
461                 adjustment[i].set = 1;
462               }
463               break;
464             case 3:
465               /* Not yet supported.  */
466               break;
467             case 4: case 5:
468               if (! base)
469                 break;
470               prev = base;
471               goto label_adjust_anchor;
472             default:            /* i.e. case 6 */
473               if (! mark)
474                 break;
475               prev = mark;
476
477             label_adjust_anchor:
478               {
479                 int base_x, base_y, mark_x, mark_y;
480
481                 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
482                 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
483                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
484                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
485
486                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
487                   adjust_anchor (otfg->f.f4.base_anchor, face, prev->code,
488                                  x_ppem, y_ppem, &base_x, &base_y);
489                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
490                   adjust_anchor (otfg->f.f4.mark_anchor, face, g->code,
491                                  x_ppem, y_ppem, &mark_x, &mark_y);
492                 adjustment[i].xoff = (base_x - mark_x);
493                 adjustment[i].yoff = - (base_y - mark_y);
494                 adjustment[i].back = (g - prev);
495                 adjustment[i].set = 1;
496               }
497             }
498           if (otfg->GlyphClass == OTF_GlyphClass0)
499             base = mark = g;
500           else if (otfg->GlyphClass == OTF_GlyphClassMark)
501             mark = g;
502           else
503             base = g;
504         }
505     }
506   free (otf_gstring.glyphs);
507   return to;
508
509  simple_copy:
510   font->get_metrics (font, in, from, to);
511   for (i = 0; i < len; i++)
512     {
513       MFLTGlyph *g = in->glyphs + (from + i);
514
515       out->glyphs[out->used++] = *g;
516     }
517   if (otf_gstring.glyphs)
518     free (otf_gstring.glyphs);
519   return to;
520 }
521
522 MFLTFont *
523 open_font (char *fontname, char **err)
524 {
525   FT_Face face = new_face (fontname, err);
526   FontInfoOTF *font_info;
527
528   if (! face)
529     return NULL;
530   font_info = malloc (sizeof (FontInfoOTF));
531   font_info->face = face;
532   font_info->otf = OTF_open_ft_face (face);
533   return ((MFLTFont *) font_info);
534 }
535
536 void
537 close_font (MFLTFont *font)
538 {
539   FontInfoOTF *font_info = (FontInfoOTF *) font;
540
541   OTF_close (font_info->otf);
542   FT_Done_Face (font_info->face);
543   free (font_info);
544 }
545
546 #else  /* FLT_HB */
547
548 typedef struct {
549   HB_UShort count;
550   HB_UShort *indices;
551 } FeatureInfo;
552
553 typedef struct {
554   FeatureInfo gsub;
555   FeatureInfo gpos;
556 } GsubGposInfo;
557
558 typedef struct {
559   MFLTFont font;
560   FT_Face face;
561   HB_FontRec hb_font;
562   HB_StreamRec gdef_stream;
563   HB_GDEF gdef;
564   HB_GSUB gsub;
565   HB_GPOS gpos;
566   MPlist *otf_spec_cache;
567 } FontInfoHB;
568
569 HB_Bool
570 convertStringToGlyphIndices (HB_Font font, const HB_UChar16 *string,
571                              hb_uint32 length, HB_Glyph *glyphs,
572                              hb_uint32 *numGlyphs, HB_Bool rightToLeft)
573 {
574   return TRUE;
575 }
576
577 void
578 getGlyphAdvances (HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs,
579                   HB_Fixed *advances, int flags /*HB_ShaperFlag*/)
580 {
581   hb_uint32 i;
582
583   for (i = 0; i < numGlyphs; i++)
584     advances[i] =0;
585 }
586
587 HB_Bool
588 canRender (HB_Font font, const HB_UChar16 *string, hb_uint32 length)
589 {
590   return TRUE;
591 }
592
593 HB_Error
594 getPointInOutline (HB_Font font, HB_Glyph glyph, int flags /*HB_ShaperFlag*/,
595                    hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos,
596                    hb_uint32 *nPoints)
597 {
598   FT_Face face = font->faceData;
599   HB_Error error;
600
601   if ((error = (HB_Error) FT_Load_Glyph (face, glyph, flags)))
602     return error;
603   if (face->glyph->format != ft_glyph_format_outline)
604     return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
605   *nPoints = face->glyph->outline.n_points;
606   if (! *nPoints)
607     return HB_Err_Ok;
608   if (point > *nPoints)
609     return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
610
611   *xpos = face->glyph->outline.points[point].x;
612   *ypos = face->glyph->outline.points[point].y;
613
614   return HB_Err_Ok;
615 }
616
617 void
618 getGlyphMetrics (HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
619 {
620 }
621
622 HB_Fixed
623 getFontMetric (HB_Font font, HB_FontMetric metric)
624 {
625   return 0;
626 }
627
628 #define MAKE_TAG(name) ((((FT_ULong) (name)[0]) << 24)          \
629                         | (((FT_ULong) (name)[1]) << 16)        \
630                         | (((FT_ULong) (name)[2]) << 8)         \
631                         | (name)[3])
632
633 HB_Error
634 new_stream (FT_Face face, char *tagname, HB_Stream stream)
635 {
636   FT_ULong tag = MAKE_TAG (tagname);
637   FT_ULong len;
638   FT_Byte *buf;
639
640   if (! FT_IS_SFNT (face))
641     return HB_Err_Invalid_Argument;
642   len = 0;
643   if (FT_Load_Sfnt_Table (face, tag, 0, NULL, &len))
644     return HB_Err_Table_Missing;
645   buf = malloc (len);
646   if (! buf)
647     return HB_Err_Out_Of_Memory;
648   if (FT_Load_Sfnt_Table (face, tag, 0, buf, &len))
649     {
650       free (buf);
651       return HB_Err_Table_Missing;
652     }
653   stream->base = (HB_Byte *) buf;
654   stream->size = len;
655   stream->pos = 0;
656   stream->cursor = NULL;
657
658   return HB_Err_Ok;
659 }
660
661 HB_Error
662 load_gdef (FontInfoHB *font_info)
663 {
664   HB_Error err;
665
666   if (! font_info->gdef_stream.base)
667     {
668       err = new_stream ((FT_Face) font_info->hb_font.faceData, "GDEF",
669                         &font_info->gdef_stream);
670       if (err != HB_Err_Ok)
671         return err;
672     }
673   return HB_Load_GDEF_Table (&font_info->gdef_stream, &font_info->gdef);
674 }
675
676 HB_Error
677 load_gsub (FontInfoHB *font_info)
678 {
679   HB_Error err;
680   HB_StreamRec stream;
681   HB_LookupList *lookup_list;
682   int i;
683
684   if (! font_info->gdef)
685     {
686       if ((err = load_gdef (font_info)) != HB_Err_Ok)
687         return err;
688     }
689   err = new_stream ((FT_Face) font_info->hb_font.faceData, "GSUB", &stream);
690   if (err != HB_Err_Ok)
691     return err;
692   err = HB_Load_GSUB_Table (&stream, &font_info->gsub,
693                             font_info->gdef, &font_info->gdef_stream);
694   free (stream.base);
695   lookup_list = &font_info->gsub->LookupList;
696   for (i = 0; i < lookup_list->LookupCount; i++)
697     lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
698   return err;
699 }
700
701 HB_Error
702 load_gpos (FontInfoHB *font_info)
703 {
704   HB_Error err;
705   HB_StreamRec stream;
706   HB_LookupList *lookup_list;
707   int i;
708
709   if (! font_info->gdef)
710     {
711       if ((err = load_gdef (font_info)) != HB_Err_Ok)
712         return err;
713     }
714   err = new_stream ((FT_Face) font_info->hb_font.faceData, "GPOS", &stream);
715   if (err != HB_Err_Ok)
716     return err;
717   err = HB_Load_GPOS_Table (&stream, &font_info->gpos,
718                             font_info->gdef, &font_info->gdef_stream);
719   free (stream.base);
720   lookup_list = &font_info->gpos->LookupList;
721   for (i = 0; i < lookup_list->LookupCount; i++)
722     lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
723   return err;
724 }
725
726 const HB_FontClass hb_fontClass = {
727     convertStringToGlyphIndices, getGlyphAdvances, canRender,
728     getPointInOutline, getGlyphMetrics, getFontMetric
729 };
730
731 void
732 setup_features (int gsubp, FontInfoHB *font_info, MFLTOtfSpec *spec,
733                 FeatureInfo *info)
734 {
735   int count, preordered;
736   unsigned int *features;
737   FT_UShort script, langsys;
738   FT_UShort req_feature, index;
739   FT_UInt *feature_list;
740   int i, j, k;
741
742   if (gsubp)
743     {
744       if (! font_info->gsub)
745         {
746           if (load_gsub (font_info) != HB_Err_Ok)
747             return;
748         }
749       if (HB_GSUB_Select_Script (font_info->gsub, spec->script, &script)
750           != HB_Err_Ok)
751         return;
752       if (spec->langsys)
753         {
754           if (HB_GSUB_Select_Language (font_info->gsub, spec->langsys,
755                                        script, &langsys, &req_feature)
756               != HB_Err_Ok)
757             return;
758         }
759       else
760         langsys = req_feature = 0xFFFF;
761       count = spec->gsub_count;
762       features = spec->gsub;
763     }
764   else
765     {
766       if (! font_info->gpos)
767         {
768           if (load_gpos (font_info) != HB_Err_Ok)
769             return;
770         }
771       if (HB_GPOS_Select_Script (font_info->gpos, spec->script, &script)
772           != HB_Err_Ok)
773         return;
774       if (spec->langsys)
775         {
776           if (HB_GPOS_Select_Language (font_info->gpos, spec->langsys,
777                                        script, &langsys, &req_feature)
778               != HB_Err_Ok)
779             return;
780         }
781       else
782         langsys = req_feature = 0xFFFF;
783       count = spec->gpos_count;
784       features = spec->gpos;
785     }
786   feature_list = NULL;
787   for (preordered = 0; preordered < count; preordered++)
788     if (features[preordered] == 0)
789       {
790         if ((gsubp ? HB_GSUB_Query_Features (font_info->gsub, script, langsys,
791                                              &feature_list)
792              : HB_GPOS_Query_Features (font_info->gpos, script, langsys,
793                                        &feature_list))
794             != HB_Err_Ok)
795           return;
796         break;
797       }
798   if (feature_list)
799     for (i = 0; feature_list[i]; i++);
800   else
801     i = preordered;
802   info->indices = malloc (sizeof (FT_UShort) * ((req_feature != 0xFFFF) + i));
803   i = 0;
804   if (req_feature != 0xFFFF)
805     info->indices[i++] = req_feature;
806   for (j = 0; j < preordered; j++)
807     if ((gsubp ? HB_GSUB_Select_Feature (font_info->gsub, features[j],
808                                          script, langsys, &index)
809          : HB_GPOS_Select_Feature (font_info->gpos, features[j],
810                                    script, langsys, &index))
811         == HB_Err_Ok)
812       info->indices[i++] = index;
813   if (feature_list)
814     for (j = 0; feature_list[j]; j++)
815       {
816         for (k = preordered + 1; k < count; k++)
817           if (feature_list[j] == features[k])
818             break;
819         if (k == count
820             && ((gsubp
821                  ? HB_GSUB_Select_Feature (font_info->gsub, feature_list[j],
822                                            script, langsys, &index)
823                  : HB_GPOS_Select_Feature (font_info->gpos, feature_list[j],
824                                            script, langsys, &index))
825                 == HB_Err_Ok))
826           info->indices[i++] = index;
827       }
828   info->count = i;
829 }
830
831 GsubGposInfo *
832 setup_otf_spec (MFLTFont *font, MFLTOtfSpec *spec)
833 {
834   FontInfoHB *font_info = (FontInfoHB *) font;
835   GsubGposInfo *ginfo;
836
837   if (spec->gsub_count + spec->gpos_count == 0)
838     return NULL;
839   ginfo = mplist_get (font_info->otf_spec_cache, spec->sym);
840   if (ginfo)
841     return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL);
842   ginfo = calloc (1, sizeof (GsubGposInfo));
843   mplist_push (font_info->otf_spec_cache, spec->sym, ginfo);
844   setup_features (1, font_info, spec, &(ginfo->gsub));
845   setup_features (0, font_info, spec, &(ginfo->gpos));
846   return ginfo;
847 }
848
849 int
850 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
851            MFLTGlyphString *in, int from, int to,
852            MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
853 {
854   FontInfoHB *font_info = (FontInfoHB *) font;
855   int len = to - from;
856   int i;
857   HB_Buffer buf;
858   GsubGposInfo *ginfo;
859   HB_UShort *apply_order_save;
860   HB_UShort apply_count_save;
861   int gpos_applied = 0;
862   HB_Error err;
863
864   if (len == 0)
865     return from;
866
867   buf = NULL;
868   if (hb_buffer_new (&buf) != FT_Err_Ok)
869     goto simple_copy;
870   for (i = from; i < to; i++)
871     {
872       if (hb_buffer_add_glyph (buf, in->glyphs[i].code, 0, i) != FT_Err_Ok)
873         goto simple_copy;
874     }
875   ginfo = setup_otf_spec (font, spec);
876   if (! ginfo)
877     goto simple_copy;
878   if (ginfo->gsub.count > 0)
879     {
880       if (! font_info->gdef
881           && load_gdef (font_info) != HB_Err_Ok)
882         goto simple_copy;
883       apply_order_save = font_info->gsub->FeatureList.ApplyOrder;
884       apply_count_save = font_info->gsub->FeatureList.ApplyCount;
885       font_info->gsub->FeatureList.ApplyOrder = ginfo->gsub.indices;
886       font_info->gsub->FeatureList.ApplyCount = ginfo->gsub.count;
887       err = HB_GSUB_Apply_String (font_info->gsub, buf);
888       font_info->gsub->FeatureList.ApplyOrder = apply_order_save;
889       font_info->gsub->FeatureList.ApplyCount = apply_count_save;
890       if (err != HB_Err_Ok && err != HB_Err_Not_Covered)
891         goto simple_copy;
892       if (out->used + buf->in_length > out->allocated)
893         return -2;
894     }
895
896   if (ginfo->gpos.count > 0
897       && (font_info->gpos || load_gpos (font_info) == HB_Err_Ok))
898     {
899       apply_order_save = font_info->gpos->FeatureList.ApplyOrder;
900       apply_count_save = font_info->gpos->FeatureList.ApplyCount;
901       font_info->gpos->FeatureList.ApplyOrder = ginfo->gpos.indices;
902       font_info->gpos->FeatureList.ApplyCount = ginfo->gpos.count;
903       err = HB_GPOS_Apply_String (&font_info->hb_font, font_info->gpos,
904                                   FT_LOAD_DEFAULT, buf, FALSE, FALSE);
905       font_info->gpos->FeatureList.ApplyOrder = apply_order_save;
906       font_info->gpos->FeatureList.ApplyCount = apply_count_save;
907       if (err == HB_Err_Ok)
908         gpos_applied = 1;
909     }
910
911   for (i = 0; i < buf->in_length; i++)
912     {
913       HB_GlyphItem hg = buf->in_string + i;
914       HB_Position pos = buf->positions + i;
915       MFLTGlyph *g;
916
917       out->glyphs[out->used] = in->glyphs[hg->cluster];
918       g = out->glyphs + out->used++;
919       if (g->code != hg->gindex)
920         {
921           g->c = 0;
922           g->code = hg->gindex;
923           g->measured = 0;
924         }
925       adjustment[i].set = gpos_applied;
926       if (gpos_applied)
927         {
928           adjustment[i].xadv = pos->x_advance;
929           adjustment[i].yadv = pos->y_advance;
930           adjustment[i].xoff = pos->x_pos;
931           adjustment[i].yoff = - pos->y_pos;
932           adjustment[i].back = pos->back;
933           adjustment[i].advance_is_absolute = pos->new_advance;
934         }
935     }
936   return to;
937
938  simple_copy:
939   if (buf)
940     hb_buffer_free (buf);
941   for (i = 0; i < len; i++)
942     out->glyphs[out->used++] = in->glyphs[from + i];
943   return to;
944 }
945
946 MFLTFont *
947 open_font (char *fontname, char **err)
948 {
949   FT_Face face = new_face (fontname, err);
950   FontInfoHB *font_info;
951
952   if (! face)
953     return NULL;
954   font_info = calloc (1, sizeof (FontInfoHB));
955   font_info->face = face;
956   font_info->hb_font.klass = &hb_fontClass;
957   font_info->hb_font.faceData = face;
958   font_info->hb_font.userData = NULL;
959   font_info->hb_font.x_ppem = face->size->metrics.x_ppem;
960   font_info->hb_font.x_scale = face->size->metrics.x_scale;
961   font_info->hb_font.y_scale = face->size->metrics.y_scale;
962   font_info->hb_font.y_ppem = face->size->metrics.y_ppem;
963   font_info->otf_spec_cache = mplist ();
964   return ((MFLTFont *) font_info);
965 }
966
967 void
968 close_font (MFLTFont *font)
969 {
970   FontInfoHB *font_info = (FontInfoHB *) font;
971   MPlist *p;
972
973   if (font_info->gdef)
974     {
975       HB_Done_GDEF_Table (font_info->gdef);
976       free (font_info->gdef_stream.base);
977     }
978   if (font_info->gsub)
979     HB_Done_GSUB_Table (font_info->gsub);
980   if (font_info->gpos)
981     HB_Done_GPOS_Table (font_info->gpos);
982   FT_Done_Face ((FT_Face) (font_info->hb_font.faceData));
983   for (p = font_info->otf_spec_cache; mplist_key (p) != Mnil;
984        p = mplist_next (p))
985     {
986       GsubGposInfo *ginfo = mplist_value (p);
987
988       if (ginfo->gsub.count > 0)
989         free (ginfo->gsub.indices);
990       if (ginfo->gpos.count > 0)
991         free (ginfo->gpos.indices);
992     }
993   m17n_object_unref (font_info->otf_spec_cache);
994   free (font_info);
995 }
996
997 #endif
998
999 #else  /* (defined (FLT_PANGO) */
1000
1001 typedef struct {
1002   int count;
1003   guint *indices;
1004   PangoOTRuleset *ruleset;
1005 } FeatureInfo;
1006
1007 typedef struct {
1008   FeatureInfo gsub;
1009   FeatureInfo gpos;
1010 } GsubGposInfo;
1011
1012 typedef struct {
1013   MFLTFont font;
1014   PangoFontMap *fontmap;
1015   PangoContext *context;
1016   PangoFcFont *pango_font;
1017   MPlist *otf_spec_cache;
1018 } FontInfoPango;
1019
1020 int
1021 get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
1022 {
1023   FontInfoPango *font_info = (FontInfoPango *) font;
1024
1025   for (; from < to; from++)
1026     {
1027       MFLTGlyph *g = gstring->glyphs + from;
1028
1029       if (! g->encoded
1030           && ! (g->code = pango_fc_font_get_glyph (font_info->pango_font,
1031                                                    g->code)))
1032         return -1;
1033       g->encoded = 1;
1034     }
1035   return 0;
1036 }
1037
1038 #define PANGO_SCALE_TO_26_6 (PANGO_SCALE / (1<<6))
1039
1040 int
1041 get_metrics (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
1042 {
1043   FontInfoPango *font_info = (FontInfoPango *) font;
1044   int i;
1045
1046   for (i = from; i < to; i++)
1047     {
1048       MFLTGlyph *g = gstring->glyphs + from;
1049
1050       if (! g->measured)
1051         {
1052           PangoRectangle inc, logical;
1053
1054           pango_font_get_glyph_extents (PANGO_FONT (font_info->pango_font),
1055                                         gstring->glyphs[i].code, &inc, &logical);
1056           g->lbearing = inc.x / PANGO_SCALE_TO_26_6;
1057           g->rbearing = (inc.x + inc.width) / PANGO_SCALE_TO_26_6;
1058           g->xadv = logical.width / PANGO_SCALE_TO_26_6;
1059           g->yadv = 0;
1060           g->ascent = - inc.y / PANGO_SCALE_TO_26_6;
1061           g->descent = (inc.height + inc.y) / PANGO_SCALE_TO_26_6;
1062           g->measured = 1;
1063         }
1064     }
1065   return 0;
1066 }
1067
1068
1069 #ifndef PANGO_OT_DEFAULT_LANGUAGE
1070 #define PANGO_OT_DEFAULT_LANGUAGE ((guint) 0xFFFF)
1071 #endif
1072 #ifndef PANGO_OT_ALL_GLYPHS
1073 #define PANGO_OT_ALL_GLYPHS ((guint) 0xFFFF)
1074 #endif
1075
1076 void
1077 setup_features (PangoOTTableType type, FontInfoPango *font_info,
1078                 MFLTOtfSpec *spec, FeatureInfo *info)
1079 {
1080   int count, preordered;
1081   unsigned int *features;
1082   guint script, langsys;
1083   guint req_feature, index;
1084   guint *feature_list;
1085   int i, j, k;
1086   FT_Face face;
1087   PangoOTInfo *ot_info; 
1088
1089   face = pango_fc_font_lock_face (font_info->pango_font);
1090   ot_info = pango_ot_info_get (face);
1091   pango_fc_font_unlock_face (font_info->pango_font);
1092
1093   if (! pango_ot_info_find_script (ot_info, type, spec->script, &script))
1094     return;
1095   if (spec->langsys)
1096     {
1097       if (! pango_ot_info_find_language (ot_info, type, script,
1098                                          spec->langsys,
1099                                          &langsys, &req_feature))
1100         return;
1101     }
1102   else
1103     {
1104       langsys = PANGO_OT_DEFAULT_LANGUAGE;
1105       req_feature = 0xFFFF;
1106     }
1107   if (type == PANGO_OT_TABLE_GSUB)
1108     {
1109       count = spec->gsub_count;
1110       features = spec->gsub;
1111     }
1112   else
1113     {
1114       count = spec->gpos_count;
1115       features = spec->gpos;
1116     }
1117   feature_list = NULL;
1118   for (preordered = 0; preordered < count; preordered++)
1119     if (features[preordered] == 0)
1120       {
1121         feature_list = pango_ot_info_list_features (ot_info, type, 0,
1122                                                     script, langsys);
1123         if (! feature_list)
1124           return;
1125         break;
1126       }
1127   if (feature_list)
1128     for (i = 0; feature_list[i]; i++);
1129   else
1130     i = preordered;
1131   info->indices = malloc (sizeof (guint) * ((req_feature != 0xFFFF) + i));
1132   i = 0;
1133   if (req_feature != 0xFFFF)
1134     info->indices[i++] = req_feature;
1135   for (j = 0; j < preordered; j++)
1136     if (pango_ot_info_find_feature (ot_info, type, features[j],
1137                                     script, langsys, &index))
1138       info->indices[i++] = index;
1139   if (feature_list)
1140     for (j = 0; feature_list[j]; j++)
1141       {
1142         for (k = preordered + 1; k < count; k++)
1143           if (feature_list[j] == features[k])
1144             break;
1145         if (k == count
1146             && pango_ot_info_find_feature (ot_info, type, feature_list[j],
1147                                            script, langsys, &index))
1148           info->indices[i++] = index;
1149       }
1150   info->count = i;
1151   info->ruleset = pango_ot_ruleset_new (ot_info);
1152 #if 1
1153   for (i = 0; i < info->count; i++)
1154     pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i],
1155                                   PANGO_OT_ALL_GLYPHS);
1156 #else
1157   for (i = info->count - 1; i >= 0; i--)
1158     pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i],
1159                                   PANGO_OT_ALL_GLYPHS);
1160 #endif
1161 }
1162
1163 GsubGposInfo *
1164 setup_otf_spec (FontInfoPango *font_info, MFLTOtfSpec *spec)
1165 {
1166   GsubGposInfo *ginfo;
1167
1168   if (spec->gsub_count + spec->gpos_count == 0)
1169     return NULL;
1170   ginfo = mplist_get (font_info->otf_spec_cache, spec->sym);
1171   if (ginfo)
1172     return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL);
1173   ginfo = calloc (1, sizeof (GsubGposInfo));
1174   mplist_push (font_info->otf_spec_cache, spec->sym, ginfo);
1175   setup_features (PANGO_OT_TABLE_GSUB, font_info, spec, &(ginfo->gsub));
1176   setup_features (PANGO_OT_TABLE_GPOS, font_info, spec, &(ginfo->gpos));
1177   return ginfo;
1178 }
1179
1180 int
1181 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
1182            MFLTGlyphString *in, int from, int to,
1183            MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
1184 {
1185   FontInfoPango *font_info = (FontInfoPango *) font;
1186   PangoOTBuffer *buffer;
1187   GsubGposInfo *ginfo;
1188   PangoGlyphString *glyphs;
1189   int i;
1190
1191   buffer = pango_ot_buffer_new (font_info->pango_font);
1192   for (i = from; i < to; i++)
1193     pango_ot_buffer_add_glyph (buffer, in->glyphs[i].code, 0, i);
1194   ginfo = setup_otf_spec (font_info, spec);
1195   if (! ginfo)
1196     goto simple_copy;
1197   if (ginfo->gsub.count > 0)
1198     pango_ot_ruleset_substitute (ginfo->gsub.ruleset, buffer);
1199   if (ginfo->gpos.count > 0)
1200     pango_ot_ruleset_position (ginfo->gpos.ruleset, buffer);
1201   glyphs = pango_glyph_string_new ();
1202   pango_ot_buffer_output (buffer, glyphs);
1203   for (i = 0; i < glyphs->num_glyphs; i++)
1204     {
1205       PangoGlyphInfo *glyph_info = glyphs->glyphs + i;
1206       MFLTGlyph *g;
1207
1208       out->glyphs[out->used] = in->glyphs[glyphs->log_clusters[i]];
1209       g = out->glyphs + out->used++;
1210       if (g->code != glyph_info->glyph)
1211         {
1212           g->c = 0;
1213           g->code = glyph_info->glyph;
1214           g->measured = 0;
1215         }
1216       g->xoff = glyph_info->geometry.x_offset / PANGO_SCALE_TO_26_6;
1217       g->yoff = glyph_info->geometry.y_offset / PANGO_SCALE_TO_26_6;
1218       g->xadv = glyph_info->geometry.width / PANGO_SCALE_TO_26_6;
1219       g->yadv = 0;
1220       adjustment[i].set = 0;
1221     }
1222   pango_ot_buffer_destroy (buffer);
1223   pango_glyph_string_free (glyphs);
1224   return to;
1225
1226  simple_copy:
1227   pango_ot_buffer_destroy (buffer);
1228   for (i = from; i < to; i++)
1229     out->glyphs[out->used++] = in->glyphs[i];
1230   return to;
1231 }
1232
1233
1234 MFLTFont *
1235 open_font (char *fontname, char **err)
1236 {
1237   FontInfoPango *font_info = NULL;
1238   PangoFontMap *fontmap;
1239   PangoContext *context;
1240   PangoFontDescription *desc;
1241   PangoFont *pango_font;
1242   char *family;
1243   int size;
1244   double pango_size;
1245   
1246   if (parse_font_name (fontname, &family, &size, err) < 0)
1247     return NULL;
1248   desc = pango_font_description_new ();
1249   pango_font_description_set_family (desc, family);
1250   free (family);
1251   pango_size = size * PANGO_SCALE;
1252   pango_font_description_set_absolute_size (desc, pango_size);
1253
1254   fontmap = pango_ft2_font_map_new ();
1255   context = pango_context_new ();
1256   pango_context_set_font_map (context, fontmap);
1257   pango_font = pango_context_load_font (context, desc);
1258   pango_font_description_free (desc);
1259   if (pango_font)
1260     {
1261       font_info = calloc (1, sizeof (FontInfoPango));
1262       font_info->fontmap = fontmap;
1263       font_info->context = context;
1264       font_info->pango_font = PANGO_FC_FONT (pango_font);
1265       font_info->otf_spec_cache = mplist ();
1266     }
1267   else
1268     {
1269       g_object_unref (context);
1270       g_object_unref (fontmap);
1271     }
1272   return (MFLTFont *) font_info;
1273 }
1274
1275 void
1276 close_font (MFLTFont *font)
1277 {
1278   FontInfoPango *font_info = (FontInfoPango *) font;
1279
1280   g_object_unref (font_info->context);
1281   g_object_unref (font_info->fontmap);
1282 }
1283
1284 #endif
1285
1286 #ifdef FLT_GUI
1287
1288 int
1289 run_flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
1290 {
1291   MDrawControl control;
1292
1293   memset (&control, 0, sizeof (MDrawControl));
1294   control.two_dimensional = 1;
1295   control.enable_bidi = 1;
1296   control.anti_alias = 1;
1297   /*control.disable_caching = 1;*/
1298   mtext_put_prop (mt, from, to, Mfont, font->font);
1299   mdraw_text_extents (frame, mt, from, to, &control, NULL, NULL, NULL);
1300   return 0;
1301 }
1302
1303 #else
1304
1305 int
1306 run_flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
1307 {
1308   static MFLT *flt = NULL;
1309   MCharTable *coverage;
1310   static MFLTGlyphString gstring;
1311
1312   if (! flt
1313       && ! (flt = mflt_get (flt_name)))
1314     {
1315       fprintf (stderr, "Invalid FLT name: %s\n", flt_name);
1316       exit (1);
1317     }
1318   coverage = mflt_coverage (flt);
1319   while (from < to)
1320     {
1321       int len = 0, i;
1322
1323       for (; from < to; from++)
1324         if (mchartable_lookup (coverage, mtext_ref_char (mt, from)))
1325           {
1326             for (i = from + 1; i < to; i++)
1327               if (! mchartable_lookup (coverage, mtext_ref_char (mt, i)))
1328                 break;
1329             len = i - from;
1330             break;
1331           }
1332       if (len > 0)
1333         {
1334           if (gstring.allocated < len)
1335             {
1336               gstring.allocated = len * 2;
1337               gstring.glyphs = realloc (gstring.glyphs,
1338                                         sizeof (MFLTGlyph) * len * 2);
1339             }
1340           gstring.glyph_size = sizeof (MFLTGlyph);
1341           for (i = 0; i < len; i++)
1342             gstring.glyphs[i].c = mtext_ref_char (mt, from + i);
1343           gstring.used = len;
1344           i = mflt_run (&gstring, 0, len, font, flt);
1345           if (i < 0)
1346             return i;
1347           from += len;
1348         }
1349     }
1350   return to;
1351 }
1352 #endif
1353
1354
1355 int
1356 main (int argc, char **argv)
1357 {
1358   char *font_name, *flt_name;
1359   char *err;
1360   MText *mt;
1361   MFLTFont *font;
1362   int len, i, j;
1363   unsigned char *buf;
1364
1365   if (argc < 3)
1366     {
1367       fprintf (stderr, "Usage: flt FONT-NAME FLT-NAME < TEXT-FILE\n");
1368       exit (1);
1369     }
1370
1371   font_name = argv[1];
1372   flt_name = argv[2];
1373
1374   FT_Init_FreeType (&ft_library);
1375   M17N_INIT ();
1376   font = open_font (font_name, &err);
1377   if (! font)
1378     {
1379       fprintf (stderr, "Font error: %s: %s\n", argv[1], err);
1380       exit (1);
1381     }
1382   font->get_glyph_id = get_glyph_id;
1383   font->get_metrics = get_metrics;
1384   font->drive_otf = drive_otf;
1385
1386   i = 0;
1387   buf = malloc (4096);
1388   while ((j = fread (buf + i, 1, 4096, stdin)) == 4096)
1389     {
1390       i += 4096;
1391       buf = realloc (buf, i + 4096);
1392     }
1393   mt = mtext_from_data (buf, i, MTEXT_FORMAT_UTF_8);
1394   len = mtext_len (mt);
1395   for (i = 0, j = mtext_character (mt, i, len, '\n'); i < len;
1396        i = j + 1, j = mtext_character (mt, i, len, '\n'))
1397     {
1398       int to;
1399
1400       if (j < 0)
1401         j = len;
1402       to = run_flt (mt, i, j, font, flt_name);
1403       if (to < 0)
1404         {
1405           fprintf (stderr, "Error in FLT processing.\n");
1406           exit (1);
1407         }
1408       i = j;
1409     }
1410   m17n_object_unref (mt);
1411   free (buf);
1412   close_font (font);
1413   M17N_FINI ();
1414   return 0;
1415 }