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