(DEVICE_DELTA): New macro.
[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       char *filename;
308
309       if (fs->nfont > 0)
310         for (i = 0; i < fs->nfont; i++)
311           {
312             FcPatternGetString (fs->fonts[i], FC_FILE, 0, 
313                                 (FcChar8 **) &filename);
314             add_font_info (filename, family);
315           }
316       else
317         {
318           FcPattern *match;
319           FcResult result;
320
321           FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
322           FcDefaultSubstitute (pattern);
323           match = FcFontMatch (fc_config, pattern, &result);
324           if (FcPatternGetString (match, FC_FILE, 0, (FcChar8 **) &filename)
325               == FcResultMatch)
326             add_font_info (filename, family);
327           FcPatternDestroy (match);
328         }
329       FcFontSetDestroy (fs);
330     }
331   FcObjectSetDestroy (os);
332   FcPatternDestroy (pattern);
333 }
334
335 #else  /* not HAVE_FONTCONFIG */
336
337 static void
338 ft_list ()
339 {
340   MPlist *plist;
341   struct stat buf;
342   char *pathname;
343
344   MPLIST_DO (plist, mfont_freetype_path)
345     if (MPLIST_STRING_P (plist)
346         && (pathname = MPLIST_STRING (plist))
347         && stat (pathname, &buf) == 0)
348       {
349         if (S_ISREG (buf.st_mode))
350           add_font_info (pathname, Mnil);
351         else if (S_ISDIR (buf.st_mode))
352           {
353             int len = strlen (pathname);
354             char path[PATH_MAX];
355             DIR *dir = opendir (pathname);
356             struct dirent *dp;
357
358             if (dir)
359               {
360                 strcpy (path, pathname);
361                 strcpy (path + len, "/");
362                 len++;
363                 while ((dp = readdir (dir)) != NULL)
364                   {
365                     strcpy (path + len, dp->d_name);
366                     add_font_info (path, Mnil);
367                   }
368                 closedir (dir);
369               }
370           }
371       }
372 }
373
374 #endif  /* not HAVE_FONTCONFIG */
375
376 /* The FreeType font driver function SELECT.  */
377
378 static MRealizedFont *
379 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
380 {
381   MPlist *plist, *pl;
382   MFTInfo *best_font;
383   int best_score;
384   MRealizedFont *rfont;
385   MSymbol family, registry;
386
387   best_font = NULL;
388   best_score = 0;
389   family = FONT_PROPERTY (spec, MFONT_FAMILY);
390   if (family == Mnil)
391     family = FONT_PROPERTY (request, MFONT_FAMILY);
392   registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
393   if (registry == Mnil)
394     registry = Mt;
395
396   if (! ft_font_list)
397     ft_font_list = mplist ();
398 #ifdef HAVE_FONTCONFIG
399   if (family != Mnil)
400     {
401       plist = mplist_get (ft_font_list, family);
402       if (! plist)
403         {
404           fc_list (family);
405           plist = mplist_get (ft_font_list, family);
406           if (! plist)
407             {
408               mplist_add (ft_font_list, family, plist = mplist ());
409               return NULL;
410             }
411         }
412     }
413   else
414     {
415       if (! all_fonts_scaned)
416         {
417           fc_list (Mnil);
418           all_fonts_scaned = 1;
419         }
420     }
421 #else  /* not HAVE_FONTCONFIG */
422   if (! all_fonts_scaned)
423     {
424       ft_list ();
425       all_fonts_scaned = 1;
426     }
427   if (family != Mnil)
428     {
429       plist = mplist_get (ft_font_list, family);
430       if (! plist)
431         return NULL;
432     }
433 #endif  /* not HAVE_FONTCONFIG */
434
435   if (family == Mnil)
436     plist = MPLIST_VAL (ft_font_list);
437
438  retry:
439   MPLIST_DO (pl, plist)
440     {
441       MFTInfo *ft_info = MPLIST_VAL (pl);
442       int score;
443
444       if (! mplist_find_by_key (ft_info->charmap_list, registry))
445         continue;
446       /* We always ignore FOUNDRY.  */
447       ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
448       score = mfont__score (&ft_info->font, spec, request, limited_size);
449       if (score >= 0
450           && (! best_font
451               || best_score > score))
452         {
453           best_font = ft_info;
454           best_score = score;
455           if (score == 0)
456             break;
457         }
458     }
459   if (family == Mnil)
460     {
461       plist = MPLIST_NEXT (plist);
462       if (! MPLIST_TAIL_P (plist))
463         goto retry;
464     }
465   if (! best_font)
466     return NULL;
467
468   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
469   rfont->frame = frame;
470   rfont->spec = *spec;
471   rfont->request = *request;
472   rfont->font = best_font->font;
473   rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
474   rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
475   rfont->score = best_score;
476   rfont->info = best_font;
477   M17N_OBJECT_REF (best_font);
478   return rfont;
479 }
480
481
482 /* The FreeType font driver function OPEN.  */
483
484 static int
485 ft_open (MRealizedFont *rfont)
486 {
487   MFTInfo *base = rfont->info, *ft_info;
488   MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
489   int mdebug_mask = MDEBUG_FONT;
490   int size;
491
492   M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
493   ft_info->font = base->font;
494   ft_info->filename = strdup (base->filename);
495   ft_info->otf_flag = base->otf_flag;
496   ft_info->charmap_list = base->charmap_list;
497   M17N_OBJECT_REF (ft_info->charmap_list);
498   M17N_OBJECT_UNREF (base);
499   rfont->info = ft_info;
500
501   rfont->status = -1;
502   ft_info->ft_face = NULL;
503   if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
504     goto err;
505   if (registry == Mnil)
506     registry = Mt;
507   ft_info->charmap_index
508     = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
509   if (ft_info->charmap_index >= 0
510       && FT_Set_Charmap (ft_info->ft_face, 
511                          ft_info->ft_face->charmaps[ft_info->charmap_index]))
512     goto err;
513   size = rfont->font.property[MFONT_SIZE] / 10;
514   if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
515     goto err;
516
517   MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
518   rfont->status = 1;
519   rfont->ascent = ft_info->ft_face->ascender >> 6;
520   rfont->descent = - (ft_info->ft_face->descender >> 6);
521   return 0;
522
523  err:
524   MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
525   if (ft_info->ft_face)
526     FT_Done_Face (ft_info->ft_face);
527   M17N_OBJECT_UNREF (ft_info->charmap_list);
528   free (ft_info->filename);
529   free (ft_info);
530   rfont->info = NULL;
531   return -1;
532 }
533
534 /* The FreeType font driver function FIND_METRIC.  */
535
536 static void
537 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
538                 int from, int to)
539 {
540   MFTInfo *ft_info = (MFTInfo *) rfont->info;
541   FT_Face ft_face = ft_info->ft_face;
542   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
543   FT_Int32 load_flags = FT_LOAD_RENDER;
544
545 #ifdef FT_LOAD_TARGET_MONO
546   load_flags |= FT_LOAD_TARGET_MONO;
547 #else
548   load_flags |= FT_LOAD_MONOCHROME;
549 #endif
550
551   for (; g != gend; g++)
552     {
553       if (g->code == MCHAR_INVALID_CODE)
554         {
555           if (FT_IS_SCALABLE (ft_face))
556             {
557               unsigned unitsPerEm = ft_face->units_per_EM;
558               int size = rfont->font.property[MFONT_SIZE] / 10;
559
560               g->lbearing = 0;
561               g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
562               g->width = ft_face->max_advance_width * size / unitsPerEm;
563               g->ascent = ft_face->ascender * size / unitsPerEm;
564               g->descent = (- ft_face->descender) * size / unitsPerEm;
565             }
566           else
567             {
568               BDF_PropertyRec prop;
569
570               g->lbearing = 0;
571               g->rbearing = g->width = ft_face->available_sizes->width;
572               if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
573                 {
574                   g->ascent = prop.u.integer;
575                   FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
576                   g->descent = prop.u.integer;
577                 }
578               else
579                 {
580                   g->ascent = ft_face->available_sizes->height;
581                   g->descent = 0;
582                 }
583             }
584         }
585       else
586         {
587           FT_Glyph_Metrics *metrics;
588
589           FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_RENDER);
590           metrics = &ft_face->glyph->metrics;
591           g->lbearing = (metrics->horiBearingX >> 6);
592           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
593           g->width = metrics->horiAdvance >> 6;
594           g->ascent = metrics->horiBearingY >> 6;
595           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
596         }
597     }
598 }
599
600 /* The FreeType font driver function ENCODE_CHAR.  */
601
602 static unsigned
603 ft_encode_char (MRealizedFont *rfont, unsigned code)
604 {
605   MFTInfo *ft_info;
606
607   if (rfont->status == 0)
608     {
609       if ((rfont->driver->open) (rfont) < 0)
610         return -1;
611     }
612   ft_info = (MFTInfo *) rfont->info;
613   code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
614   if (! code)
615     return MCHAR_INVALID_CODE;
616   return (code);
617
618 }
619
620 /* The FreeType font driver function RENDER.  */
621
622 #define NUM_POINTS 0x1000
623
624 typedef struct {
625   MDrawPoint points[NUM_POINTS];
626   MDrawPoint *p;
627 } MPointTable;
628
629 static void
630 ft_render (MDrawWindow win, int x, int y,
631            MGlyphString *gstring, MGlyph *from, MGlyph *to,
632            int reverse, MDrawRegion region)
633 {
634   MFTInfo *ft_info;
635   FT_Face ft_face;
636   MRealizedFace *rface = from->rface;
637   MFrame *frame = rface->frame;
638   FT_Int32 load_flags = FT_LOAD_RENDER;
639   MGlyph *g;
640   int i, j;
641   MPointTable point_table[8];
642
643   if (from == to)
644     return;
645
646   /* It is assured that the all glyphs in the current range use the
647      same realized face.  */
648   ft_info = (MFTInfo *) rface->rfont->info;
649   ft_face = ft_info->ft_face;
650
651   if (! gstring->anti_alias)
652     {
653 #ifdef FT_LOAD_TARGET_MONO
654       load_flags |= FT_LOAD_TARGET_MONO;
655 #else
656       load_flags |= FT_LOAD_MONOCHROME;
657 #endif
658     }
659
660   for (i = 0; i < 8; i++)
661     point_table[i].p = point_table[i].points;
662
663   for (g = from; g < to; x += g++->width)
664     {
665       unsigned char *bmp;
666       int intensity;
667       MPointTable *ptable;
668       int xoff, yoff;
669       int width, pitch;
670
671       FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
672       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
673       bmp = ft_face->glyph->bitmap.buffer;
674       width = ft_face->glyph->bitmap.width;
675       pitch = ft_face->glyph->bitmap.pitch;
676       if (! gstring->anti_alias)
677         pitch *= 8;
678       if (width > pitch)
679         width = pitch;
680
681       if (gstring->anti_alias)
682         for (i = 0; i < ft_face->glyph->bitmap.rows;
683              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
684           {
685             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
686             for (j = 0; j < width; j++, xoff++)
687               {
688                 intensity = bmp[j] >> 5;
689                 if (intensity)
690                   {
691                     ptable = point_table + intensity;
692                     ptable->p->x = xoff;
693                     ptable->p->y = yoff;
694                     ptable->p++;
695                     if (ptable->p - ptable->points == NUM_POINTS)
696                       {
697                         (*frame->driver->draw_points)
698                           (frame, win, rface,
699                            reverse ? 7 - intensity : intensity,
700                            ptable->points, NUM_POINTS, region);
701                         ptable->p = ptable->points;
702                       }
703                   }
704               }
705           }
706       else
707         for (i = 0; i < ft_face->glyph->bitmap.rows;
708              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
709           {
710             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
711             for (j = 0; j < width; j++, xoff++)
712               {
713                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
714                 if (intensity)
715                   {
716                     ptable = point_table;
717                     ptable->p->x = xoff;
718                     ptable->p->y = yoff;
719                     ptable->p++;
720                     if (ptable->p - ptable->points == NUM_POINTS)
721                       {
722                         (*frame->driver->draw_points) (frame, win, rface,
723                                            reverse ? 0 : 7,
724                                            ptable->points, NUM_POINTS, region);
725                         ptable->p = ptable->points;
726                       }             
727                   }
728               }
729         }
730     }
731
732   if (gstring->anti_alias)
733     {
734       for (i = 1; i < 8; i++)
735         if (point_table[i].p != point_table[i].points)
736           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
737                              point_table[i].points,
738                              point_table[i].p - point_table[i].points, region);
739     }
740   else
741     {
742       if (point_table[0].p != point_table[0].points)
743         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
744                            point_table[0].points,
745                            point_table[0].p - point_table[0].points, region);
746     }
747 }
748
749 \f
750 /* Internal API */
751
752 MFontDriver mfont__ft_driver =
753   { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render };
754
755 int
756 mfont__ft_init ()
757 {
758   struct {
759     char *ft_style;
760     char *weight, *style, *stretch;
761   } ft_to_prop_name[] =
762     { { "regular", "medium", "r", "normal" },
763       { "italic", "medium", "i", "normal" },
764       { "bold", "bold", "r", "normal" },
765       { "bold italic", "bold", "i", "normal" },
766       { "narrow", "medium", "r", "condensed" },
767       { "narrow italic", "medium", "i", "condensed" },
768       { "narrow bold", "bold", "r", "condensed" },
769       { "narrow bold italic", "bold", "i", "condensed" },
770       { "black", "black", "r", "normal" },
771       { "black italic", "black", "i", "normal" },
772       { "oblique", "medium", "o", "normal" },
773       { "boldoblique", "bold", "o", "normal" } };
774   int i;
775
776   if (FT_Init_FreeType (&ft_library) != 0)
777     MERROR (MERROR_FONT_FT, -1);
778
779   ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
780   MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
781   for (i = 0; i < ft_to_prop_size; i++)
782     {
783       ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
784       ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
785       ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
786       ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
787     }
788
789   Municode_bmp = msymbol ("unicode-bmp");
790   Municode_full = msymbol ("unicode-full");
791   Miso10646_1 = msymbol ("iso10646-1");
792   Miso8859_1 = msymbol ("iso8859-1");
793
794   return 0;
795 }
796
797 void
798 mfont__ft_fini ()
799 {
800   MPlist *plist, *p;
801
802   if (ft_font_list)
803     {
804       MPLIST_DO (plist, ft_font_list)
805         {
806           MPLIST_DO (p, MPLIST_VAL (plist))
807             {
808               MFTInfo *ft_info = MPLIST_VAL (p);
809
810               M17N_OBJECT_UNREF (ft_info);
811             }
812           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
813         }
814       M17N_OBJECT_UNREF (ft_font_list);
815       ft_font_list = NULL;
816     }
817   free (ft_to_prop);
818   FT_Done_FreeType (ft_library);
819   all_fonts_scaned = 0;
820 }
821
822
823 #ifdef HAVE_FONTCONFIG
824 int
825 mfont__ft_parse_name (char *name, MFont *font)
826 {
827   FcPattern *pat = FcNameParse ((FcChar8 *) name);
828   FcResult result;
829   FcChar8 *str;
830   double size;
831   
832   if (! pat)
833     return -1;
834   if ((result = FcPatternGetString (pat, FC_FOUNDRY, 0, &str)) == FcResultMatch)
835     mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
836   if ((result = FcPatternGetString (pat, FC_FAMILY, 0, &str)) == FcResultMatch)
837     mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
838   if ((result = FcPatternGetString (pat, FC_STYLE, 0, &str)) == FcResultMatch)
839     {
840       MSymbol style = msymbol ((char *) str);
841       int i;
842
843       for (i = 0; i < ft_to_prop_size; i++)
844         if (ft_to_prop[i].ft_style == style)
845           {
846             mfont__set_property (font, MFONT_WEIGHT, ft_to_prop[i].weight);
847             mfont__set_property (font, MFONT_STYLE, ft_to_prop[i].style);
848             mfont__set_property (font, MFONT_STRETCH, ft_to_prop[i].stretch);
849             break;
850           }
851     }
852   if ((result = FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size))
853       == FcResultMatch)
854     font->property[MFONT_SIZE] = size * 10;
855   FcPatternDestroy (pat);
856   return 0;
857 }
858
859 char *
860 mfont__ft_unparse_name (MFont *font)
861 {
862   FcPattern *pat = FcPatternCreate ();
863   MSymbol sym, weight, style, stretch;
864   char *name;
865   int i;
866
867   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
868     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
869   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
870     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
871   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) == Mnil)
872     weight = msymbol ("medium");
873   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) == Mnil)
874     style = msymbol ("r");
875   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) == Mnil)
876     stretch = msymbol ("normal");
877   for (i = 0; i < ft_to_prop_size; i++)
878     if (ft_to_prop[i].weight == weight
879         && ft_to_prop[i].style == style
880         && ft_to_prop[i].stretch == stretch)
881       FcPatternAddString (pat, FC_STYLE,
882                           (FcChar8 *) MSYMBOL_NAME (ft_to_prop[i].ft_style));
883   name = (char *) FcNameUnparse (pat);
884   FcPatternDestroy (pat);
885   return name;
886 }
887 #endif  /* HAVE_FONTCONFIG */
888
889 \f
890 #ifdef HAVE_OTF
891
892 #define DEVICE_DELTA(table, size)                               \
893   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
894    ? (table).DeltaValue[(size) >= (table).StartSize]            \
895    : 0)
896
897 void
898 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
899                MGlyph *prev, int size, int *x, int *y)
900 {
901   if (anchor->AnchorFormat == 2 && prev)
902     {
903       FT_Outline *outline;
904       int ap = anchor->f.f1.AnchorPoint;
905
906       FT_Load_Glyph (ft_face, (FT_UInt) prev->code, FT_LOAD_MONOCHROME);
907       outline = &ft_face->glyph->outline;
908       if (ap < outline->n_points)
909         {
910           *x = outline->points[ap].x;
911           *y = outline->points[ap].y;
912         }
913     }
914   else if (anchor->AnchorFormat == 3)
915     {
916       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
917       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
918     }
919 }
920
921 int
922 mfont__ft_drive_gsub (MGlyphString *gstring, int from, int to)
923 {
924   int len = to - from;
925   MGlyph g;
926   int i;
927   MFTInfo *ft_info;
928   OTF *otf;
929   OTF_GlyphString otf_gstring;
930   OTF_Glyph *otfg;
931   char *script_name, *language_name;
932   char *gsub_feature_names;
933   int from_pos, to_pos;
934   int need_cmap;
935
936   if (len == 0)
937     return from;
938
939   g = gstring->glyphs[from];
940   ft_info = g.rface->rfont->info;
941   if (ft_info->otf_flag < 0)
942     goto simple_copy;
943   otf = ft_info->otf;
944   if (! otf)
945     {
946       otf = OTF_open (ft_info->filename);
947       if (otf && OTF_get_table (otf, "head") < 0)
948         {
949           OTF_close (otf);
950           otf = NULL;
951         }
952       if (! otf)
953         {
954           ft_info->otf_flag = -1;
955           goto simple_copy;
956         }
957       ft_info->otf = otf;
958     }
959
960   if (g.otf_cmd->script != Mnil)
961     script_name = msymbol_name (g.otf_cmd->script);
962   else
963     script_name = NULL;
964   if (g.otf_cmd->langsys != Mnil)
965     language_name = msymbol_name (g.otf_cmd->langsys);
966   else
967     language_name = NULL;
968   gsub_feature_names
969     = (g.otf_cmd->gsub_features == Mt ? "*"
970        : g.otf_cmd->gsub_features == Mnil ? NULL
971        : msymbol_name (g.otf_cmd->gsub_features));
972   if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
973     gsub_feature_names = NULL;
974   if (! gsub_feature_names)
975     goto simple_copy;
976
977   from_pos = g.pos;
978   to_pos = g.to;
979   for (i = from + 1; i < to; i++)
980     {
981       if (from_pos > gstring->glyphs[i].pos)
982         from_pos = gstring->glyphs[i].pos;
983       if (to_pos < gstring->glyphs[i].to)
984         to_pos = gstring->glyphs[i].to;
985     }
986
987   otf_gstring.size = otf_gstring.used = len;
988   otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
989   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
990   for (i = 0, need_cmap = 0; i < len; i++)
991     {
992       if (gstring->glyphs[from + i].otf_encoded)
993         {
994           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
995           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
996         }
997       else
998         {
999           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1000           need_cmap++;
1001         }
1002     }
1003   if (need_cmap
1004       && OTF_drive_cmap (otf, &otf_gstring) < 0)
1005     goto simple_copy;
1006   if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1007                       gsub_feature_names) < 0)
1008     goto simple_copy;
1009
1010   g.pos = from_pos;
1011   g.to = to_pos;
1012   for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1013     {
1014       g.combining_code = 0;
1015       g.c = otfg->c;
1016       if (otfg->glyph_id)
1017         {
1018           g.code = otfg->glyph_id;
1019           g.otf_encoded = 1;
1020         }
1021       else
1022         {
1023           g.code = otfg->c;
1024           g.otf_encoded = 0;
1025         }
1026       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
1027     }
1028   return to;
1029
1030  simple_copy:
1031   for (i = 0; i < len; i++)
1032     {
1033       g = gstring->glyphs[from + i];
1034       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
1035     }
1036   return to;
1037 }
1038
1039 int
1040 mfont__ft_drive_gpos (MGlyphString *gstring, int from, int to)
1041 {
1042   int len = to - from;
1043   MGlyph *g, *prev;
1044   int i;
1045   MFTInfo *ft_info;
1046   OTF *otf;
1047   OTF_GlyphString otf_gstring;
1048   OTF_Glyph *otfg;
1049   char *script_name, *language_name;
1050   char *gpos_feature_names;
1051   int u;
1052   int size10, size;
1053
1054   if (len == 0)
1055     return from;
1056
1057   g = MGLYPH (from);
1058   ft_info = g->rface->rfont->info;
1059   if (ft_info->otf_flag < 0)
1060     return to;
1061   otf = ft_info->otf;
1062   if (! otf)
1063     return to;
1064   if (g->otf_cmd->script != Mnil)
1065     script_name = msymbol_name (g->otf_cmd->script);
1066   else
1067     script_name = NULL;
1068   if (g->otf_cmd->langsys != Mnil)
1069     language_name = msymbol_name (g->otf_cmd->langsys);
1070   else
1071     language_name = NULL;
1072   gpos_feature_names
1073     = (g->otf_cmd->gpos_features == Mt ? "*"
1074        : g->otf_cmd->gpos_features == Mnil ? NULL
1075        : msymbol_name (g->otf_cmd->gpos_features));
1076   if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1077     gpos_feature_names = NULL;
1078   if (! gpos_feature_names)
1079     return to;
1080
1081   otf_gstring.size = otf_gstring.used = len;
1082   otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
1083   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1084   for (i = 0; i < len; i++)
1085     {
1086       otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1087       otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1088     }
1089   if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1090                       gpos_feature_names) < 0)
1091     return to;
1092
1093   u = otf->head->unitsPerEm;
1094   size10 = g->rface->rfont->font.property[MFONT_SIZE];
1095   size = size10 / 10;
1096   prev = NULL;
1097   for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
1098        prev = g++, i++, otfg++)
1099     switch (otfg->positioning_type)
1100       {
1101       case 0:
1102         break;
1103       case 1: case 2:
1104         {
1105           int format = otfg->f.f1.format;
1106
1107           if (format & OTF_XPlacement)
1108             g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1109           if (format & OTF_XPlaDevice)
1110             g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1111           if (format & OTF_YPlacement)
1112             g->yoff = otfg->f.f1.value->YPlacement * size10 / u / 10;
1113           if (format & OTF_YPlaDevice)
1114             g->yoff += DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1115         }
1116         break;
1117       case 3:
1118         /* Not yet supported.  */
1119         break;
1120       case 4:
1121         {
1122           int base_x, base_y, mark_x, mark_y;
1123
1124           base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1125           base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1126           mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1127           mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1128
1129           if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1130             adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1131                            prev, size, &base_x, &base_y);
1132           if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1133             adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1134                            prev, size, &mark_x, &mark_y);
1135           g->xoff = (base_x - prev->width) - mark_x;
1136           g->yoff = base_y - mark_y;
1137         }
1138         break;
1139       case 5:
1140         /* Not yet supported.  */
1141         break;
1142       default:          /* i.e case 6 */
1143         /* Not yet supported.  */
1144         break;
1145       }
1146   return to;
1147 }
1148
1149 int
1150 mfont__ft_decode_otf (MGlyph *g)
1151 {
1152   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1153   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1154
1155   return (c ? c : -1);
1156 }
1157
1158 #endif  /* HAVE_OTF */
1159
1160 #endif /* HAVE_FREETYPE */