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" } };
626 if (FT_Init_FreeType (&ft_library) != 0)
627 MERROR (MERROR_FONT_FT, -1);
629 ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
630 MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
631 for (i = 0; i < ft_to_prop_size; i++)
633 ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
634 ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
635 ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
636 ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
639 mfont__driver_list[MFONT_TYPE_FT] = &ft_driver;
651 MPLIST_DO (plist, ft_font_list)
653 MFTInfo *ft_info = (MFTInfo *) MPLIST_VAL (plist);
654 free (ft_info->filename);
655 M17N_OBJECT_UNREF (ft_info->charmap_list);
658 M17N_OBJECT_UNREF (ft_font_list);
662 FT_Done_FreeType (ft_library);
667 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
668 MRealizedFont *rfont,
669 MSymbol script, MSymbol langsys,
670 MSymbol gsub_features, MSymbol gpos_features)
678 OTF_GlyphString otf_gstring;
680 char *script_name, *language_name;
681 char *gsub_feature_names, *gpos_feature_names;
682 int from_pos, to_pos;
688 ft_info = (MFTInfo *) rfont->info;
689 if (ft_info->otf_flag < 0)
692 if (! otf && (otf = OTF_open (ft_info->filename)))
694 if (OTF_get_table (otf, "head") < 0
695 || (OTF_check_table (otf, "GSUB") < 0
696 && OTF_check_table (otf, "GPOS") < 0))
699 ft_info->otf_flag = -1;
706 script_name = msymbol_name (script);
707 language_name = langsys != Mnil ? msymbol_name (langsys) : NULL;
709 = (gsub_features == Mt ? "*"
710 : gsub_features == Mnil ? NULL
711 : msymbol_name (gsub_features));
713 = (gpos_features == Mt ? "*"
714 : gpos_features == Mnil ? NULL
715 : msymbol_name (gpos_features));
717 g = gstring->glyphs[from];
720 for (i = from + 1; i < to; i++)
722 if (from_pos > gstring->glyphs[i].pos)
723 from_pos = gstring->glyphs[i].pos;
724 if (to_pos < gstring->glyphs[i].to)
725 to_pos = gstring->glyphs[i].to;
728 unitsPerEm = otf->head->unitsPerEm;
729 otf_gstring.size = otf_gstring.used = len;
730 otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
731 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
732 for (i = 0; i < len; i++)
734 if (gstring->glyphs[from + i].otf_encoded)
736 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
737 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
741 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
745 if (OTF_drive_tables (otf, &otf_gstring, script_name, language_name,
746 gsub_feature_names, gpos_feature_names) < 0)
750 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
752 g.combining_code = 0;
756 g.code = otfg->glyph_id;
757 switch (otfg->positioning_type)
761 int off_x = 128, off_y = 128;
763 if (otfg->f.f1.format & OTF_XPlacement)
764 off_x = ((double) (otfg->f.f1.value->XPlacement)
765 * 100 / unitsPerEm + 128);
766 if (otfg->f.f1.format & OTF_YPlacement)
767 off_y = ((double) (otfg->f.f1.value->YPlacement)
768 * 100 / unitsPerEm + 128);
770 = MAKE_COMBINING_CODE (3, 2, 3, 0, off_y, off_x);
771 if ((otfg->f.f1.format & OTF_XAdvance)
772 || (otfg->f.f1.format & OTF_YAdvance))
777 /* Not yet supported. */
783 off_x = ((double) (otfg->f.f4.base_anchor->XCoordinate
784 - otfg->f.f4.mark_anchor->XCoordinate)
785 * 100 / unitsPerEm + 128);
786 off_y = ((double) (otfg->f.f4.base_anchor->YCoordinate
787 - otfg->f.f4.mark_anchor->YCoordinate)
788 * 100 / unitsPerEm + 128);
790 = MAKE_COMBINING_CODE (3, 0, 3, 0, off_y, off_x);
794 /* Not yet supported. */
796 default: /* i.e case 6 */
797 /* Not yet supported. */
807 MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
812 #endif /* HAVE_OTF */
813 for (i = 0; i < len; i++)
815 g = gstring->glyphs[from + i];
816 MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
822 mfont__ft_decode_otf (MGlyph *g)
825 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
826 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
829 #else /* not HAVE_OTF */
831 #endif /* not HAVE_OTF */
834 #else /* not HAVE_FREETYPE */
847 #endif /* HAVE_FREETYPE */