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