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
6 This file is part of the m17n library.
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.
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.
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
28 #include <sys/types.h>
35 #include "m17n-misc.h"
38 #include "internal-gui.h"
44 #include FT_FREETYPE_H
50 static FT_Library ft_library;
55 MSymbol weight, style, stretch;
58 static int ft_to_prop_size;
59 static MFTtoProp *ft_to_prop;
68 int otf_flag; /* This font 1: is OTF, 0: may be OTF, -1: is not OTF. */
74 /* List of FreeType fonts. Keys are family names, values are (MFTInfo
75 *) where MFTInfo->ft_face and MFTInfo->otf are NULL. */
76 static MPlist *ft_font_list;
78 /** Return 1 iff the filename in DIRENTRY matches FreeType font file.
79 We select only TrueType/OpenType/Type1 fonts.
80 Used as the arg SELECT of scandir () in list_ft_in_dir (). */
83 check_filename (const char *name)
85 int len = strlen (name);
86 const char *ext = name + (len - 4);
90 if (! memcmp (ext, ".ttf", 4)
91 || ! memcmp (ext, ".TTF", 4)
92 || ! memcmp (ext, ".otf", 4)
93 || ! memcmp (ext, ".OTF", 4))
95 if (! memcmp (ext, ".PFA", 4)
96 || ! memcmp (ext, ".pfa", 4)
97 || ! memcmp (ext, ".PFB", 4)
98 || ! memcmp (ext, ".pfb", 4))
104 ft_set_property (MFont *font, char *family_name, char *style_name)
112 font->property[MFONT_TYPE] = MFONT_TYPE_FT + 1;
113 mfont__set_property (font, MFONT_ADSTYLE, msymbol (""));
115 len = strlen (family_name) + 1;
116 buf = (char *) alloca (len);
117 memcpy (buf, family_name, len);
118 for (p = buf; *p; p++)
119 if (*p >= 'A' && *p <= 'Z')
121 family = msymbol (buf);
122 mfont__set_property (font, MFONT_FAMILY, family);
126 len = strlen (style_name) + 1;
127 buf = (char *) alloca (len);
128 memcpy (buf, style_name, len);
129 for (p = buf; *p; p++)
130 if (*p >= 'A' && *p <= 'Z')
132 style = msymbol (buf);
141 for (i = 0; i < ft_to_prop_size; i++)
142 if (ft_to_prop[i].ft_style == style)
144 mfont__set_property (font, MFONT_WEIGHT, ft_to_prop[i].weight);
145 mfont__set_property (font, MFONT_STYLE, ft_to_prop[i].style);
146 mfont__set_property (font, MFONT_STRETCH, ft_to_prop[i].stretch);
150 mfont__set_property (font, MFONT_WEIGHT, msymbol ("medium"));
151 mfont__set_property (font, MFONT_STYLE, msymbol ("r"));
152 mfont__set_property (font, MFONT_STRETCH, msymbol ("normal"));
157 add_font_list (char *filename, int otf_flag)
162 char registry_buf[16];
165 if (FT_New_Face (ft_library, filename, 0, &ft_face))
168 if (ft_face->family_name && ((char *) ft_face->family_name)[0])
170 int unicode_charmap_bmp = -1, unicode_charmap_full = -1;
172 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
173 family = ft_set_property (&ft_info->font,
174 (char *) ft_face->family_name,
175 (char *) ft_face->style_name);
176 ft_info->filename = strdup (filename);
177 ft_info->charmap_list = mplist ();
178 mplist_add (ft_info->charmap_list, Mt, (void *) -1);
179 for (i = 0; i < ft_face->num_charmaps; i++)
181 sprintf (registry_buf, "%d-%d",
182 ft_face->charmaps[i]->platform_id,
183 ft_face->charmaps[i]->encoding_id);
184 mplist_add (ft_info->charmap_list, msymbol (registry_buf),
186 if (ft_face->charmaps[i]->platform_id == 0)
188 if (ft_face->charmaps[i]->encoding_id == 3)
189 unicode_charmap_bmp = i;
190 else if (ft_face->charmaps[i]->encoding_id == 4)
191 unicode_charmap_full = i;
193 else if (ft_face->charmaps[i]->platform_id == 3)
195 if (ft_face->charmaps[i]->encoding_id == 1)
196 unicode_charmap_bmp = i;
197 else if (ft_face->charmaps[i]->encoding_id == 10)
198 unicode_charmap_full = i;
200 else if (ft_face->charmaps[i]->platform_id == 1
201 && ft_face->charmaps[i]->encoding_id == 0)
202 mplist_add (ft_info->charmap_list, msymbol ("apple-roman"),
205 if (unicode_charmap_bmp >= 0)
206 mplist_add (ft_info->charmap_list, msymbol ("unicode-bmp"),
207 (void *) unicode_charmap_bmp);
208 if (unicode_charmap_full >= 0)
209 mplist_add (ft_info->charmap_list, msymbol ("unicode-full"),
210 (void *) unicode_charmap_full);
211 mplist_add (ft_font_list, family, ft_info);
213 FT_Done_Face (ft_face);
223 ft_font_list = mplist ();
225 MPLIST_DO (plist, mfont_freetype_path)
226 if (MPLIST_STRING_P (plist)
227 && (pathname = MPLIST_STRING (plist))
228 && stat (pathname, &buf) == 0)
230 if (S_ISREG (buf.st_mode))
232 int result = check_filename (pathname);
234 add_font_list (pathname, result > 0 ? 0 : -1);
236 else if (S_ISDIR (buf.st_mode))
238 int len = strlen (pathname);
240 DIR *dir = opendir (pathname);
246 strcpy (path, pathname);
247 strcpy (path + len, "/");
249 while ((dp = readdir (dir)) != NULL)
250 if ((result = check_filename (dp->d_name)) >= 0)
252 strcpy (path + len, dp->d_name);
253 add_font_list (path, result > 0 ? 0 : -1);
261 static MRealizedFont *ft_select (MFrame *, MFont *, MFont *, int);
262 static int ft_open (MRealizedFont *);
263 static void ft_close (MRealizedFont *);
264 static void ft_find_metric (MRealizedFont *, MGlyph *);
265 static unsigned ft_encode_char (MRealizedFont *, int, unsigned);
266 static void ft_render (MDrawWindow, int, int, MGlyphString *,
267 MGlyph *, MGlyph *, int, MDrawRegion);
269 MFontDriver ft_driver =
270 { ft_select, ft_open, ft_close,
271 ft_find_metric, ft_encode_char, ft_render };
273 /* The FreeType font driver function LIST. */
275 static MRealizedFont *
276 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
281 MRealizedFont *rfont;
282 MSymbol family, registry;
288 family = FONT_PROPERTY (spec, MFONT_FAMILY);
289 registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
290 if (registry == Mnil)
293 MPLIST_DO (plist, ft_font_list)
300 plist = mplist_find_by_key (plist, family);
304 ft_info = (MFTInfo *) MPLIST_VAL (plist);
305 if (! mplist_find_by_key (ft_info->charmap_list, registry))
308 /* We always ignore FOUNDRY. */
309 ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
310 score = mfont__score (&ft_info->font, spec, request, limited_size);
313 || best_score > score))
324 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
325 rfont->frame = frame;
327 rfont->request = *request;
328 rfont->font = best_font->font;
329 rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
330 rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
331 rfont->score = best_score;
332 rfont->info = best_font;
333 rfont->driver = &ft_driver;
338 close_ft (void *object)
340 MFTInfo *ft_info = (MFTInfo *) object;
342 if (ft_info->ft_face)
343 FT_Done_Face (ft_info->ft_face);
346 OTF_close (ft_info->otf);
347 #endif /* HAVE_OTF */
351 /* The FreeType font driver function OPEN. */
354 ft_open (MRealizedFont *rfont)
357 MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
359 int mdebug_mask = MDEBUG_FONT;
361 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
362 ft_info->font = ((MFTInfo *) rfont->info)->font;
363 ft_info->otf_flag = ((MFTInfo *) rfont->info)->otf_flag;
364 ft_info->filename = ((MFTInfo *) rfont->info)->filename;
365 ft_info->charmap_list = ((MFTInfo *) rfont->info)->charmap_list;
366 rfont->info = ft_info;
369 if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
371 if (registry == Mnil)
373 i = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
375 && FT_Set_Charmap (ft_info->ft_face, ft_info->ft_face->charmaps[i]))
377 if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0,
378 rfont->font.property[MFONT_SIZE] / 10))
381 MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
383 rfont->ascent = ft_info->ft_face->ascender >> 6;
384 rfont->descent = ft_info->ft_face->descender >> 6;
388 MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
392 /* The FreeType font driver function CLOSE. */
395 ft_close (MRealizedFont *rfont)
397 M17N_OBJECT_UNREF (rfont->info);
400 /* The FreeType font driver function FIND_METRIC. */
403 ft_find_metric (MRealizedFont *rfont, MGlyph *g)
405 MFTInfo *ft_info = (MFTInfo *) rfont->info;
406 FT_Face ft_face = ft_info->ft_face;
408 if (g->code == MCHAR_INVALID_CODE)
410 unsigned unitsPerEm = ft_face->units_per_EM;
411 int size = rfont->font.property[MFONT_SIZE] / 10;
414 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
415 g->width = ft_face->max_advance_width * size / unitsPerEm;
416 g->ascent = ft_face->ascender * size / unitsPerEm;
417 g->descent = (- ft_face->descender) * size / unitsPerEm;
421 FT_Glyph_Metrics *metrics;
427 code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
429 FT_Load_Glyph (ft_face, code, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
430 metrics = &ft_face->glyph->metrics;
431 g->lbearing = metrics->horiBearingX >> 6;
432 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
433 g->width = metrics->horiAdvance >> 6;
434 g->ascent = metrics->horiBearingY >> 6;
435 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
439 /* The FreeType font driver function ENCODE_CHAR. */
442 ft_encode_char (MRealizedFont *rfont, int c, unsigned ignored)
447 if (rfont->status == 0)
449 if (ft_open (rfont) < 0)
452 ft_info = (MFTInfo *) rfont->info;
453 code = FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) c);
455 return MCHAR_INVALID_CODE;
457 FT_Load_Glyph (ft_info->ft_face, code, FT_LOAD_NO_SCALE);
458 return (ft_info->ft_face->glyph->metrics.width > 0
459 ? (unsigned) c : MCHAR_INVALID_CODE);
461 return ((unsigned) c);
465 /* The FreeType font driver function RENDER. */
468 ft_render (MDrawWindow win, int x, int y,
469 MGlyphString *gstring, MGlyph *from, MGlyph *to,
470 int reverse, MDrawRegion region)
472 MRealizedFace *rface;
475 FT_Face ft_face = NULL;
481 /* It is assured that the all glyphs in the current range use the
482 same realized face. */
484 frame = rface->frame;
485 ft_info = (MFTInfo *) rface->rfont->info;
486 ft_face = ft_info->ft_face;
491 if (g->type == GLYPH_CHAR)
498 code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
499 #ifdef FT_LOAD_TARGET_MONO
500 FT_Load_Glyph (ft_face, code, FT_LOAD_RENDER | FT_LOAD_TARGET_MONO);
502 FT_Render_Glyph (ft_face->glyph, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
504 mwin__draw_bitmap (frame, win, rface, reverse,
505 x + ft_face->glyph->bitmap_left + g->xoff,
506 y - ft_face->glyph->bitmap_top + g->yoff,
507 ft_face->glyph->bitmap.width,
508 ft_face->glyph->bitmap.rows,
509 ft_face->glyph->bitmap.pitch,
510 ft_face->glyph->bitmap.buffer,
526 char *weight, *style, *stretch;
527 } ft_to_prop_name[] =
528 { { "regular", "medium", "r", "normal" },
529 { "italic", "medium", "i", "normal" },
530 { "bold", "bold", "r", "normal" },
531 { "bold italic", "bold", "i", "normal" },
532 { "narrow", "medium", "r", "condensed" },
533 { "narrow italic", "medium", "i", "condensed" },
534 { "narrow bold", "bold", "r", "condensed" },
535 { "narrow bold italic", "bold", "i", "condensed" },
536 { "black", "black", "r", "normal" },
537 { "black italic", "black", "i", "normal" } };
540 if (FT_Init_FreeType (&ft_library) != 0)
541 MERROR (MERROR_FONT_FT, -1);
543 ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
544 MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
545 for (i = 0; i < ft_to_prop_size; i++)
547 ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
548 ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
549 ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
550 ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
553 mfont__driver_list[MFONT_TYPE_FT] = &ft_driver;
565 MPLIST_DO (plist, ft_font_list)
567 MFTInfo *ft_info = (MFTInfo *) MPLIST_VAL (plist);
568 free (ft_info->filename);
569 M17N_OBJECT_UNREF (ft_info->charmap_list);
572 M17N_OBJECT_UNREF (ft_font_list);
576 FT_Done_FreeType (ft_library);
581 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
582 MSymbol script, MSymbol langsys,
583 MSymbol gsub_features, MSymbol gpos_features)
591 OTF_GlyphString otf_gstring;
593 char *script_name, *language_name;
594 char *gsub_feature_names, *gpos_feature_names;
595 int from_pos, to_pos;
601 ft_info = (MFTInfo *) gstring->glyphs[from].rface->rfont->info;
602 if (ft_info->otf_flag < 0)
605 if (! otf && (otf = OTF_open (ft_info->filename)))
607 if (OTF_get_table (otf, "head") < 0
608 || (OTF_check_table (otf, "GSUB") < 0
609 && OTF_check_table (otf, "GPOS") < 0))
612 ft_info->otf_flag = -1;
619 script_name = msymbol_name (script);
620 language_name = langsys != Mnil ? msymbol_name (langsys) : NULL;
622 = (gsub_features == Mt ? "*"
623 : gsub_features == Mnil ? NULL
624 : msymbol_name (gsub_features));
626 = (gpos_features == Mt ? "*"
627 : gpos_features == Mnil ? NULL
628 : msymbol_name (gpos_features));
630 g = gstring->glyphs[from];
633 for (i = from + 1; i < to; i++)
635 if (from_pos > gstring->glyphs[i].pos)
636 from_pos = gstring->glyphs[i].pos;
637 if (to_pos < gstring->glyphs[i].to)
638 to_pos = gstring->glyphs[i].to;
641 unitsPerEm = otf->head->unitsPerEm;
642 otf_gstring.size = otf_gstring.used = len;
643 otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
644 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
645 for (i = 0; i < len; i++)
647 if (gstring->glyphs[from + i].otf_encoded)
649 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
650 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
654 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
658 if (OTF_drive_tables (otf, &otf_gstring, script_name, language_name,
659 gsub_feature_names, gpos_feature_names) < 0)
663 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
665 g.combining_code = 0;
669 g.code = otfg->glyph_id;
670 switch (otfg->positioning_type)
674 int off_x = 128, off_y = 128;
676 if (otfg->f.f1.format & OTF_XPlacement)
677 off_x = ((double) (otfg->f.f1.value->XPlacement)
678 * 100 / unitsPerEm + 128);
679 if (otfg->f.f1.format & OTF_YPlacement)
680 off_y = ((double) (otfg->f.f1.value->YPlacement)
681 * 100 / unitsPerEm + 128);
683 = MAKE_COMBINING_CODE (3, 2, 3, 0, off_y, off_x);
684 if ((otfg->f.f1.format & OTF_XAdvance)
685 || (otfg->f.f1.format & OTF_YAdvance))
690 /* Not yet supported. */
696 off_x = ((double) (otfg->f.f4.base_anchor->XCoordinate
697 - otfg->f.f4.mark_anchor->XCoordinate)
698 * 100 / unitsPerEm + 128);
699 off_y = ((double) (otfg->f.f4.base_anchor->YCoordinate
700 - otfg->f.f4.mark_anchor->YCoordinate)
701 * 100 / unitsPerEm + 128);
703 = MAKE_COMBINING_CODE (3, 0, 3, 0, off_y, off_x);
707 /* Not yet supported. */
709 default: /* i.e case 6 */
710 /* Not yet supported. */
720 MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
725 #endif /* HAVE_OTF */
726 for (i = 0; i < len; i++)
728 g = gstring->glyphs[from + i];
729 MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
735 mfont__ft_decode_otf (MGlyph *g)
738 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
739 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
742 #else /* not HAVE_OTF */
744 #endif /* not HAVE_OTF */
747 #else /* not HAVE_FREETYPE */
760 #endif /* HAVE_FREETYPE */