(ft_find_metric): Call FT_Load_Glyph with
[m17n/m17n-lib.git] / src / font-ft.c
1 /* font-ft.c -- FreeType interface sub-module.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <ctype.h>
33
34 #include "m17n-gui.h"
35 #include "m17n-misc.h"
36 #include "internal.h"
37 #include "plist.h"
38 #include "symbol.h"
39 #include "internal-gui.h"
40 #include "font.h"
41 #include "face.h"
42
43 #ifdef HAVE_FREETYPE
44
45 #include <freetype/ftbdf.h>
46
47 #ifdef HAVE_FONTCONFIG
48 #include <fontconfig/fontconfig.h>
49
50 int fontconfig_initialized = 0;
51 FcConfig *fc_config;
52 #endif  /* not HAVE_FONTCONFIG */
53
54 static MSymbol Municode_bmp, Municode_full, Miso10646_1, Miso8859_1;
55
56 static FT_Library ft_library;
57
58 typedef struct
59 {
60   MSymbol ft_style;
61   MSymbol weight, style, stretch;
62 } MFTtoProp;
63
64 static int ft_to_prop_size;
65 static MFTtoProp *ft_to_prop;
66
67 /** List of FreeType fonts.  Keys are family names, values are plists
68     contains fonts of the corresponding family.  In the deeper plist,
69     keys are Mt, values are (MFTInfo *).  */
70 static MPlist *ft_font_list;
71
72 static int all_fonts_scaned;
73
74 /** Return 0 if NAME implies TrueType or OpenType fonts.  Othersize
75     return -1.  */
76
77 static int
78 check_otf_filename (const char *name)
79 {
80   int len = strlen (name);
81   const char *ext = name + (len - 4);
82
83   if (len < 5
84       || (memcmp (ext, ".ttf", 4)
85           && memcmp (ext, ".TTF", 4)
86           && memcmp (ext, ".otf", 4)
87           && memcmp (ext, ".OTF", 4)))
88     return -1;
89   return 0;
90 }
91
92 /** Setup members of FT_INFO from FT_FACE.  Return the family name.  */
93
94 static MSymbol
95 set_font_info (FT_Face ft_face, MFTInfo *ft_info, MSymbol family)
96 {
97   MFont *font = &ft_info->font;
98   MSymbol style;
99   int len;
100   char *buf, *p;
101   MPlist *charmap_list;
102   int unicode_bmp = -1, unicode_full = -1, unicode = -1;
103   int i;
104
105   MFONT_INIT (font);
106
107   if (family == Mnil)
108     {
109       len = strlen (ft_face->family_name) + 1;
110       buf = (char *) alloca (len);
111       memcpy (buf, ft_face->family_name, len);
112       for (p = buf; *p; p++)
113         if (*p >= 'A' && *p <= 'Z')
114           *p += 'a' - 'A';
115       family = msymbol (buf);
116     }
117   mfont__set_property (font, MFONT_FAMILY, family);
118
119   if (ft_face->style_name)
120     {
121       len = strlen (ft_face->style_name) + 1;
122       buf = (char *) alloca (len);
123       memcpy (buf, ft_face->style_name, len);
124       for (p = buf; *p; p++)
125         if (*p >= 'A' && *p <= 'Z')
126           *p += 'a' - 'A';
127       style = msymbol (buf);
128       for (i = 0; i < ft_to_prop_size; i++)
129         if (ft_to_prop[i].ft_style == style)
130           {
131             mfont__set_property (font, MFONT_WEIGHT, ft_to_prop[i].weight);
132             mfont__set_property (font, MFONT_STYLE, ft_to_prop[i].style);
133             mfont__set_property (font, MFONT_STRETCH, ft_to_prop[i].stretch);
134             break;
135           }
136     }
137   else
138     i = ft_to_prop_size;
139
140   if (i == ft_to_prop_size)
141     {
142       mfont__set_property (font, MFONT_WEIGHT, msymbol ("medium"));
143       mfont__set_property (font, MFONT_STYLE, msymbol ("r"));
144       mfont__set_property (font, MFONT_STRETCH, msymbol ("normal"));
145     }
146
147   mfont__set_property (font, MFONT_ADSTYLE, msymbol (""));
148
149   charmap_list = mplist ();
150   mplist_add (charmap_list, Mt, (void *) -1);
151   for (i = 0; i < ft_face->num_charmaps; i++)
152     {
153       char registry_buf[16];
154       MSymbol registry;
155
156       sprintf (registry_buf, "%d-%d",
157                ft_face->charmaps[i]->platform_id,
158                ft_face->charmaps[i]->encoding_id);
159       registry = msymbol (registry_buf);
160       mplist_add (charmap_list, registry, (void *) i);
161       
162       if (ft_face->charmaps[i]->platform_id == 0)
163         {
164           if (ft_face->charmaps[i]->encoding_id == 3)
165             unicode_bmp = i;
166           else if (ft_face->charmaps[i]->encoding_id == 4)
167             unicode_full = i;
168         }
169       else if (ft_face->charmaps[i]->platform_id == 3)
170         {
171           if (ft_face->charmaps[i]->encoding_id == 1)
172             unicode_bmp = i;
173           else if (ft_face->charmaps[i]->encoding_id == 10)
174             unicode_full = i;
175         }
176       else if (ft_face->charmaps[i]->platform_id == 1
177                && ft_face->charmaps[i]->encoding_id == 0)
178         mplist_add (charmap_list, msymbol ("apple-roman"), (void *) i);
179     }
180   if (unicode_full >= 0)
181     {
182       mplist_add (charmap_list, Municode_full, (void *) unicode_full);
183       mplist_add (charmap_list, Municode_bmp, (void *) unicode_full);
184       mplist_add (charmap_list, Miso10646_1, (void *) unicode_full);
185       unicode = unicode_full;
186     }
187   else if (unicode_bmp >= 0)
188     {
189       mplist_add (charmap_list, Municode_bmp, (void *) unicode_bmp);
190       mplist_add (charmap_list, Miso10646_1, (void *) unicode_bmp);
191       unicode = unicode_bmp;
192     }
193   if (unicode >= 0)
194     {
195       FT_Set_Charmap (ft_face, ft_face->charmaps[unicode]);
196       for (i = 255; i >= 32; i--)
197         {
198           if (i == 160)
199             i = 126;
200           if (FT_Get_Char_Index (ft_face, (FT_ULong) i) == 0)
201             break;
202         }
203       if (i == 31)
204         mplist_add (charmap_list, Miso8859_1, (void *) unicode);
205     }
206
207   ft_info->charmap_list = charmap_list;
208
209   if (! FT_IS_SCALABLE (ft_face))
210     {
211       BDF_PropertyRec prop;
212       
213       FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop);
214       font->property[MFONT_SIZE] = prop.u.integer * 10;
215       FT_Get_BDF_Property (ft_face, "RESOLUTION_Y", &prop);
216       font->property[MFONT_RESY] = prop.u.integer;
217     }
218
219   return family;
220 }
221
222
223 static void
224 close_ft (void *object)
225 {
226   MFTInfo *ft_info = object;
227
228   if (ft_info->ft_face)
229     {
230       if (ft_info->extra_info)
231         M17N_OBJECT_UNREF (ft_info->extra_info);
232       FT_Done_Face (ft_info->ft_face);
233 #ifdef HAVE_OTF
234       if (ft_info->otf)
235         OTF_close (ft_info->otf);
236 #endif /* HAVE_OTF */
237     }
238   free (ft_info->filename);
239   M17N_OBJECT_UNREF (ft_info->charmap_list);
240   free (ft_info);
241 }
242
243 static void
244 add_font_info (char *filename, MSymbol family)
245 {
246   FT_Face ft_face;
247   BDF_PropertyRec prop;
248   MFTInfo *ft_info = NULL;
249
250   if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0)
251     {
252       if (FT_IS_SCALABLE (ft_face)
253           || FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0)
254         {
255           MSymbol fam;
256           MPlist *plist;
257
258           M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
259           ft_info->filename = strdup (filename);
260           ft_info->otf_flag = check_otf_filename (filename);
261           fam = set_font_info (ft_face, ft_info, family);
262           plist = mplist_get (ft_font_list, fam);
263           if (! plist)
264             {
265               plist = mplist ();
266               mplist_add (ft_font_list, fam, plist);
267             }
268           mplist_add (plist, fam, ft_info);
269         }
270       FT_Done_Face (ft_face);
271     }
272 }
273
274 #ifdef HAVE_FONTCONFIG
275
276 static void
277 fc_list (MSymbol family)
278 {
279   FcPattern *pattern;
280   FcObjectSet *os;
281   FcFontSet *fs;
282   int i;
283
284   if (! fc_config)
285     {
286       char *pathname;
287       struct stat buf;
288       MPlist *plist;
289
290       FcInit ();
291       fc_config = FcConfigGetCurrent ();
292       MPLIST_DO (plist, mfont_freetype_path)
293         if (MPLIST_STRING_P (plist)
294             && (pathname = MPLIST_STRING (plist))
295             && stat (pathname, &buf) == 0)
296           FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
297     }
298
299   pattern = FcPatternCreate ();
300   if (family)
301     FcPatternAddString (pattern, FC_FAMILY,
302                         (FcChar8 *) (msymbol_name (family)));
303   os = FcObjectSetBuild (FC_FILE, NULL);
304   fs = FcFontList (fc_config, pattern, os);
305   if (fs)
306     {
307       char *filename;
308
309       for (i = 0; i < fs->nfont; i++)
310         {
311           FcPatternGetString (fs->fonts[i], FC_FILE, 0, (FcChar8 **) &filename);
312           add_font_info (filename, family);
313         }
314       FcFontSetDestroy (fs);
315     }
316   FcObjectSetDestroy (os);
317   FcPatternDestroy (pattern);
318 }
319
320 #else  /* not HAVE_FONTCONFIG */
321
322 static void
323 ft_list ()
324 {
325   MPlist *plist;
326   struct stat buf;
327   char *pathname;
328
329   MPLIST_DO (plist, mfont_freetype_path)
330     if (MPLIST_STRING_P (plist)
331         && (pathname = MPLIST_STRING (plist))
332         && stat (pathname, &buf) == 0)
333       {
334         if (S_ISREG (buf.st_mode))
335           add_font_info (pathname, Mnil);
336         else if (S_ISDIR (buf.st_mode))
337           {
338             int len = strlen (pathname);
339             char path[PATH_MAX];
340             DIR *dir = opendir (pathname);
341             struct dirent *dp;
342
343             if (dir)
344               {
345                 strcpy (path, pathname);
346                 strcpy (path + len, "/");
347                 len++;
348                 while ((dp = readdir (dir)) != NULL)
349                   {
350                     strcpy (path + len, dp->d_name);
351                     add_font_info (path, Mnil);
352                   }
353                 closedir (dir);
354               }
355           }
356       }
357 }
358
359 #endif  /* not HAVE_FONTCONFIG */
360
361 /* The FreeType font driver function SELECT.  */
362
363 static MRealizedFont *
364 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
365 {
366   MPlist *plist, *pl;
367   MFTInfo *best_font;
368   int best_score;
369   MRealizedFont *rfont;
370   MSymbol family, registry;
371
372   best_font = NULL;
373   best_score = 0;
374   family = FONT_PROPERTY (spec, MFONT_FAMILY);
375   if (family == Mnil)
376     family = FONT_PROPERTY (request, MFONT_FAMILY);
377   registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
378   if (registry == Mnil)
379     registry = Mt;
380
381   if (! ft_font_list)
382     ft_font_list = mplist ();
383 #ifdef HAVE_FONTCONFIG
384   if (family != Mnil)
385     {
386       plist = mplist_get (ft_font_list, family);
387       if (! plist)
388         {
389           fc_list (family);
390           plist = mplist_get (ft_font_list, family);
391           if (! plist)
392             {
393               mplist_add (ft_font_list, family, plist = mplist ());
394               return NULL;
395             }
396         }
397     }
398   else
399     {
400       if (! all_fonts_scaned)
401         {
402           fc_list (Mnil);
403           all_fonts_scaned = 1;
404         }
405     }
406 #else  /* not HAVE_FONTCONFIG */
407   if (! all_fonts_scaned)
408     {
409       ft_list ();
410       all_fonts_scaned = 1;
411     }
412   if (family != Mnil)
413     {
414       plist = mplist_get (ft_font_list, family);
415       if (! plist)
416         return NULL;
417     }
418 #endif  /* not HAVE_FONTCONFIG */
419
420   if (family == Mnil)
421     plist = MPLIST_VAL (ft_font_list);
422
423  retry:
424   MPLIST_DO (pl, plist)
425     {
426       MFTInfo *ft_info = MPLIST_VAL (pl);
427       int score;
428
429       if (! mplist_find_by_key (ft_info->charmap_list, registry))
430         continue;
431       /* We always ignore FOUNDRY.  */
432       ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
433       score = mfont__score (&ft_info->font, spec, request, limited_size);
434       if (score >= 0
435           && (! best_font
436               || best_score > score))
437         {
438           best_font = ft_info;
439           best_score = score;
440           if (score == 0)
441             break;
442         }
443     }
444   if (family == Mnil)
445     {
446       plist = MPLIST_NEXT (plist);
447       if (! MPLIST_TAIL_P (plist))
448         goto retry;
449     }
450   if (! best_font)
451     return NULL;
452
453   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
454   rfont->frame = frame;
455   rfont->spec = *spec;
456   rfont->request = *request;
457   rfont->font = best_font->font;
458   rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
459   rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
460   rfont->score = best_score;
461   rfont->info = best_font;
462   M17N_OBJECT_REF (best_font);
463   return rfont;
464 }
465
466
467 /* The FreeType font driver function OPEN.  */
468
469 static int
470 ft_open (MRealizedFont *rfont)
471 {
472   MFTInfo *base = rfont->info, *ft_info;
473   MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
474   int mdebug_mask = MDEBUG_FONT;
475   int size;
476
477   M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
478   ft_info->font = base->font;
479   ft_info->filename = strdup (base->filename);
480   ft_info->otf_flag = base->otf_flag;
481   ft_info->charmap_list = base->charmap_list;
482   M17N_OBJECT_REF (ft_info->charmap_list);
483   M17N_OBJECT_UNREF (base);
484   rfont->info = ft_info;
485
486   rfont->status = -1;
487   ft_info->ft_face = NULL;
488   if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
489     goto err;
490   if (registry == Mnil)
491     registry = Mt;
492   ft_info->charmap_index
493     = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
494   if (ft_info->charmap_index >= 0
495       && FT_Set_Charmap (ft_info->ft_face, 
496                          ft_info->ft_face->charmaps[ft_info->charmap_index]))
497     goto err;
498   size = rfont->font.property[MFONT_SIZE] / 10;
499   if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
500     goto err;
501
502   MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
503   rfont->status = 1;
504   rfont->ascent = ft_info->ft_face->ascender >> 6;
505   rfont->descent = - (ft_info->ft_face->descender >> 6);
506   return 0;
507
508  err:
509   MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
510   if (ft_info->ft_face)
511     FT_Done_Face (ft_info->ft_face);
512   M17N_OBJECT_UNREF (ft_info->charmap_list);
513   free (ft_info->filename);
514   free (ft_info);
515   rfont->info = NULL;
516   return -1;
517 }
518
519 /* The FreeType font driver function FIND_METRIC.  */
520
521 static void
522 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
523                 int from, int to)
524 {
525   MFTInfo *ft_info = (MFTInfo *) rfont->info;
526   FT_Face ft_face = ft_info->ft_face;
527   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
528
529   for (; g != gend; g++)
530     {
531       if (g->code == MCHAR_INVALID_CODE)
532         {
533           if (FT_IS_SCALABLE (ft_face))
534             {
535               unsigned unitsPerEm = ft_face->units_per_EM;
536               int size = rfont->font.property[MFONT_SIZE] / 10;
537
538               g->lbearing = 0;
539               g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
540               g->width = ft_face->max_advance_width * size / unitsPerEm;
541               g->ascent = ft_face->ascender * size / unitsPerEm;
542               g->descent = (- ft_face->descender) * size / unitsPerEm;
543             }
544           else
545             {
546               BDF_PropertyRec prop;
547
548               g->lbearing = 0;
549               g->rbearing = g->width = ft_face->available_sizes->width;
550               if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
551                 {
552                   g->ascent = prop.u.integer;
553                   FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
554                   g->descent = prop.u.integer;
555                 }
556               else
557                 {
558                   g->ascent = ft_face->available_sizes->height;
559                   g->descent = 0;
560                 }
561             }
562         }
563       else
564         {
565           FT_Glyph_Metrics *metrics;
566
567           FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
568           metrics = &ft_face->glyph->metrics;
569           g->lbearing = (metrics->horiBearingX >> 6);
570           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
571           g->width = metrics->horiAdvance >> 6;
572           g->ascent = metrics->horiBearingY >> 6;
573           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
574         }
575     }
576 }
577
578 /* The FreeType font driver function ENCODE_CHAR.  */
579
580 static unsigned
581 ft_encode_char (MRealizedFont *rfont, unsigned code)
582 {
583   MFTInfo *ft_info;
584
585   if (rfont->status == 0)
586     {
587       if ((rfont->driver->open) (rfont) < 0)
588         return -1;
589     }
590   ft_info = (MFTInfo *) rfont->info;
591   code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
592   if (! code)
593     return MCHAR_INVALID_CODE;
594   return (code);
595
596 }
597
598 /* The FreeType font driver function RENDER.  */
599
600 #define NUM_POINTS 0x1000
601
602 typedef struct {
603   MDrawPoint points[NUM_POINTS];
604   MDrawPoint *p;
605 } MPointTable;
606
607 static void
608 ft_render (MDrawWindow win, int x, int y,
609            MGlyphString *gstring, MGlyph *from, MGlyph *to,
610            int reverse, MDrawRegion region)
611 {
612   MFTInfo *ft_info;
613   FT_Face ft_face;
614   MRealizedFace *rface = from->rface;
615   MFrame *frame = rface->frame;
616   FT_Int32 load_flags = FT_LOAD_RENDER;
617   MGlyph *g;
618   int i, j;
619   MPointTable point_table[8];
620
621   if (from == to)
622     return;
623
624   /* It is assured that the all glyphs in the current range use the
625      same realized face.  */
626   ft_info = (MFTInfo *) rface->rfont->info;
627   ft_face = ft_info->ft_face;
628
629   if (! gstring->anti_alias)
630     {
631 #ifdef FT_LOAD_TARGET_MONO
632       load_flags |= FT_LOAD_TARGET_MONO;
633 #else
634       load_flags |= FT_LOAD_MONOCHROME;
635 #endif
636     }
637
638   for (i = 0; i < 8; i++)
639     point_table[i].p = point_table[i].points;
640
641   for (g = from; g < to; x += g++->width)
642     {
643       unsigned char *bmp;
644       int intensity;
645       MPointTable *ptable;
646       int xoff, yoff;
647       int width, pitch;
648
649       FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
650       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
651       bmp = ft_face->glyph->bitmap.buffer;
652       width = ft_face->glyph->bitmap.width;
653       pitch = ft_face->glyph->bitmap.pitch;
654       if (! gstring->anti_alias)
655         pitch *= 8;
656       if (width > pitch)
657         width = pitch;
658
659       if (gstring->anti_alias)
660         for (i = 0; i < ft_face->glyph->bitmap.rows;
661              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
662           {
663             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
664             for (j = 0; j < width; j++, xoff++)
665               {
666                 intensity = bmp[j] >> 5;
667                 if (intensity)
668                   {
669                     ptable = point_table + intensity;
670                     ptable->p->x = xoff;
671                     ptable->p->y = yoff;
672                     ptable->p++;
673                     if (ptable->p - ptable->points == NUM_POINTS)
674                       {
675                         (*frame->driver->draw_points)
676                           (frame, win, rface,
677                            reverse ? 7 - intensity : intensity,
678                            ptable->points, NUM_POINTS, region);
679                         ptable->p = ptable->points;
680                       }
681                   }
682               }
683           }
684       else
685         for (i = 0; i < ft_face->glyph->bitmap.rows;
686              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
687           {
688             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
689             for (j = 0; j < width; j++, xoff++)
690               {
691                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
692                 if (intensity)
693                   {
694                     ptable = point_table;
695                     ptable->p->x = xoff;
696                     ptable->p->y = yoff;
697                     ptable->p++;
698                     if (ptable->p - ptable->points == NUM_POINTS)
699                       {
700                         (*frame->driver->draw_points) (frame, win, rface,
701                                            reverse ? 0 : 7,
702                                            ptable->points, NUM_POINTS, region);
703                         ptable->p = ptable->points;
704                       }             
705                   }
706               }
707         }
708     }
709
710   if (gstring->anti_alias)
711     {
712       for (i = 1; i < 8; i++)
713         if (point_table[i].p != point_table[i].points)
714           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
715                              point_table[i].points,
716                              point_table[i].p - point_table[i].points, region);
717     }
718   else
719     {
720       if (point_table[0].p != point_table[0].points)
721         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
722                            point_table[0].points,
723                            point_table[0].p - point_table[0].points, region);
724     }
725 }
726
727 \f
728 /* Internal API */
729
730 MFontDriver mfont__ft_driver =
731   { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render };
732
733 int
734 mfont__ft_init ()
735 {
736   struct {
737     char *ft_style;
738     char *weight, *style, *stretch;
739   } ft_to_prop_name[] =
740     { { "regular", "medium", "r", "normal" },
741       { "medium", "medium", "r", "normal" },
742       { "normal", "medium", "r", "normal" },
743       { "italic", "medium", "i", "normal" },
744       { "bold", "bold", "r", "normal" },
745       { "bolditalic", "bold", "i", "normal" },
746       { "bold italic", "bold", "i", "normal" },
747       { "narrow", "medium", "r", "condensed" },
748       { "narrow italic", "medium", "i", "condensed" },
749       { "narrow bold", "bold", "r", "condensed" },
750       { "narrow bold italic", "bold", "i", "condensed" },
751       { "black", "black", "r", "normal" },
752       { "black italic", "black", "i", "normal" },
753       { "oblique", "medium", "o", "normal" },
754       { "boldoblique", "bold", "o", "normal" },
755       { "bold oblique", "bold", "o", "normal" } };
756   int i;
757
758   if (FT_Init_FreeType (&ft_library) != 0)
759     MERROR (MERROR_FONT_FT, -1);
760
761   ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
762   MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
763   for (i = 0; i < ft_to_prop_size; i++)
764     {
765       ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
766       ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
767       ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
768       ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
769     }
770
771   Municode_bmp = msymbol ("unicode-bmp");
772   Municode_full = msymbol ("unicode-full");
773   Miso10646_1 = msymbol ("iso10646-1");
774   Miso8859_1 = msymbol ("iso8859-1");
775
776   return 0;
777 }
778
779 void
780 mfont__ft_fini ()
781 {
782   MPlist *plist, *p;
783
784   if (ft_font_list)
785     {
786       MPLIST_DO (plist, ft_font_list)
787         {
788           MPLIST_DO (p, MPLIST_VAL (plist))
789             {
790               MFTInfo *ft_info = MPLIST_VAL (p);
791
792               M17N_OBJECT_UNREF (ft_info);
793             }
794           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
795         }
796       M17N_OBJECT_UNREF (ft_font_list);
797       ft_font_list = NULL;
798     }
799   free (ft_to_prop);
800   FT_Done_FreeType (ft_library);
801   all_fonts_scaned = 0;
802 }
803
804
805 #ifdef HAVE_FONTCONFIG
806 int
807 mfont__ft_parse_name (char *name, MFont *font)
808 {
809   FcPattern *pat = FcNameParse ((FcChar8 *) name);
810   FcResult result;
811   FcChar8 *str;
812   double size;
813   
814   if (! pat)
815     return -1;
816   if ((result = FcPatternGetString (pat, FC_FOUNDRY, 0, &str)) == FcResultMatch)
817     mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
818   if ((result = FcPatternGetString (pat, FC_FAMILY, 0, &str)) == FcResultMatch)
819     mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
820   if ((result = FcPatternGetString (pat, FC_STYLE, 0, &str)) == FcResultMatch)
821     {
822       MSymbol style = msymbol ((char *) str);
823       int i;
824
825       for (i = 0; i < ft_to_prop_size; i++)
826         if (ft_to_prop[i].ft_style == style)
827           {
828             mfont__set_property (font, MFONT_WEIGHT, ft_to_prop[i].weight);
829             mfont__set_property (font, MFONT_STYLE, ft_to_prop[i].style);
830             mfont__set_property (font, MFONT_STRETCH, ft_to_prop[i].stretch);
831             break;
832           }
833     }
834   if ((result = FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size))
835       == FcResultMatch)
836     font->property[MFONT_SIZE] = size * 10;
837   FcPatternDestroy (pat);
838   return 0;
839 }
840
841 char *
842 mfont__ft_unparse_name (MFont *font)
843 {
844   FcPattern *pat = FcPatternCreate ();
845   MSymbol sym, weight, style, stretch;
846   char *name;
847   int i;
848
849   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
850     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
851   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
852     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
853   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) == Mnil)
854     weight = msymbol ("medium");
855   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) == Mnil)
856     style = msymbol ("r");
857   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) == Mnil)
858     stretch = msymbol ("normal");
859   for (i = 0; i < ft_to_prop_size; i++)
860     if (ft_to_prop[i].weight == weight
861         && ft_to_prop[i].style == style
862         && ft_to_prop[i].stretch == stretch)
863       FcPatternAddString (pat, FC_STYLE,
864                           (FcChar8 *) MSYMBOL_NAME (ft_to_prop[i].ft_style));
865   name = (char *) FcNameUnparse (pat);
866   FcPatternDestroy (pat);
867   return name;
868 }
869 #endif  /* HAVE_FONTCONFIG */
870
871 \f
872 #ifdef HAVE_OTF
873
874 #define DEVICE_DELTA(table, size)                               \
875   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
876    ? (table).DeltaValue[(size) >= (table).StartSize]            \
877    : 0)
878
879 void
880 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
881                unsigned code, int size, int *x, int *y)
882 {
883   if (anchor->AnchorFormat == 2)
884     {
885       FT_Outline *outline;
886       int ap = anchor->f.f1.AnchorPoint;
887
888       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
889       outline = &ft_face->glyph->outline;
890       if (ap < outline->n_points)
891         {
892           *x = outline->points[ap].x;
893           *y = outline->points[ap].y;
894         }
895     }
896   else if (anchor->AnchorFormat == 3)
897     {
898       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
899       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
900     }
901 }
902
903 int
904 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
905                      MSymbol script, MSymbol langsys,
906                      MSymbol gsub_features, MSymbol gpos_features)
907 {
908   int len = to - from;
909   MGlyph *g = MGLYPH (from);
910   int i, gidx;
911   MRealizedFont *rfont;
912   MFTInfo *ft_info;
913   OTF *otf;
914   OTF_GlyphString otf_gstring;
915   OTF_Glyph *otfg;
916   char *script_name, *language_name;
917   char *gsub_feature_names, *gpos_feature_names;
918   int need_cmap;
919
920   if (len == 0)
921     return from;
922
923   rfont = g->rface->rfont;
924   ft_info = rfont->info;
925   if (ft_info->otf_flag < 0)
926     goto simple_copy;
927   otf = ft_info->otf;
928   if (! otf)
929     {
930       otf = OTF_open (ft_info->filename);
931       if (otf && OTF_get_table (otf, "head") < 0)
932         {
933           OTF_close (otf);
934           otf = NULL;
935         }
936       if (! otf)
937         {
938           ft_info->otf_flag = -1;
939           goto simple_copy;
940         }
941       ft_info->otf = otf;
942     }
943
944   if (script != Mnil)
945     script_name = msymbol_name (script);
946   else
947     script_name = NULL;
948   if (langsys != Mnil)
949     language_name = msymbol_name (langsys);
950   else
951     language_name = NULL;
952   gsub_feature_names
953     = (gsub_features == Mt ? "*"
954        : gsub_features == Mnil ? NULL
955        : msymbol_name (gsub_features));
956   if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
957     gsub_feature_names = NULL;
958   gpos_feature_names
959     = (gpos_features == Mt ? "*"
960        : gpos_features == Mnil ? NULL
961        : msymbol_name (gpos_features));
962   if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
963     gpos_feature_names = NULL;
964
965   otf_gstring.size = otf_gstring.used = len;
966   otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
967   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
968   for (i = 0, need_cmap = 0; i < len; i++)
969     {
970       if (gstring->glyphs[from + i].otf_encoded)
971         {
972           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
973           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
974         }
975       else
976         {
977           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
978           need_cmap++;
979         }
980     }
981   if (need_cmap
982       && OTF_drive_cmap (otf, &otf_gstring) < 0)
983     goto simple_copy;
984
985   OTF_drive_gdef (otf, &otf_gstring);
986   gidx = gstring->used;
987
988   if (gsub_feature_names)
989     {
990       if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
991                           gsub_feature_names) < 0)
992         goto simple_copy;
993       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
994         {
995           MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
996
997           temp.c = otfg->c;
998           temp.combining_code = 0;
999           if (otfg->glyph_id)
1000             {
1001               temp.code = otfg->glyph_id;
1002               temp.otf_encoded = 1;
1003             }
1004           else
1005             {
1006               temp.code = temp.c;
1007               temp.otf_encoded = 0;
1008             }
1009           temp.to = MGLYPH (from + otfg->f.index.to)->to;
1010           MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1011         }
1012     }
1013   else
1014     for (i = 0; i < len; i++)
1015       {
1016         MGlyph temp = gstring->glyphs[from + i];
1017
1018         if (otf_gstring.glyphs[i].glyph_id)
1019           {
1020             temp.code = otf_gstring.glyphs[i].glyph_id;
1021             temp.otf_encoded = 1;
1022           }
1023         MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1024       }
1025
1026   ft_find_metric (rfont, gstring, gidx, gstring->used);
1027
1028   if (gpos_feature_names)
1029     {
1030       int u;
1031       int size10, size;
1032       MGlyph *base = NULL, *mark = NULL;
1033
1034       if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1035                           gpos_feature_names) < 0)
1036         return to;
1037
1038       u = otf->head->unitsPerEm;
1039       size10 = rfont->font.property[MFONT_SIZE];
1040       size = size10 / 10;
1041
1042       for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1043            i < otf_gstring.used; i++, otfg++, g++)
1044         {
1045           MGlyph *prev;
1046
1047           if (! otfg->glyph_id)
1048             continue;
1049           switch (otfg->positioning_type)
1050             {
1051             case 0:
1052               break;
1053             case 1: case 2:
1054               {
1055                 int format = otfg->f.f1.format;
1056
1057                 if (format & OTF_XPlacement)
1058                   g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1059                 if (format & OTF_XPlaDevice)
1060                   g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1061                 if (format & OTF_YPlacement)
1062                   g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1063                 if (format & OTF_YPlaDevice)
1064                   g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1065                 if (format & OTF_XAdvance)
1066                   g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1067                 if (format & OTF_XAdvDevice)
1068                   g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1069               }
1070               break;
1071             case 3:
1072               /* Not yet supported.  */
1073               break;
1074             case 4: case 5:
1075               if (! base)
1076                 break;
1077               prev = base;
1078               goto label_adjust_anchor;
1079             default:            /* i.e. case 6 */
1080               if (! mark)
1081                 break;
1082               prev = mark;
1083
1084             label_adjust_anchor:
1085               {
1086                 int base_x, base_y, mark_x, mark_y;
1087
1088                 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1089                 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1090                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1091                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1092
1093                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1094                   adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1095                                  prev->code, size, &base_x, &base_y);
1096                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1097                   adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1098                                  g->code, size, &mark_x, &mark_y);
1099                 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1100                 g->yoff = prev->yoff + mark_y - base_y;
1101                 g->combining_code = MAKE_COMBINING_CODE_BY_CLASS (0);
1102               }
1103             }
1104           if (otfg->GlyphClass == OTF_GlyphClass0)
1105             base = mark = g;
1106           else if (otfg->GlyphClass == OTF_GlyphClassMark)
1107             mark = g;
1108           else
1109             base = g;
1110         }
1111     }
1112   return to;
1113
1114  simple_copy:
1115   ft_find_metric (rfont, gstring, from, to);
1116   for (i = 0; i < len; i++)
1117     {
1118       MGlyph temp = gstring->glyphs[from + i];
1119       MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1120     }
1121   return to;
1122 }
1123
1124
1125 int
1126 mfont__ft_decode_otf (MGlyph *g)
1127 {
1128   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1129   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1130
1131   return (c ? c : -1);
1132 }
1133
1134 #endif  /* HAVE_OTF */
1135
1136 #endif /* HAVE_FREETYPE */