*** empty log message ***
[m17n/m17n-test.git] / flt-hb.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 #incldue <otf.h>
18 #define PROGNAME "flt-otf"
19
20 #else  /* defined (FLT_HB) */
21
22 #include <m17n-flt.h>
23 #include <harfbuzz.h>
24 #define PROGNAME "flt-hb"
25
26 #fi
27
28 static FT_Library ft_library;
29
30 FT_Face
31 new_face (char *fontname, char **err)
32 {
33   FcPattern *pat;
34   FcChar8 *fam, *file;
35   double pixelsize;
36   FcFontSet *fs;
37   FcObjectSet *os;
38   FT_Face face;
39
40   pat = FcNameParse ((FcChar8 *) fontname);
41   if (! pat)
42     {
43       *err = "invalid name format";
44       return NULL;
45     }
46   if (FcPatternGetString (pat, FC_FAMILY, 0, &fam) != FcResultMatch)
47     {
48       *err = "no family name";
49       return NULL;
50     }
51   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &pixelsize) != FcResultMatch)
52     pixelsize = 20;
53   FcPatternAddBool (pat, FC_SCALABLE, FcTrue);
54   FcPatternDel (pat, FC_PIXEL_SIZE);
55   os = FcObjectSetBuild (FC_FILE, NULL);
56   fs = FcFontList (NULL, pat, os);
57   if (fs->nfont == 0)
58     {
59       *err = "no matching font";
60       return NULL;
61     }
62   FcPatternGetString (fs->fonts[0], FC_FILE, 0, &file);
63
64   if (FT_New_Face (ft_library, (char *) file, 0, &face))
65     {
66       FcFontSetDestroy (fs);
67       FcObjectSetDestroy (os);
68       FcPatternDestroy (pat);
69       *err = "font open fail";
70       return NULL;
71     }
72   FcFontSetDestroy (fs);
73   FcObjectSetDestroy (os);
74   FcPatternDestroy (pat);
75   if (FT_Set_Pixel_Sizes (face, pixelsize, pixelsize))
76     {
77       *err = "set pixelsize fail";
78       FT_Done_Face (face);
79       return NULL;
80     }
81   return face;
82 }
83
84 #ifdef FLT_GUI
85
86 typedef struct
87 {
88   MFont *font;
89   FT_Face face;
90 } MFLTFont;
91
92 MFrame *frame;
93
94 MFLTFont *
95 open_font (char *fontname, char **err)
96 {
97   FT_Face ft_face = new_face (fontname, err);
98   MFLTFont *font;
99   MFace *face;
100   MPlist *plist;
101   MFontset *fontset;
102
103   if (! face)
104     return NULL;
105   face = mface ();
106   plist = mplist ();
107   fontset = mfontset ("generic");
108   mface_put_prop (face, Mfontset, fontset);
109   mplist_add (plist, Mface, face);
110   mplist_add (plist, Mdevice, Mnil);
111   frame = mframe (plist);
112   m17n_object_unref (plist);
113   m17n_object_unref (face);
114   m17n_object_unref (fontset);
115
116   font = calloc (1, sizeof (MFLTFont));
117   font->font = mfont_encapsulate (frame, Mfreetype, ft_face);
118   font->face = ft_face;
119   return font;
120 }
121
122 void
123 close_font (MFLTFont *font)
124 {
125   FT_Done_Face (font->face);
126   free (font);
127   m17n_object_unref (frame);
128 }
129
130 int
131 flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
132 {
133   mtext_put_prop (mt, from, to, Mfont, font->font);
134   mdraw_text_extents (frame, mt, from, to, NULL, NULL, NULL, NULL);
135   return 0;
136 }
137
138 #else  /* FLT_OTF or FLT_HB */
139
140 typedef struct {
141   MFLTFont font;
142   FT_Face face;
143   OTF *otf;
144 } FontInfo;
145
146 int
147 get_glyph_id (MFLTFont *font, MFLTGlyph *g)
148 {
149   FT_Face face = ((FontInfo *) font)->face;
150
151   g->code = FT_Get_Char_Index (face, g->code);
152
153   return (g->code ? 0 : -1);
154 }
155
156 int 
157 get_metric (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
158 {
159   FT_Face face = ((FontInfo *) font)->face;
160
161   for (; from < to; from++)
162     {
163       MFLTGlyph *g = gstring->glyphs + from;
164       FT_Glyph_Metrics *metrics;
165
166       if (FT_Load_Glyph (face, g->code, FT_LOAD_DEFAULT))
167         return -1;
168       metrics = &face->glyph->metrics;
169       g->lbearing = metrics->horiBearingX;
170       g->rbearing = metrics->horiBearingX + metrics->width;
171       g->xadv = metrics->horiAdvance;
172       g->yadv = metrics->vertAdvance;
173       g->ascent = metrics->horiBearingY;
174       g->descent = metrics->height - metrics->horiBearingY;
175     }
176   return 0;
177 }
178
179 int
180 flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
181 {
182   MFLTGlyphString gstring;
183   int len = to - from;
184   int i;
185
186   memset (&gstring, 0, sizeof (MFLTGlyphString));
187   gstring.glyph_size = sizeof (MFLTGlyph);
188   gstring.allocated = len * 2;
189   gstring.glyphs = alloca (sizeof (MFLTGlyph) * gstring.allocated);
190   for (i = 0; i < len; i++)
191     gstring.glyphs[i].c = mtext_ref_char (mt, from + i);
192   gstring.used = len;
193   return mflt_run (&gstring, 0, len, font, msymbol (flt_name));
194 }
195
196 #ifdef FLT_OTF
197
198 typedef struct {
199   MFLTFont font;
200   FT_Face face;
201   OTF *otf;
202 } FontInfo;
203
204 #define DEVICE_DELTA(table, size)                               \
205   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
206    ? ((table).DeltaValue[(size) - (table).StartSize] << 6)      \
207    : 0)
208
209 static void
210 adjust_anchor (OTF_Anchor *anchor, FT_Face face,
211                unsigned code, unsigned x_ppem, unsigned y_ppem, int *x, int *y)
212 {
213   if (anchor->AnchorFormat == 2)
214     {
215       FT_Outline *outline;
216       int ap = anchor->f.f1.AnchorPoint;
217
218       FT_Load_Glyph (face, (FT_UInt) code, FT_LOAD_MONOCHROME);
219       outline = &face->glyph->outline;
220       if (ap < outline->n_points)
221         {
222           *x = outline->points[ap].x;
223           *y = outline->points[ap].y;
224         }
225     }
226   else if (anchor->AnchorFormat == 3)
227     {
228       if (anchor->f.f2.XDeviceTable.offset)
229         *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
230       if (anchor->f.f2.YDeviceTable.offset)
231         *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
232     }
233 }
234
235 char *
236 tag_name (char *str, unsigned tag)
237 {
238   *str++ = tag >> 24;
239   *str++ = (tag >> 16) & 0xFF;
240   *str++ = (tag >> 8) & 0xFF;
241   *str++ = tag & 0xFF;
242   return str;
243 }
244
245 void
246 encode_features (char *str, int count, unsigned *features)
247 {
248   int all = 0;
249   int i;
250
251   for (i = 0; i < count; i++)
252     {
253       unsigned tag = features[i];
254
255       if (tag == 0)
256         all = 1;
257       else
258         {
259           if (i > 0)
260             *str++ = ',';
261           if (all)
262             *str++ = '~';
263           str = tag_name (str, tag);
264         }
265     }
266   if (all)
267     {
268       if (i > 1)
269         *str++ = ',';
270       *str++ = '*';
271     }
272   *str = '\0';
273 }
274
275 int
276 drive_otf (MFLTFont *font, MFLT_OTF_Spec *spec,
277            MFLTGlyphString *in, int from, int to,
278            MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
279 {
280   int len = to - from;
281   int i, gidx;
282   OTF *otf = ((FontInfo *) font)->otf;
283   OTF_GlyphString otf_gstring;
284   OTF_Glyph *otfg;
285   char script[4], langsys[4];
286   char *gsub_features = NULL, *gpos_features = NULL;
287
288   if (len == 0)
289     return from;
290
291   if (! otf)
292     goto simple_copy;
293   otf_gstring.glyphs = NULL;
294   if (OTF_get_table (otf, "head") < 0)
295     {
296       OTF_close (otf);
297       ((FontInfo *) font)->otf = NULL;
298       goto simple_copy;
299     }
300
301   tag_name (script, spec->script);
302   tag_name (langsys, spec->langsys);
303
304   if (spec->gsub_count > 0)
305     {
306       gsub_features = alloca (6 * spec->gsub_count);
307       if (gsub_features)
308         {
309           if (OTF_check_table (otf, "GSUB") < 0)
310             gsub_features = NULL;
311           else
312             encode_features (gsub_features, spec->gsub_count, spec->gsub);
313         }
314     }
315   if (spec->gpos_count)
316     {
317       gpos_features = alloca (6 * spec->gpos_count);
318       if (gpos_features)
319         {
320           if (OTF_check_table (otf, "GPOS") < 0)
321             gpos_features = NULL;
322           else
323             encode_features (gpos_features, spec->gpos_count, spec->gpos);
324         }
325     }
326
327   otf_gstring.size = otf_gstring.used = len;
328   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
329   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
330   for (i = 0; i < len; i++)
331     {
332       otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
333       otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
334     }
335
336   OTF_drive_gdef (otf, &otf_gstring);
337   gidx = out->used;
338
339   if (gsub_features)
340     {
341       if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
342           < 0)
343         goto simple_copy;
344       if (out->allocated < out->used + otf_gstring.used)
345         return -2;
346       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
347         {
348           MFLTGlyph *g = out->glyphs + out->used;
349
350           *g = in->glyphs[from + otfg->f.index.from];
351           g->c = otfg->c;
352           g->code = otfg->glyph_id;
353           out->used++;
354         }
355     }
356   else
357     {
358       if (out->allocated < out->used + len)
359         return -2;
360       for (i = 0; i < len; i++)
361         out->glyphs[out->used++] = in->glyphs[from + i];
362     }
363
364   font->get_metric (font, out, gidx, out->used);
365
366   if (gpos_features)
367     {
368       FT_Face face;
369       MFLTGlyph *base = NULL, *mark = NULL, *g;
370       int x_ppem, y_ppem, x_scale, y_scale;
371
372       if (OTF_check_features (otf, 1,
373                               spec->script, spec->langsys,
374                               spec->gpos, spec->gpos_count) != 1
375           || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
376                               gpos_features) < 0))
377         return to;
378
379       face = ((FontInfo *) font)->face;
380       x_ppem = face->size->metrics.x_ppem;
381       y_ppem = face->size->metrics.y_ppem;
382       x_scale = face->size->metrics.x_scale;
383       y_scale = face->size->metrics.y_scale;
384
385       for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
386            i < otf_gstring.used; i++, otfg++, g++)
387         {
388           MFLTGlyph *prev;
389
390           if (! otfg->glyph_id)
391             continue;
392           switch (otfg->positioning_type)
393             {
394             case 0:
395               break;
396             case 1: case 2:
397               {
398                 int format = otfg->f.f1.format;
399
400                 if (format & OTF_XPlacement)
401                   adjustment[i].xoff
402                     = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
403                 if (format & OTF_XPlaDevice)
404                   adjustment[i].xoff
405                     += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
406                 if (format & OTF_YPlacement)
407                   adjustment[i].yoff
408                     = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
409                 if (format & OTF_YPlaDevice)
410                   adjustment[i].yoff
411                     -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
412                 if (format & OTF_XAdvance)
413                   adjustment[i].xadv
414                     += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
415                 if (format & OTF_XAdvDevice)
416                   adjustment[i].xadv
417                     += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
418                 if (format & OTF_YAdvance)
419                   adjustment[i].yadv
420                     += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
421                 if (format & OTF_YAdvDevice)
422                   adjustment[i].xadv
423                     += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
424                 adjustment[i].set = 1;
425               }
426               break;
427             case 3:
428               /* Not yet supported.  */
429               break;
430             case 4: case 5:
431               if (! base)
432                 break;
433               prev = base;
434               goto label_adjust_anchor;
435             default:            /* i.e. case 6 */
436               if (! mark)
437                 break;
438               prev = mark;
439
440             label_adjust_anchor:
441               {
442                 int base_x, base_y, mark_x, mark_y;
443
444                 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
445                 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
446                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
447                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
448
449                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
450                   adjust_anchor (otfg->f.f4.base_anchor, face, prev->code,
451                                  x_ppem, y_ppem, &base_x, &base_y);
452                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
453                   adjust_anchor (otfg->f.f4.mark_anchor, face, g->code,
454                                  x_ppem, y_ppem, &mark_x, &mark_y);
455                 adjustment[i].xoff = (base_x - mark_x);
456                 adjustment[i].yoff = - (base_y - mark_y);
457                 adjustment[i].back = (g - prev);
458                 adjustment[i].set = 1;
459               }
460             }
461           if (otfg->GlyphClass == OTF_GlyphClass0)
462             base = mark = g;
463           else if (otfg->GlyphClass == OTF_GlyphClassMark)
464             mark = g;
465           else
466             base = g;
467         }
468     }
469   free (otf_gstring.glyphs);
470   return to;
471
472  simple_copy:
473   font->get_metric (font, in, from, to);
474   for (i = 0; i < len; i++)
475     {
476       MFLTGlyph *g = in->glyphs + (from + i);
477
478       out->glyphs[out->used++] = *g;
479     }
480   if (otf_gstring.glyphs)
481     free (otf_gstring.glyphs);
482   return to;
483 }
484
485 MFLTFont *
486 open_font (char *fontname, char **err)
487 {
488   FT_Face face = new_face (fontname, err);
489   FontInfo *font_info;
490
491   if (! face)
492     return NULL;
493   font_info = malloc (sizeof (FontInfo));
494   font_info->font.get_glyph_id = get_glyph_id;
495   font_info->font.get_metric = get_metric;
496   font_info->font.drive_otf = drive_otf;
497   font_info->face = face;
498   font_info->otf = OTF_open_ft_face (face);
499   return ((MFLTFont *) font_info);
500 }
501
502 void
503 close_font (MFLTFont *font)
504 {
505   FontInfo *font_info = (FontInfo *) font;
506
507   OTF_close (font_info->otf);
508   FT_Done_Face (font_info->face);
509   free (font_info);
510 }
511
512 #else  /* FLT_HB */
513
514 typedef struct {
515   HB_UShort count;
516   HB_UShort *indices;
517 } FeatureInfo;
518
519 typedef struct {
520   FeatureInfo gsub;
521   FeatureInfo gpos;
522 } GsubGposInfo;
523
524 typedef struct {
525   MFLTFont font;
526   FT_Face face;
527   HB_FontRec hb_font;
528   HB_StreamRec gdef_stream;
529   HB_GDEF gdef;
530   HB_GSUB gsub;
531   HB_GPOS gpos;
532   MPlist *otf_spec_cache;
533 } FontInfo;
534
535 HB_Bool
536 convertStringToGlyphIndices (HB_Font font, const HB_UChar16 *string,
537                              hb_uint32 length, HB_Glyph *glyphs,
538                              hb_uint32 *numGlyphs, HB_Bool rightToLeft)
539 {
540   return TRUE;
541 }
542
543 void
544 getGlyphAdvances (HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs,
545                   HB_Fixed *advances, int flags /*HB_ShaperFlag*/)
546 {
547   hb_uint32 i;
548
549   for (i = 0; i < numGlyphs; i++)
550     advances[i] =0;
551 }
552
553 HB_Bool
554 canRender (HB_Font font, const HB_UChar16 *string, hb_uint32 length)
555 {
556   return TRUE;
557 }
558
559 HB_Error
560 getPointInOutline (HB_Font font, HB_Glyph glyph, int flags /*HB_ShaperFlag*/,
561                    hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos,
562                    hb_uint32 *nPoints)
563 {
564   FT_Face face = font->faceData;
565   HB_Error error;
566
567   if ((error = (HB_Error) FT_Load_Glyph (face, glyph, flags)))
568     return error;
569   if (face->glyph->format != ft_glyph_format_outline)
570     return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
571   *nPoints = face->glyph->outline.n_points;
572   if (! *nPoints)
573     return HB_Err_Ok;
574   if (point > *nPoints)
575     return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
576
577   *xpos = face->glyph->outline.points[point].x;
578   *ypos = face->glyph->outline.points[point].y;
579
580   return HB_Err_Ok;
581 }
582
583 void
584 getGlyphMetrics (HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
585 {
586 }
587
588 HB_Fixed
589 getFontMetric (HB_Font font, HB_FontMetric metric)
590 {
591   return 0;
592 }
593
594 #define MAKE_TAG(name) ((((FT_ULong) (name)[0]) << 24)          \
595                         | (((FT_ULong) (name)[1]) << 16)        \
596                         | (((FT_ULong) (name)[2]) << 8)         \
597                         | (name)[3])
598
599 HB_Error
600 new_stream (FT_Face face, char *tagname, HB_Stream stream)
601 {
602   FT_ULong tag = MAKE_TAG (tagname);
603   FT_ULong len;
604   FT_Byte *buf;
605
606   if (! FT_IS_SFNT (face))
607     return HB_Err_Invalid_Argument;
608   len = 0;
609   if (FT_Load_Sfnt_Table (face, tag, 0, NULL, &len))
610     return HB_Err_Table_Missing;
611   buf = malloc (len);
612   if (! buf)
613     return HB_Err_Out_Of_Memory;
614   if (FT_Load_Sfnt_Table (face, tag, 0, buf, &len))
615     {
616       free (buf);
617       return HB_Err_Table_Missing;
618     }
619   stream->base = (HB_Byte *) buf;
620   stream->size = len;
621   stream->pos = 0;
622   stream->cursor = NULL;
623
624   return HB_Err_Ok;
625 }
626
627 HB_Error
628 load_gdef (FontInfo *font_info)
629 {
630   HB_Error err;
631
632   if (! font_info->gdef_stream.base)
633     {
634       err = new_stream ((FT_Face) font_info->hb_font.faceData, "GDEF",
635                         &font_info->gdef_stream);
636       if (err != HB_Err_Ok)
637         return err;
638     }
639   return HB_Load_GDEF_Table (&font_info->gdef_stream, &font_info->gdef);
640 }
641
642 HB_Error
643 load_gsub (FontInfo *font_info)
644 {
645   HB_Error err;
646   HB_StreamRec stream;
647   HB_LookupList *lookup_list;
648   int i;
649
650   if (! font_info->gdef)
651     {
652       if ((err = load_gdef (font_info)) != HB_Err_Ok)
653         return err;
654     }
655   err = new_stream ((FT_Face) font_info->hb_font.faceData, "GSUB", &stream);
656   if (err != HB_Err_Ok)
657     return err;
658   err = HB_Load_GSUB_Table (&stream, &font_info->gsub,
659                             font_info->gdef, &font_info->gdef_stream);
660   free (stream.base);
661   lookup_list = &font_info->gsub->LookupList;
662   for (i = 0; i < lookup_list->LookupCount; i++)
663     lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
664   return err;
665 }
666
667 HB_Error
668 load_gpos (FontInfo *font_info)
669 {
670   HB_Error err;
671   HB_StreamRec stream;
672   HB_LookupList *lookup_list;
673   int i;
674
675   if (! font_info->gdef)
676     {
677       if ((err = load_gdef (font_info)) != HB_Err_Ok)
678         return err;
679     }
680   err = new_stream ((FT_Face) font_info->hb_font.faceData, "GPOS", &stream);
681   if (err != HB_Err_Ok)
682     return err;
683   err = HB_Load_GPOS_Table (&stream, &font_info->gpos,
684                             font_info->gdef, &font_info->gdef_stream);
685   free (stream.base);
686   lookup_list = &font_info->gpos->LookupList;
687   for (i = 0; i < lookup_list->LookupCount; i++)
688     lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
689   return err;
690 }
691
692 const HB_FontClass hb_fontClass = {
693     convertStringToGlyphIndices, getGlyphAdvances, canRender,
694     getPointInOutline, getGlyphMetrics, getFontMetric
695 };
696
697 HB_Error
698 setup_features (int gsubp, FontInfo *font_info, MFLT_OTF_Spec *spec,
699                 FeatureInfo *info)
700 {
701   int count, preordered;
702   unsigned int *features;
703   FT_UShort script, langsys;
704   FT_UShort req_feature, index;
705   FT_UInt *feature_list;
706   int i, j, k;
707   HB_Error err;
708
709   if (gsubp)
710     {
711       if (! font_info->gsub)
712         {
713           if ((err = load_gsub (font_info)) != HB_Err_Ok)
714             return err;
715         }
716       if ((err = HB_GSUB_Select_Script (font_info->gsub, spec->script, &script))
717           != HB_Err_Ok)
718         return err;
719       if (spec->langsys)
720         {
721           if ((err = HB_GSUB_Select_Language (font_info->gsub, spec->langsys,
722                                               script, &langsys, &req_feature))
723               != HB_Err_Ok)
724             return err;
725         }
726       else
727         langsys = req_feature = 0xFFFF;
728       count = spec->gsub_count;
729       features = spec->gsub;
730     }
731   else
732     {
733       if (! font_info->gpos)
734         {
735           if ((err = load_gpos (font_info)) != HB_Err_Ok)
736             return err;
737         }
738       if ((err = HB_GPOS_Select_Script (font_info->gpos, spec->script, &script))
739           != HB_Err_Ok)
740         return err;
741       if (spec->langsys)
742         {
743           if ((err = HB_GPOS_Select_Language (font_info->gpos, spec->langsys,
744                                               script, &langsys, &req_feature))
745               != HB_Err_Ok)
746             return err;
747         }
748       else
749         langsys = req_feature = 0xFFFF;
750       count = spec->gpos_count;
751       features = spec->gpos;
752     }
753   feature_list = NULL;
754   for (preordered = 0; preordered < count; preordered++)
755     if (features[preordered] == 0)
756       {
757         if ((err = (gsubp
758                     ? HB_GSUB_Query_Features (font_info->gsub, script, langsys,
759                                               &feature_list)
760                     : HB_GPOS_Query_Features (font_info->gpos, script, langsys,
761                                               &feature_list)))
762             != HB_Err_Ok)
763           return err;
764         break;
765       }
766   if (feature_list)
767     for (i = 0; feature_list[i]; i++);
768   else
769     i = preordered;
770   info->indices = malloc (sizeof (FT_UShort) * ((req_feature != 0xFFFF) + i));
771   i = 0;
772   if (req_feature != 0xFFFF)
773     info->indices[i++] = req_feature;
774   for (j = 0; j < preordered; j++)
775     {
776       if ((err = (gsubp
777                   ? HB_GSUB_Select_Feature (font_info->gsub, features[j],
778                                             script, langsys, &index)
779                   : HB_GPOS_Select_Feature (font_info->gpos, features[j],
780                                             script, langsys, &index)))
781           != HB_Err_Ok)
782         return err;
783       info->indices[i++] = index;
784     }
785   if (feature_list)
786     for (j = 0; feature_list[j]; j++)
787       {
788         for (k = preordered + 1; k < count; k++)
789           if (feature_list[j] == features[k])
790             break;
791         if (k == count)
792           {
793             if ((gsubp
794                  ? HB_GSUB_Select_Feature (font_info->gsub, feature_list[j],
795                                            script, langsys, &index)
796                  : HB_GPOS_Select_Feature (font_info->gpos, feature_list[j],
797                                            script, langsys, &index))
798                 != FT_Err_Ok)
799               return -1;
800             info->indices[i++] = index;
801           }
802       }
803   info->count = i;
804   return HB_Err_Ok;
805 }
806
807 GsubGposInfo *
808 setup_otf_spec (MFLTFont *font, MFLT_OTF_Spec *spec)
809 {
810   FontInfo *font_info = (FontInfo *) font;
811   GsubGposInfo *ginfo;
812
813   if (spec->gsub_count + spec->gpos_count == 0)
814     return NULL;
815   ginfo = mplist_get (font_info->otf_spec_cache, spec->sym);
816   if (ginfo)
817     return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL);
818   ginfo = calloc (1, sizeof (GsubGposInfo));
819   mplist_push (font_info->otf_spec_cache, spec->sym, ginfo);
820   if (setup_features (1, font_info, spec, &(ginfo->gsub)) != HB_Err_Ok)
821     return NULL;
822   if (setup_features (0, font_info, spec, &(ginfo->gpos)) != HB_Err_Ok)
823     return NULL;
824   return ginfo;
825 }
826
827 int
828 drive_otf (MFLTFont *font, MFLT_OTF_Spec *spec,
829            MFLTGlyphString *in, int from, int to,
830            MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
831 {
832   FontInfo *font_info = (FontInfo *) font;
833   int len = to - from;
834   int i, gidx;
835   HB_Buffer buf;
836   GsubGposInfo *ginfo;
837   HB_UShort *apply_order_save;
838   HB_UShort apply_count_save;
839   int apply_saved = 0;
840   int gpos_applied = 0;
841   HB_Error err;
842
843   if (len == 0)
844     return from;
845
846   buf = NULL;
847   if (hb_buffer_new (&buf) != FT_Err_Ok)
848     goto simple_copy;
849   for (i = from; i < to; i++)
850     {
851       if (hb_buffer_add_glyph (buf, in->glyphs[i].code, 0, i) != FT_Err_Ok)
852         goto simple_copy;
853     }
854   ginfo = setup_otf_spec (font, spec);
855   if (! ginfo)
856     goto simple_copy;
857   if (ginfo->gsub.count > 0)
858     {
859       if (! font_info->gdef
860           && load_gdef (font_info) != HB_Err_Ok)
861         goto simple_copy;
862       apply_order_save = font_info->gsub->FeatureList.ApplyOrder;
863       apply_count_save = font_info->gsub->FeatureList.ApplyCount;
864       apply_saved = 1;
865       font_info->gsub->FeatureList.ApplyOrder = ginfo->gsub.indices;
866       font_info->gsub->FeatureList.ApplyCount = ginfo->gsub.count;
867       err = HB_GSUB_Apply_String (font_info->gsub, buf);
868       if (err != HB_Err_Ok && err != HB_Err_Not_Covered)
869         goto simple_copy;
870       if (out->used + buf->in_length > out->allocated)
871         return -2;
872     }
873
874   if (ginfo->gpos.count > 0
875       && (font_info->gpos || load_gpos (font_info) == HB_Err_Ok))
876     {
877       if (! apply_saved)
878         {
879           apply_order_save = font_info->gsub->FeatureList.ApplyOrder;
880           apply_count_save = font_info->gsub->FeatureList.ApplyCount;
881           apply_saved = 1;
882         }
883       font_info->gpos->FeatureList.ApplyOrder = ginfo->gpos.indices;
884       font_info->gpos->FeatureList.ApplyCount = ginfo->gpos.count;
885       err = HB_GPOS_Apply_String (&font_info->hb_font, font_info->gpos,
886                                   FT_LOAD_DEFAULT, buf, FALSE, FALSE);
887       if (err == HB_Err_Ok)
888         gpos_applied = 1;
889     }
890
891   if (apply_saved)
892     {
893       font_info->gsub->FeatureList.ApplyOrder = apply_order_save;
894       font_info->gsub->FeatureList.ApplyCount = apply_count_save;
895     }
896
897   gidx = out->used;
898
899   for (i = 0; i < buf->in_length; i++)
900     {
901       HB_GlyphItem hg = buf->in_string + i;
902       HB_Position pos = buf->positions + i;
903       MFLTGlyph *g;
904
905       out->glyphs[out->used] = in->glyphs[hg->cluster];
906       g = out->glyphs + out->used++;
907       if (g->code != hg->gindex)
908         g->c = 0, g->code = hg->gindex;
909       adjustment[i].set = gpos_applied;
910       if (gpos_applied)
911         {
912           adjustment[i].xadv = pos->x_advance;
913           adjustment[i].yadv = pos->y_advance;
914           adjustment[i].xoff = pos->x_pos;
915           adjustment[i].yoff = - pos->y_pos;
916           adjustment[i].back = pos->back;
917           adjustment[i].advance_is_absolute = pos->new_advance;
918         }
919     }
920   return to;
921
922  simple_copy:
923   if (buf)
924     hb_buffer_free (buf);
925   for (i = 0; i < len; i++)
926     out->glyphs[out->used++] = in->glyphs[from + i];
927   return to;
928 }
929
930 MFLTFont *
931 open_font (char *fontname, char **err)
932 {
933   FT_Face face = new_face (fontname, err);
934   FontInfo *font_info;
935
936   if (! face)
937     return NULL;
938   font_info = calloc (1, sizeof (FontInfo));
939   font_info->font.get_glyph_id = get_glyph_id;
940   font_info->font.get_metric = get_metric;
941   font_info->font.drive_otf = drive_otf;
942   font_info->face = face;
943   font_info->hb_font.klass = &hb_fontClass;
944   font_info->hb_font.faceData = face;
945   font_info->hb_font.userData = NULL;
946   font_info->hb_font.x_ppem = face->size->metrics.x_ppem;
947   font_info->hb_font.x_scale = face->size->metrics.x_scale;
948   font_info->hb_font.y_scale = face->size->metrics.y_scale;
949   font_info->hb_font.y_ppem = face->size->metrics.y_ppem;
950   font_info->otf_spec_cache = mplist ();
951   return ((MFLTFont *) font_info);
952 }
953
954 void
955 close_font (MFLTFont *font)
956 {
957   FontInfo *font_info = (FontInfo *) font;
958   MPlist *p;
959
960   if (font_info->gdef)
961     {
962       HB_Done_GDEF_Table (font_info->gdef);
963       free (font_info->gdef_stream.base);
964     }
965   if (font_info->gsub)
966     HB_Done_GSUB_Table (font_info->gsub);
967   if (font_info->gpos)
968     HB_Done_GPOS_Table (font_info->gpos);
969   FT_Done_Face ((FT_Face) (font_info->hb_font.faceData));
970   for (p = font_info->otf_spec_cache; mplist_key (p) != Mnil;
971        p = mplist_next (p))
972     {
973       GsubGposInfo *ginfo = mplist_value (p);
974
975       if (ginfo->gsub.count > 0)
976         free (ginfo->gsub.indices);
977       if (ginfo->gpos.count > 0)
978         free (ginfo->gpos.indices);
979     }
980   m17n_object_unref (font_info->otf_spec_cache);
981   free (font_info);
982 }
983
984 #endif
985 #endif
986
987 int
988 main (int argc, char **argv)
989 {
990   char *font_name, *flt_name;
991   char *err;
992   MText *mt;
993   MFLTFont *font;
994   int len, i, j, k;
995
996   if (argc < 3)
997     {
998       fprintf (stderr, "Usage: flt FONT-NAME FLT-NAME < TEXT-FILE\n");
999       exit (1);
1000     }
1001
1002   font_name = argv[1];
1003   flt_name = argv[2];
1004
1005   FT_Init_FreeType (&ft_library);
1006   M17N_INIT ();
1007   font = open_font (font_name, &err);
1008   if (! font)
1009     {
1010       fprintf (stderr, "Font error: %s: %s\n", argv[1], err);
1011       exit (1);
1012     }
1013
1014   mt = mconv_decode_stream (msymbol ("utf-8"), stdin);
1015   len = mtext_len (mt);
1016   for (i = 0, j = mtext_character (mt, i, len, '\n'); i < len;
1017        i = j + 1, j = mtext_character (mt, i, len, '\n'))
1018     {
1019       if (j < 0)
1020         j = len;
1021       if (flt (mt, i, j, font, flt_name) < 0)
1022         {
1023           fprintf (stderr, "Error in FLT processing.\n");
1024           exit (1);
1025         }
1026     }
1027   m17n_object_unref (mt);
1028   close_font (font);
1029   M17N_FINI ();
1030   return 0;
1031 }