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