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