(mfont__ft_drive_gpos): Fix previous change.
[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   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
574           FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_RENDER);
575           metrics = &ft_face->glyph->metrics;
576           g->lbearing = (metrics->horiBearingX >> 6);
577           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
578           g->width = metrics->horiAdvance >> 6;
579           g->ascent = metrics->horiBearingY >> 6;
580           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
581         }
582     }
583 }
584
585 /* The FreeType font driver function ENCODE_CHAR.  */
586
587 static unsigned
588 ft_encode_char (MRealizedFont *rfont, unsigned code)
589 {
590   MFTInfo *ft_info;
591
592   if (rfont->status == 0)
593     {
594       if ((rfont->driver->open) (rfont) < 0)
595         return -1;
596     }
597   ft_info = (MFTInfo *) rfont->info;
598   code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
599   if (! code)
600     return MCHAR_INVALID_CODE;
601   return (code);
602
603 }
604
605 /* The FreeType font driver function RENDER.  */
606
607 #define NUM_POINTS 0x1000
608
609 typedef struct {
610   MDrawPoint points[NUM_POINTS];
611   MDrawPoint *p;
612 } MPointTable;
613
614 static void
615 ft_render (MDrawWindow win, int x, int y,
616            MGlyphString *gstring, MGlyph *from, MGlyph *to,
617            int reverse, MDrawRegion region)
618 {
619   MFTInfo *ft_info;
620   FT_Face ft_face;
621   MRealizedFace *rface = from->rface;
622   MFrame *frame = rface->frame;
623   FT_Int32 load_flags = FT_LOAD_RENDER;
624   MGlyph *g;
625   int i, j;
626   MPointTable point_table[8];
627
628   if (from == to)
629     return;
630
631   /* It is assured that the all glyphs in the current range use the
632      same realized face.  */
633   ft_info = (MFTInfo *) rface->rfont->info;
634   ft_face = ft_info->ft_face;
635
636   if (! gstring->anti_alias)
637     {
638 #ifdef FT_LOAD_TARGET_MONO
639       load_flags |= FT_LOAD_TARGET_MONO;
640 #else
641       load_flags |= FT_LOAD_MONOCHROME;
642 #endif
643     }
644
645   for (i = 0; i < 8; i++)
646     point_table[i].p = point_table[i].points;
647
648   for (g = from; g < to; x += g++->width)
649     {
650       unsigned char *bmp;
651       int intensity;
652       MPointTable *ptable;
653       int xoff, yoff;
654       int width, pitch;
655
656       FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
657       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
658       bmp = ft_face->glyph->bitmap.buffer;
659       width = ft_face->glyph->bitmap.width;
660       pitch = ft_face->glyph->bitmap.pitch;
661       if (! gstring->anti_alias)
662         pitch *= 8;
663       if (width > pitch)
664         width = pitch;
665
666       if (gstring->anti_alias)
667         for (i = 0; i < ft_face->glyph->bitmap.rows;
668              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
669           {
670             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
671             for (j = 0; j < width; j++, xoff++)
672               {
673                 intensity = bmp[j] >> 5;
674                 if (intensity)
675                   {
676                     ptable = point_table + intensity;
677                     ptable->p->x = xoff;
678                     ptable->p->y = yoff;
679                     ptable->p++;
680                     if (ptable->p - ptable->points == NUM_POINTS)
681                       {
682                         (*frame->driver->draw_points)
683                           (frame, win, rface,
684                            reverse ? 7 - intensity : intensity,
685                            ptable->points, NUM_POINTS, region);
686                         ptable->p = ptable->points;
687                       }
688                   }
689               }
690           }
691       else
692         for (i = 0; i < ft_face->glyph->bitmap.rows;
693              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
694           {
695             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
696             for (j = 0; j < width; j++, xoff++)
697               {
698                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
699                 if (intensity)
700                   {
701                     ptable = point_table;
702                     ptable->p->x = xoff;
703                     ptable->p->y = yoff;
704                     ptable->p++;
705                     if (ptable->p - ptable->points == NUM_POINTS)
706                       {
707                         (*frame->driver->draw_points) (frame, win, rface,
708                                            reverse ? 0 : 7,
709                                            ptable->points, NUM_POINTS, region);
710                         ptable->p = ptable->points;
711                       }             
712                   }
713               }
714         }
715     }
716
717   if (gstring->anti_alias)
718     {
719       for (i = 1; i < 8; i++)
720         if (point_table[i].p != point_table[i].points)
721           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
722                              point_table[i].points,
723                              point_table[i].p - point_table[i].points, region);
724     }
725   else
726     {
727       if (point_table[0].p != point_table[0].points)
728         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
729                            point_table[0].points,
730                            point_table[0].p - point_table[0].points, region);
731     }
732 }
733
734 \f
735 /* Internal API */
736
737 MFontDriver mfont__ft_driver =
738   { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render };
739
740 int
741 mfont__ft_init ()
742 {
743   struct {
744     char *ft_style;
745     char *weight, *style, *stretch;
746   } ft_to_prop_name[] =
747     { { "regular", "medium", "r", "normal" },
748       { "medium", "medium", "r", "normal" },
749       { "normal", "medium", "r", "normal" },
750       { "italic", "medium", "i", "normal" },
751       { "bold", "bold", "r", "normal" },
752       { "bolditalic", "bold", "i", "normal" },
753       { "bold italic", "bold", "i", "normal" },
754       { "narrow", "medium", "r", "condensed" },
755       { "narrow italic", "medium", "i", "condensed" },
756       { "narrow bold", "bold", "r", "condensed" },
757       { "narrow bold italic", "bold", "i", "condensed" },
758       { "black", "black", "r", "normal" },
759       { "black italic", "black", "i", "normal" },
760       { "oblique", "medium", "o", "normal" },
761       { "boldoblique", "bold", "o", "normal" },
762       { "bold oblique", "bold", "o", "normal" } };
763   int i;
764
765   if (FT_Init_FreeType (&ft_library) != 0)
766     MERROR (MERROR_FONT_FT, -1);
767
768   ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
769   MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
770   for (i = 0; i < ft_to_prop_size; i++)
771     {
772       ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
773       ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
774       ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
775       ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
776     }
777
778   Municode_bmp = msymbol ("unicode-bmp");
779   Municode_full = msymbol ("unicode-full");
780   Miso10646_1 = msymbol ("iso10646-1");
781   Miso8859_1 = msymbol ("iso8859-1");
782
783   return 0;
784 }
785
786 void
787 mfont__ft_fini ()
788 {
789   MPlist *plist, *p;
790
791   if (ft_font_list)
792     {
793       MPLIST_DO (plist, ft_font_list)
794         {
795           MPLIST_DO (p, MPLIST_VAL (plist))
796             {
797               MFTInfo *ft_info = MPLIST_VAL (p);
798
799               M17N_OBJECT_UNREF (ft_info);
800             }
801           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
802         }
803       M17N_OBJECT_UNREF (ft_font_list);
804       ft_font_list = NULL;
805     }
806   free (ft_to_prop);
807   FT_Done_FreeType (ft_library);
808   all_fonts_scaned = 0;
809 }
810
811
812 #ifdef HAVE_FONTCONFIG
813 int
814 mfont__ft_parse_name (char *name, MFont *font)
815 {
816   FcPattern *pat = FcNameParse ((FcChar8 *) name);
817   FcResult result;
818   FcChar8 *str;
819   double size;
820   
821   if (! pat)
822     return -1;
823   if ((result = FcPatternGetString (pat, FC_FOUNDRY, 0, &str)) == FcResultMatch)
824     mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
825   if ((result = FcPatternGetString (pat, FC_FAMILY, 0, &str)) == FcResultMatch)
826     mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
827   if ((result = FcPatternGetString (pat, FC_STYLE, 0, &str)) == FcResultMatch)
828     {
829       MSymbol style = msymbol ((char *) str);
830       int i;
831
832       for (i = 0; i < ft_to_prop_size; i++)
833         if (ft_to_prop[i].ft_style == style)
834           {
835             mfont__set_property (font, MFONT_WEIGHT, ft_to_prop[i].weight);
836             mfont__set_property (font, MFONT_STYLE, ft_to_prop[i].style);
837             mfont__set_property (font, MFONT_STRETCH, ft_to_prop[i].stretch);
838             break;
839           }
840     }
841   if ((result = FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size))
842       == FcResultMatch)
843     font->property[MFONT_SIZE] = size * 10;
844   FcPatternDestroy (pat);
845   return 0;
846 }
847
848 char *
849 mfont__ft_unparse_name (MFont *font)
850 {
851   FcPattern *pat = FcPatternCreate ();
852   MSymbol sym, weight, style, stretch;
853   char *name;
854   int i;
855
856   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
857     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
858   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
859     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
860   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) == Mnil)
861     weight = msymbol ("medium");
862   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) == Mnil)
863     style = msymbol ("r");
864   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) == Mnil)
865     stretch = msymbol ("normal");
866   for (i = 0; i < ft_to_prop_size; i++)
867     if (ft_to_prop[i].weight == weight
868         && ft_to_prop[i].style == style
869         && ft_to_prop[i].stretch == stretch)
870       FcPatternAddString (pat, FC_STYLE,
871                           (FcChar8 *) MSYMBOL_NAME (ft_to_prop[i].ft_style));
872   name = (char *) FcNameUnparse (pat);
873   FcPatternDestroy (pat);
874   return name;
875 }
876 #endif  /* HAVE_FONTCONFIG */
877
878 \f
879 #ifdef HAVE_OTF
880
881 #define DEVICE_DELTA(table, size)                               \
882   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
883    ? (table).DeltaValue[(size) >= (table).StartSize]            \
884    : 0)
885
886 void
887 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
888                MGlyph *prev, int size, int *x, int *y)
889 {
890   if (anchor->AnchorFormat == 2 && prev)
891     {
892       FT_Outline *outline;
893       int ap = anchor->f.f1.AnchorPoint;
894
895       FT_Load_Glyph (ft_face, (FT_UInt) prev->code, FT_LOAD_MONOCHROME);
896       outline = &ft_face->glyph->outline;
897       if (ap < outline->n_points)
898         {
899           *x = outline->points[ap].x;
900           *y = outline->points[ap].y;
901         }
902     }
903   else if (anchor->AnchorFormat == 3)
904     {
905       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
906       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
907     }
908 }
909
910 int
911 mfont__ft_drive_gsub (MGlyphString *gstring, int from, int to)
912 {
913   int len = to - from;
914   MGlyph g;
915   int i;
916   MFTInfo *ft_info;
917   OTF *otf;
918   OTF_GlyphString otf_gstring;
919   OTF_Glyph *otfg;
920   char *script_name, *language_name;
921   char *gsub_feature_names;
922   int from_pos, to_pos;
923   int need_cmap;
924
925   if (len == 0)
926     return from;
927
928   g = gstring->glyphs[from];
929   ft_info = g.rface->rfont->info;
930   if (ft_info->otf_flag < 0)
931     goto simple_copy;
932   otf = ft_info->otf;
933   if (! otf)
934     {
935       otf = OTF_open (ft_info->filename);
936       if (otf && OTF_get_table (otf, "head") < 0)
937         {
938           OTF_close (otf);
939           otf = NULL;
940         }
941       if (! otf)
942         {
943           ft_info->otf_flag = -1;
944           goto simple_copy;
945         }
946       ft_info->otf = otf;
947     }
948
949   if (g.otf_cmd->script != Mnil)
950     script_name = msymbol_name (g.otf_cmd->script);
951   else
952     script_name = NULL;
953   if (g.otf_cmd->langsys != Mnil)
954     language_name = msymbol_name (g.otf_cmd->langsys);
955   else
956     language_name = NULL;
957   gsub_feature_names
958     = (g.otf_cmd->gsub_features == Mt ? "*"
959        : g.otf_cmd->gsub_features == Mnil ? NULL
960        : msymbol_name (g.otf_cmd->gsub_features));
961   if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
962     gsub_feature_names = NULL;
963   if (! gsub_feature_names)
964     goto simple_copy;
965
966   from_pos = g.pos;
967   to_pos = g.to;
968   for (i = from + 1; i < to; i++)
969     {
970       if (from_pos > gstring->glyphs[i].pos)
971         from_pos = gstring->glyphs[i].pos;
972       if (to_pos < gstring->glyphs[i].to)
973         to_pos = gstring->glyphs[i].to;
974     }
975
976   otf_gstring.size = otf_gstring.used = len;
977   otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
978   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
979   for (i = 0, need_cmap = 0; i < len; i++)
980     {
981       if (gstring->glyphs[from + i].otf_encoded)
982         {
983           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
984           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
985         }
986       else
987         {
988           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
989           need_cmap++;
990         }
991     }
992   if (need_cmap
993       && OTF_drive_cmap (otf, &otf_gstring) < 0)
994     goto simple_copy;
995   if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
996                       gsub_feature_names) < 0)
997     goto simple_copy;
998
999   g.pos = from_pos;
1000   g.to = to_pos;
1001   for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1002     {
1003       g.combining_code = 0;
1004       g.c = otfg->c;
1005       if (otfg->glyph_id)
1006         {
1007           g.code = otfg->glyph_id;
1008           g.otf_encoded = 1;
1009         }
1010       else
1011         {
1012           g.code = otfg->c;
1013           g.otf_encoded = 0;
1014         }
1015       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
1016     }
1017   return to;
1018
1019  simple_copy:
1020   for (i = 0; i < len; i++)
1021     {
1022       g = gstring->glyphs[from + i];
1023       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
1024     }
1025   return to;
1026 }
1027
1028 int
1029 mfont__ft_drive_gpos (MGlyphString *gstring, int from, int to)
1030 {
1031   int len = to - from;
1032   MGlyph *g;
1033   int i;
1034   MFTInfo *ft_info;
1035   OTF *otf;
1036   OTF_GlyphString otf_gstring;
1037   char *script_name, *language_name;
1038   char *gpos_feature_names;
1039   int u;
1040   int size10, size;
1041   int inc, from_idx, to_idx;
1042
1043   if (len == 0)
1044     return from;
1045
1046   g = MGLYPH (from);
1047   ft_info = g->rface->rfont->info;
1048   if (ft_info->otf_flag < 0)
1049     return to;
1050   otf = ft_info->otf;
1051   if (! otf)
1052     return to;
1053   if (g->otf_cmd->script != Mnil)
1054     script_name = msymbol_name (g->otf_cmd->script);
1055   else
1056     script_name = NULL;
1057   if (g->otf_cmd->langsys != Mnil)
1058     language_name = msymbol_name (g->otf_cmd->langsys);
1059   else
1060     language_name = NULL;
1061   gpos_feature_names
1062     = (g->otf_cmd->gpos_features == Mt ? "*"
1063        : g->otf_cmd->gpos_features == Mnil ? NULL
1064        : msymbol_name (g->otf_cmd->gpos_features));
1065   if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1066     gpos_feature_names = NULL;
1067   if (! gpos_feature_names)
1068     return to;
1069
1070   otf_gstring.size = otf_gstring.used = len;
1071   otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
1072   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1073   if (g->bidi_level & 1)
1074     from_idx = len - 1, to_idx = -1, inc = -1;
1075   else
1076     from_idx = 0, to_idx = len, inc = 1;
1077
1078   for (i = from_idx; i != to_idx; i += inc)
1079     {
1080       otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1081       otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1082     }
1083   if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1084                       gpos_feature_names) < 0)
1085     return to;
1086
1087   u = otf->head->unitsPerEm;
1088   size10 = g->rface->rfont->font.property[MFONT_SIZE];
1089   size = size10 / 10;
1090   for (i = from_idx; i != to_idx; i += inc)
1091     {
1092       OTF_Glyph *otfg = otf_gstring.glyphs + i;
1093
1094       switch (otfg->positioning_type)
1095         {
1096         case 0:
1097           break;
1098         case 1: case 2:
1099           {
1100             int format = otfg->f.f1.format;
1101
1102             if (format & OTF_XPlacement)
1103               g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1104             if (format & OTF_XPlaDevice)
1105               g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1106             if (format & OTF_YPlacement)
1107               g->yoff = otfg->f.f1.value->YPlacement * size10 / u / 10;
1108             if (format & OTF_YPlaDevice)
1109               g->yoff += DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1110           }
1111           break;
1112         case 3:
1113           /* Not yet supported.  */
1114           break;
1115         case 4:
1116           {
1117             int base_x, base_y, mark_x, mark_y;
1118             MGlyph *prev = g - inc;
1119
1120             base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1121             base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1122             mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1123             mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1124
1125             if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1126               adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1127                              prev, size, &base_x, &base_y);
1128             if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1129               adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1130                              g, size, &mark_x, &mark_y);
1131             g->xoff = (base_x - prev->width) - mark_x;
1132             g->yoff = base_y - mark_y;
1133             if (inc < 0)
1134               {
1135                 MGlyph temp = *g;
1136
1137                 *g = g[1];
1138                 g[1] = temp;
1139               }
1140           }
1141           break;
1142         case 5:
1143           /* Not yet supported.  */
1144           break;
1145         default:                /* i.e case 6 */
1146           /* Not yet supported.  */
1147           break;
1148         }
1149     }
1150   return to;
1151 }
1152
1153 int
1154 mfont__ft_decode_otf (MGlyph *g)
1155 {
1156   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1157   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1158
1159   return (c ? c : -1);
1160 }
1161
1162 #endif  /* HAVE_OTF */
1163
1164 #endif /* HAVE_FREETYPE */