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