6c4accaa8d26e41898db7cd95a566f959f8fa849
[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, FC_FOUNDRY, FC_FAMILY, FC_STYLE, FC_PIXEL_SIZE, NULL);
304   fs = FcFontList (fc_config, pattern, os);
305   if (fs)
306     {
307       for (i = 0; i < fs->nfont; i++)
308         {
309           char *filename;
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   FT_Int32 load_flags = FT_LOAD_RENDER;
529
530 #ifdef FT_LOAD_TARGET_MONO
531   load_flags |= FT_LOAD_TARGET_MONO;
532 #else
533   load_flags |= FT_LOAD_MONOCHROME;
534 #endif
535
536   for (; g != gend; g++)
537     {
538       if (g->code == MCHAR_INVALID_CODE)
539         {
540           if (FT_IS_SCALABLE (ft_face))
541             {
542               unsigned unitsPerEm = ft_face->units_per_EM;
543               int size = rfont->font.property[MFONT_SIZE] / 10;
544
545               g->lbearing = 0;
546               g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
547               g->width = ft_face->max_advance_width * size / unitsPerEm;
548               g->ascent = ft_face->ascender * size / unitsPerEm;
549               g->descent = (- ft_face->descender) * size / unitsPerEm;
550             }
551           else
552             {
553               BDF_PropertyRec prop;
554
555               g->lbearing = 0;
556               g->rbearing = g->width = ft_face->available_sizes->width;
557               if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
558                 {
559                   g->ascent = prop.u.integer;
560                   FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
561                   g->descent = prop.u.integer;
562                 }
563               else
564                 {
565                   g->ascent = ft_face->available_sizes->height;
566                   g->descent = 0;
567                 }
568             }
569         }
570       else
571         {
572           FT_Glyph_Metrics *metrics;
573           FT_UInt code;
574
575           if (g->otf_encoded)
576             code = g->code;
577           else
578             code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
579
580           FT_Load_Glyph (ft_face, code, FT_LOAD_RENDER);
581           metrics = &ft_face->glyph->metrics;
582           g->lbearing = (metrics->horiBearingX >> 6);
583           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
584           g->width = metrics->horiAdvance >> 6;
585           g->ascent = metrics->horiBearingY >> 6;
586           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
587         }
588     }
589 }
590
591 /* The FreeType font driver function ENCODE_CHAR.  */
592
593 static unsigned
594 ft_encode_char (MRealizedFont *rfont, int c, unsigned ignored)
595 {
596   MFTInfo *ft_info;
597   FT_UInt code;
598
599   if (rfont->status == 0)
600     {
601       if ((rfont->driver->open) (rfont) < 0)
602         return -1;
603     }
604   ft_info = (MFTInfo *) rfont->info;
605   code = FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) c);
606   if (! code)
607     return MCHAR_INVALID_CODE;
608   return ((unsigned) c);
609
610 }
611
612 /* The FreeType font driver function RENDER.  */
613
614 #define NUM_POINTS 0x1000
615
616 typedef struct {
617   MDrawPoint points[NUM_POINTS];
618   MDrawPoint *p;
619 } MPointTable;
620
621 static void
622 ft_render (MDrawWindow win, int x, int y,
623            MGlyphString *gstring, MGlyph *from, MGlyph *to,
624            int reverse, MDrawRegion region)
625 {
626   MFTInfo *ft_info;
627   FT_Face ft_face;
628   MRealizedFace *rface = from->rface;
629   MFrame *frame = rface->frame;
630   FT_Int32 load_flags = FT_LOAD_RENDER;
631   MGlyph *g;
632   int i, j;
633   MPointTable point_table[8];
634
635   if (from == to)
636     return;
637
638   /* It is assured that the all glyphs in the current range use the
639      same realized face.  */
640   ft_info = (MFTInfo *) rface->rfont->info;
641   ft_face = ft_info->ft_face;
642
643   if (! gstring->anti_alias)
644     {
645 #ifdef FT_LOAD_TARGET_MONO
646       load_flags |= FT_LOAD_TARGET_MONO;
647 #else
648       load_flags |= FT_LOAD_MONOCHROME;
649 #endif
650     }
651
652   for (i = 0; i < 8; i++)
653     point_table[i].p = point_table[i].points;
654
655   for (g = from; g < to; x += g++->width)
656     {
657       FT_UInt code;
658       unsigned char *bmp;
659       int intensity;
660       MPointTable *ptable;
661       int xoff, yoff;
662       int width, pitch;
663
664       if (g->otf_encoded)
665         code = g->code;
666       else
667         code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
668       FT_Load_Glyph (ft_face, code, load_flags);
669       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
670       bmp = ft_face->glyph->bitmap.buffer;
671       width = ft_face->glyph->bitmap.width;
672       pitch = ft_face->glyph->bitmap.pitch;
673       if (! gstring->anti_alias)
674         pitch *= 8;
675       if (width > pitch)
676         width = pitch;
677
678       if (gstring->anti_alias)
679         for (i = 0; i < ft_face->glyph->bitmap.rows;
680              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
681           {
682             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
683             for (j = 0; j < width; j++, xoff++)
684               {
685                 intensity = bmp[j] >> 5;
686                 if (intensity)
687                   {
688                     ptable = point_table + intensity;
689                     ptable->p->x = xoff;
690                     ptable->p->y = yoff;
691                     ptable->p++;
692                     if (ptable->p - ptable->points == NUM_POINTS)
693                       {
694                         (*frame->driver->draw_points)
695                           (frame, win, rface,
696                            reverse ? 7 - intensity : intensity,
697                            ptable->points, NUM_POINTS, region);
698                         ptable->p = ptable->points;
699                       }
700                   }
701               }
702           }
703       else
704         for (i = 0; i < ft_face->glyph->bitmap.rows;
705              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
706           {
707             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
708             for (j = 0; j < width; j++, xoff++)
709               {
710                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
711                 if (intensity)
712                   {
713                     ptable = point_table;
714                     ptable->p->x = xoff;
715                     ptable->p->y = yoff;
716                     ptable->p++;
717                     if (ptable->p - ptable->points == NUM_POINTS)
718                       {
719                         (*frame->driver->draw_points) (frame, win, rface,
720                                            reverse ? 0 : 7,
721                                            ptable->points, NUM_POINTS, region);
722                         ptable->p = ptable->points;
723                       }             
724                   }
725               }
726         }
727     }
728
729   if (gstring->anti_alias)
730     {
731       for (i = 1; i < 8; i++)
732         if (point_table[i].p != point_table[i].points)
733           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
734                              point_table[i].points,
735                              point_table[i].p - point_table[i].points, region);
736     }
737   else
738     {
739       if (point_table[0].p != point_table[0].points)
740         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
741                            point_table[0].points,
742                            point_table[0].p - point_table[0].points, region);
743     }
744 }
745
746 \f
747 /* Internal API */
748
749 MFontDriver mfont__ft_driver =
750   { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render };
751
752 int
753 mfont__ft_init ()
754 {
755   struct {
756     char *ft_style;
757     char *weight, *style, *stretch;
758   } ft_to_prop_name[] =
759     { { "regular", "medium", "r", "normal" },
760       { "italic", "medium", "i", "normal" },
761       { "bold", "bold", "r", "normal" },
762       { "bold italic", "bold", "i", "normal" },
763       { "narrow", "medium", "r", "condensed" },
764       { "narrow italic", "medium", "i", "condensed" },
765       { "narrow bold", "bold", "r", "condensed" },
766       { "narrow bold italic", "bold", "i", "condensed" },
767       { "black", "black", "r", "normal" },
768       { "black italic", "black", "i", "normal" },
769       { "oblique", "medium", "o", "normal" },
770       { "boldoblique", "bold", "o", "normal" } };
771   int i;
772
773   if (FT_Init_FreeType (&ft_library) != 0)
774     MERROR (MERROR_FONT_FT, -1);
775
776   ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
777   MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
778   for (i = 0; i < ft_to_prop_size; i++)
779     {
780       ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
781       ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
782       ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
783       ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
784     }
785
786   Municode_bmp = msymbol ("unicode-bmp");
787   Municode_full = msymbol ("unicode-full");
788   Miso10646_1 = msymbol ("iso10646-1");
789   Miso8859_1 = msymbol ("iso8859-1");
790
791   return 0;
792 }
793
794 void
795 mfont__ft_fini ()
796 {
797   MPlist *plist, *p;
798
799   if (ft_font_list)
800     {
801       MPLIST_DO (plist, ft_font_list)
802         {
803           MPLIST_DO (p, MPLIST_VAL (plist))
804             {
805               MFTInfo *ft_info = MPLIST_VAL (p);
806
807               M17N_OBJECT_UNREF (ft_info);
808             }
809           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
810         }
811       M17N_OBJECT_UNREF (ft_font_list);
812       ft_font_list = NULL;
813     }
814   free (ft_to_prop);
815   FT_Done_FreeType (ft_library);
816   all_fonts_scaned = 0;
817 }
818
819
820 #ifdef HAVE_FONTCONFIG
821 int
822 mfont__ft_parse_name (char *name, MFont *font)
823 {
824   FcPattern *pat = FcNameParse (name);
825   FcResult result;
826   FcChar8 *str;
827   double size;
828   
829   if (! pat)
830     return -1;
831   if ((result = FcPatternGetString (pat, FC_FOUNDRY, 0, &str)) == FcResultMatch)
832     mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
833   if ((result = FcPatternGetString (pat, FC_FAMILY, 0, &str)) == FcResultMatch)
834     mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
835   if ((result = FcPatternGetString (pat, FC_STYLE, 0, &str)) == FcResultMatch)
836     {
837       MSymbol style = msymbol ((char *) str);
838       int i;
839
840       for (i = 0; i < ft_to_prop_size; i++)
841         if (ft_to_prop[i].ft_style == style)
842           {
843             mfont__set_property (font, MFONT_WEIGHT, ft_to_prop[i].weight);
844             mfont__set_property (font, MFONT_STYLE, ft_to_prop[i].style);
845             mfont__set_property (font, MFONT_STRETCH, ft_to_prop[i].stretch);
846             break;
847           }
848     }
849   if ((result = FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size))
850       == FcResultMatch)
851     font->property[MFONT_SIZE] = size * 10;
852   FcPatternDestroy (pat);
853   return 0;
854 }
855
856 char *
857 mfont__ft_unparse_name (MFont *font)
858 {
859   FcPattern *pat = FcPatternCreate ();
860   MSymbol sym, weight, style, stretch;
861   char *name;
862   int i;
863
864   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
865     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
866   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
867     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
868   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) == Mnil)
869     weight = msymbol ("medium");
870   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) == Mnil)
871     style = msymbol ("r");
872   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) == Mnil)
873     stretch = msymbol ("normal");
874   for (i = 0; i < ft_to_prop_size; i++)
875     if (ft_to_prop[i].weight == weight
876         && ft_to_prop[i].style == style
877         && ft_to_prop[i].stretch == stretch)
878       FcPatternAddString (pat, FC_STYLE,
879                           (FcChar8 *) MSYMBOL_NAME (ft_to_prop[i].ft_style));
880   name = (char *) FcNameUnparse (pat);
881   FcPatternDestroy (pat);
882   return name;
883 }
884 #endif  /* HAVE_FONTCONFIG */
885
886 int
887 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
888                      MRealizedFont *rfont,
889                      MSymbol script, MSymbol langsys, 
890                      MSymbol gsub_features, MSymbol gpos_features)
891 {
892   int len = to - from;
893   MGlyph g;
894   int i;
895 #ifdef HAVE_OTF
896   MFTInfo *ft_info;
897   OTF *otf;
898   OTF_GlyphString otf_gstring;
899   OTF_Glyph *otfg;
900   char *script_name, *language_name;
901   char *gsub_feature_names, *gpos_feature_names;
902   int from_pos, to_pos;
903   int unitsPerEm;
904
905   if (len == 0)
906     return from;
907
908   ft_info = (MFTInfo *) rfont->info;
909   if (ft_info->otf_flag < 0)
910     goto simple_copy;
911   otf = ft_info->otf;
912   if (! otf && (otf = OTF_open (ft_info->filename)))
913     {
914       if (OTF_get_table (otf, "head") < 0
915           || (OTF_check_table (otf, "GSUB") < 0
916               && OTF_check_table (otf, "GPOS") < 0))
917         {
918           OTF_close (otf);
919           ft_info->otf_flag = -1;
920           ft_info->otf = NULL;
921           goto simple_copy;
922         }
923       ft_info->otf = otf;
924     }
925
926   script_name = msymbol_name (script);
927   language_name = langsys != Mnil ? msymbol_name (langsys) : NULL;
928   gsub_feature_names
929     = (gsub_features == Mt ? "*"
930        : gsub_features == Mnil ? NULL
931        : msymbol_name (gsub_features));
932   gpos_feature_names
933     = (gpos_features == Mt ? "*"
934        : gpos_features == Mnil ? NULL
935        : msymbol_name (gpos_features));
936
937   g = gstring->glyphs[from];
938   from_pos = g.pos;
939   to_pos = g.to;
940   for (i = from + 1; i < to; i++)
941     {
942       if (from_pos > gstring->glyphs[i].pos)
943         from_pos = gstring->glyphs[i].pos;
944       if (to_pos < gstring->glyphs[i].to)
945         to_pos = gstring->glyphs[i].to;
946     }
947
948   unitsPerEm = otf->head->unitsPerEm;
949   otf_gstring.size = otf_gstring.used = len;
950   otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
951   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
952   for (i = 0; i < len; i++)
953     {
954       if (gstring->glyphs[from + i].otf_encoded)
955         {
956           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
957           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
958         }
959       else
960         {
961           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
962         }
963     }
964       
965   if (OTF_drive_tables (otf, &otf_gstring, script_name, language_name,
966                         gsub_feature_names, gpos_feature_names) < 0)
967     goto simple_copy;
968   g.pos = from_pos;
969   g.to = to_pos;
970   for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
971     {
972       g.combining_code = 0;
973       g.c = otfg->c;
974       if (otfg->glyph_id)
975         {
976           g.code = otfg->glyph_id;
977           switch (otfg->positioning_type)
978             {
979             case 1: case 2:
980               {
981                 int off_x = 128, off_y = 128;
982
983                 if (otfg->f.f1.format & OTF_XPlacement)
984                   off_x = ((double) (otfg->f.f1.value->XPlacement)
985                            * 100 / unitsPerEm + 128);
986                 if (otfg->f.f1.format & OTF_YPlacement)
987                   off_y = ((double) (otfg->f.f1.value->YPlacement)
988                            * 100 / unitsPerEm + 128);
989                 g.combining_code
990                   = MAKE_COMBINING_CODE (3, 2, 3, 0, off_y, off_x);
991                 if ((otfg->f.f1.format & OTF_XAdvance)
992                     || (otfg->f.f1.format & OTF_YAdvance))
993                   off_y--;
994               }
995               break;
996             case 3:
997               /* Not yet supported.  */
998               break;
999             case 4:
1000               {
1001                 int off_x, off_y;
1002
1003                 off_x = ((double) (otfg->f.f4.base_anchor->XCoordinate
1004                                    - otfg->f.f4.mark_anchor->XCoordinate)
1005                          * 100 / unitsPerEm + 128);
1006                 off_y = ((double) (otfg->f.f4.base_anchor->YCoordinate
1007                                    - otfg->f.f4.mark_anchor->YCoordinate)
1008                          * 100 / unitsPerEm + 128);
1009                 g.combining_code
1010                   = MAKE_COMBINING_CODE (3, 0, 3, 0, off_y, off_x);
1011               }
1012               break;
1013             case 5:
1014               /* Not yet supported.  */
1015               break;
1016             default:            /* i.e case 6 */
1017               /* Not yet supported.  */
1018               break;
1019             }
1020           g.otf_encoded = 1;
1021         }
1022       else
1023         {
1024           g.code = otfg->c;
1025           g.otf_encoded = 0;
1026         }
1027       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
1028     }
1029   return to;
1030
1031  simple_copy:
1032 #endif  /* HAVE_OTF */
1033   for (i = 0; i < len; i++)
1034     {
1035       g = gstring->glyphs[from + i];
1036       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
1037     }
1038   return to;
1039 }
1040
1041 int
1042 mfont__ft_decode_otf (MGlyph *g)
1043 {
1044 #ifdef HAVE_OTF
1045   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1046   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1047
1048   return (c ? c : -1);
1049 #else  /* not HAVE_OTF */
1050   return -1;
1051 #endif  /* not HAVE_OTF */
1052 }
1053
1054 #endif /* HAVE_FREETYPE */