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 *, MGlyphString *, int, int);
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, MGlyphString *gstring,
406 MFTInfo *ft_info = (MFTInfo *) rfont->info;
407 FT_Face ft_face = ft_info->ft_face;
408 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
409 FT_Int32 load_flags = FT_LOAD_RENDER;
411 if (! gstring->anti_alias)
413 #ifdef FT_LOAD_TARGET_MONO
414 load_flags |= FT_LOAD_TARGET_MONO;
416 load_flags |= FT_LOAD_MONOCHROME;
420 for (; g != gend; g++)
422 if (g->code == MCHAR_INVALID_CODE)
424 unsigned unitsPerEm = ft_face->units_per_EM;
425 int size = rfont->font.property[MFONT_SIZE] / 10;
428 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
429 g->width = ft_face->max_advance_width * size / unitsPerEm;
430 g->ascent = ft_face->ascender * size / unitsPerEm;
431 g->descent = (- ft_face->descender) * size / unitsPerEm;
435 FT_Glyph_Metrics *metrics;
441 code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
443 FT_Load_Glyph (ft_face, code, FT_LOAD_RENDER);
444 metrics = &ft_face->glyph->metrics;
445 g->lbearing = (metrics->horiBearingX >> 6);
446 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
447 g->width = metrics->horiAdvance >> 6;
448 g->ascent = metrics->horiBearingY >> 6;
449 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
454 /* The FreeType font driver function ENCODE_CHAR. */
457 ft_encode_char (MRealizedFont *rfont, int c, unsigned ignored)
462 if (rfont->status == 0)
464 if (ft_open (rfont) < 0)
467 ft_info = (MFTInfo *) rfont->info;
468 code = FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) c);
470 return MCHAR_INVALID_CODE;
472 FT_Load_Glyph (ft_info->ft_face, code, FT_LOAD_NO_SCALE);
473 return (ft_info->ft_face->glyph->metrics.width > 0
474 ? (unsigned) c : MCHAR_INVALID_CODE);
476 return ((unsigned) c);
480 /* The FreeType font driver function RENDER. */
482 #define NUM_POINTS 0x1000
485 MDrawPoint points[NUM_POINTS];
490 ft_render (MDrawWindow win, int x, int y,
491 MGlyphString *gstring, MGlyph *from, MGlyph *to,
492 int reverse, MDrawRegion region)
494 MRealizedFace *rface = from->rface;
495 MFrame *frame = rface->frame;
497 FT_Face ft_face = NULL;
498 FT_Int32 load_flags = FT_LOAD_RENDER;
501 MPointTable point_table[8];
506 if (! gstring->anti_alias)
508 #ifdef FT_LOAD_TARGET_MONO
509 load_flags |= FT_LOAD_TARGET_MONO;
511 load_flags |= FT_LOAD_MONOCHROME;
515 /* It is assured that the all glyphs in the current range use the
516 same realized face. */
517 ft_info = (MFTInfo *) rface->rfont->info;
518 ft_face = ft_info->ft_face;
520 for (i = 0; i < 8; i++)
521 point_table[i].p = point_table[i].points;
523 for (g = from; g < to; x += g++->width)
534 code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
535 FT_Load_Glyph (ft_face, code, load_flags);
536 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
537 bmp = ft_face->glyph->bitmap.buffer;
538 if (gstring->anti_alias)
539 for (i = 0; i < ft_face->glyph->bitmap.rows;
540 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
542 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
543 for (j = 0; j < ft_face->glyph->bitmap.width; j++, xoff++)
545 intensity = bmp[j] >> 5;
548 ptable = point_table + intensity;
552 if (ptable->p - ptable->points == NUM_POINTS)
554 mwin__draw_points (frame, win, rface,
555 reverse ? 7 - intensity : intensity,
556 ptable->points, NUM_POINTS, region);
557 ptable->p = ptable->points;
563 for (i = 0; i < ft_face->glyph->bitmap.rows;
564 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
566 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
567 for (j = 0; j < ft_face->glyph->bitmap.width; j++, xoff++)
569 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
572 ptable = point_table;
576 if (ptable->p - ptable->points == NUM_POINTS)
578 mwin__draw_points (frame, win, rface,
580 ptable->points, NUM_POINTS, region);
581 ptable->p = ptable->points;
588 if (gstring->anti_alias)
590 for (i = 1; i < 8; i++)
591 if (point_table[i].p != point_table[i].points)
592 mwin__draw_points (frame, win, rface, reverse ? 7 - i : i,
593 point_table[i].points,
594 point_table[i].p - point_table[i].points, region);
598 if (point_table[0].p != point_table[0].points)
599 mwin__draw_points (frame, win, rface, reverse ? 0 : 7,
600 point_table[0].points,
601 point_table[0].p - point_table[0].points, region);
612 char *weight, *style, *stretch;
613 } ft_to_prop_name[] =
614 { { "regular", "medium", "r", "normal" },
615 { "italic", "medium", "i", "normal" },
616 { "bold", "bold", "r", "normal" },
617 { "bold italic", "bold", "i", "normal" },
618 { "narrow", "medium", "r", "condensed" },
619 { "narrow italic", "medium", "i", "condensed" },
620 { "narrow bold", "bold", "r", "condensed" },
621 { "narrow bold italic", "bold", "i", "condensed" },
622 { "black", "black", "r", "normal" },
623 { "black italic", "black", "i", "normal" },
624 { "oblique", "medium", "o", "normal" },
625 { "boldoblique", "bold", "o", "normal" } };
628 if (FT_Init_FreeType (&ft_library) != 0)
629 MERROR (MERROR_FONT_FT, -1);
631 ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
632 MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
633 for (i = 0; i < ft_to_prop_size; i++)
635 ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
636 ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
637 ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
638 ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
641 mfont__driver_list[MFONT_TYPE_FT] = &ft_driver;
653 MPLIST_DO (plist, ft_font_list)
655 MFTInfo *ft_info = (MFTInfo *) MPLIST_VAL (plist);
656 free (ft_info->filename);
657 M17N_OBJECT_UNREF (ft_info->charmap_list);
660 M17N_OBJECT_UNREF (ft_font_list);
664 FT_Done_FreeType (ft_library);
669 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
670 MRealizedFont *rfont,
671 MSymbol script, MSymbol langsys,
672 MSymbol gsub_features, MSymbol gpos_features)
680 OTF_GlyphString otf_gstring;
682 char *script_name, *language_name;
683 char *gsub_feature_names, *gpos_feature_names;
684 int from_pos, to_pos;
690 ft_info = (MFTInfo *) rfont->info;
691 if (ft_info->otf_flag < 0)
694 if (! otf && (otf = OTF_open (ft_info->filename)))
696 if (OTF_get_table (otf, "head") < 0
697 || (OTF_check_table (otf, "GSUB") < 0
698 && OTF_check_table (otf, "GPOS") < 0))
701 ft_info->otf_flag = -1;
708 script_name = msymbol_name (script);
709 language_name = langsys != Mnil ? msymbol_name (langsys) : NULL;
711 = (gsub_features == Mt ? "*"
712 : gsub_features == Mnil ? NULL
713 : msymbol_name (gsub_features));
715 = (gpos_features == Mt ? "*"
716 : gpos_features == Mnil ? NULL
717 : msymbol_name (gpos_features));
719 g = gstring->glyphs[from];
722 for (i = from + 1; i < to; i++)
724 if (from_pos > gstring->glyphs[i].pos)
725 from_pos = gstring->glyphs[i].pos;
726 if (to_pos < gstring->glyphs[i].to)
727 to_pos = gstring->glyphs[i].to;
730 unitsPerEm = otf->head->unitsPerEm;
731 otf_gstring.size = otf_gstring.used = len;
732 otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
733 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
734 for (i = 0; i < len; i++)
736 if (gstring->glyphs[from + i].otf_encoded)
738 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
739 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
743 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
747 if (OTF_drive_tables (otf, &otf_gstring, script_name, language_name,
748 gsub_feature_names, gpos_feature_names) < 0)
752 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
754 g.combining_code = 0;
758 g.code = otfg->glyph_id;
759 switch (otfg->positioning_type)
763 int off_x = 128, off_y = 128;
765 if (otfg->f.f1.format & OTF_XPlacement)
766 off_x = ((double) (otfg->f.f1.value->XPlacement)
767 * 100 / unitsPerEm + 128);
768 if (otfg->f.f1.format & OTF_YPlacement)
769 off_y = ((double) (otfg->f.f1.value->YPlacement)
770 * 100 / unitsPerEm + 128);
772 = MAKE_COMBINING_CODE (3, 2, 3, 0, off_y, off_x);
773 if ((otfg->f.f1.format & OTF_XAdvance)
774 || (otfg->f.f1.format & OTF_YAdvance))
779 /* Not yet supported. */
785 off_x = ((double) (otfg->f.f4.base_anchor->XCoordinate
786 - otfg->f.f4.mark_anchor->XCoordinate)
787 * 100 / unitsPerEm + 128);
788 off_y = ((double) (otfg->f.f4.base_anchor->YCoordinate
789 - otfg->f.f4.mark_anchor->YCoordinate)
790 * 100 / unitsPerEm + 128);
792 = MAKE_COMBINING_CODE (3, 0, 3, 0, off_y, off_x);
796 /* Not yet supported. */
798 default: /* i.e case 6 */
799 /* Not yet supported. */
809 MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
814 #endif /* HAVE_OTF */
815 for (i = 0; i < len; i++)
817 g = gstring->glyphs[from + i];
818 MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
824 mfont__ft_decode_otf (MGlyph *g)
827 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
828 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
831 #else /* not HAVE_OTF */
833 #endif /* not HAVE_OTF */
836 #else /* not HAVE_FREETYPE */
849 #endif /* HAVE_FREETYPE */