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