2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2011 Navit Team
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
20 #ifdef HAVE_FONTCONFIG
21 #include <fontconfig/fontconfig.h>
25 #include FT_FREETYPE_H
35 #include <freetype/ftglyph.h>
42 #include "font_freetype.h"
44 #ifndef HAVE_LOOKUP_SCALER
45 #if FREETYPE_MAJOR * 10000 + FREETYPE_MINOR * 100 + FREETYPE_PATCH > 20304
46 #define HAVE_LOOKUP_SCALER 1
48 #define HAVE_LOOKUP_SCALER 0
52 struct font_freetype_font {
55 #if HAVE_LOOKUP_SCALER
58 FTC_ImageTypeRec scaler;
70 static struct font_priv dummy;
71 static FT_Library library;
73 static FTC_Manager manager;
74 static FTC_ImageCache image_cache;
75 static FTC_CMapCache charmap_cache;
76 static FTC_SBitCache sbit_cache;
78 static int library_init;
82 font_freetype_get_text_bbox(struct graphics_priv *gr,
83 struct font_freetype_font *font, char *text,
84 int dx, int dy, struct point *ret,
95 int n, len, x = 0, y = 0;
110 len = g_utf8_strlen(text, -1);
114 bbox.yMax = 13*font->size/256;
115 bbox.xMax = 9*font->size*len/256;
117 bbox.xMin = bbox.yMin = 32000;
118 bbox.xMax = bbox.yMax = -32000;
120 FT_Set_Transform(font->face, &matrix, &pen);
122 for (n = 0; n < len; n++) {
125 FTC_Node anode = NULL;
126 FT_Glyph cached_glyph;
127 glyph_index = FTC_CMapCache_Lookup(charmap_cache, font->scaler.face_id, font->charmap_index, g_utf8_get_char(p));
128 #if HAVE_LOOKUP_SCALER
129 FTC_ImageCache_LookupScaler(image_cache, &font->scaler, FT_LOAD_DEFAULT, glyph_index, &cached_glyph, &anode);
131 FTC_ImageCache_Lookup(image_cache, &font->scaler, glyph_index, &cached_glyph, &anode);
133 FT_Glyph_Copy(cached_glyph, &glyph);
134 FT_Glyph_Transform(glyph, &matrix, &pen);
136 glyph_index = FT_Get_Char_Index(font->face, g_utf8_get_char(p));
137 FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT);
138 FT_Get_Glyph(font->face->glyph, &glyph);
140 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox);
142 glyph_bbox.xMin += x >> 6;
143 glyph_bbox.xMax += x >> 6;
144 glyph_bbox.yMin += y >> 6;
145 glyph_bbox.yMax += y >> 6;
146 x += glyph->advance.x >> 10;
147 y -= glyph->advance.y >> 10;
148 if (glyph_bbox.xMin < bbox.xMin)
149 bbox.xMin = glyph_bbox.xMin;
150 if (glyph_bbox.yMin < bbox.yMin)
151 bbox.yMin = glyph_bbox.yMin;
152 if (glyph_bbox.xMax > bbox.xMax)
153 bbox.xMax = glyph_bbox.xMax;
154 if (glyph_bbox.yMax > bbox.yMax)
155 bbox.yMax = glyph_bbox.yMax;
156 p = g_utf8_next_char(p);
158 FT_Done_Glyph(glyph);
159 FTC_Node_Unref(anode, manager);
161 FT_Done_Glyph(glyph);
164 if (bbox.xMin > bbox.xMax) {
171 ret[0].x = bbox.xMin;
172 ret[0].y = -bbox.yMin;
173 ret[1].x = bbox.xMin;
174 ret[1].y = -bbox.yMax;
175 ret[2].x = bbox.xMax;
176 ret[2].y = -bbox.yMax;
177 ret[3].x = bbox.xMax;
178 ret[3].y = -bbox.yMin;
179 if (dy != 0 || dx != 0x10000) {
180 for (i = 0 ; i < 4 ; i++) {
182 ret[i].x=(pt.x*dx-pt.y*dy)/0x10000;
183 ret[i].y=(pt.y*dx+pt.x*dy)/0x10000;
188 static struct font_freetype_text *
189 font_freetype_text_new(char *text, struct font_freetype_font *font, int dx,
195 int y, n, len, w, h, pixmap_len;
196 struct font_freetype_text *ret;
197 struct font_freetype_glyph *curr;
199 unsigned char *gl, *pm;
200 FT_BitmapGlyph glyph_bitmap;
203 len = g_utf8_strlen(text, -1);
204 ret = g_malloc(sizeof(*ret) + len * sizeof(struct text_glyph *));
205 ret->glyph_count = len;
215 FT_Set_Transform(font->face, &matrix, &pen);
219 // Need to use fribidi to handle the string properly
220 char visual_text[len*4+1];
222 FriBidiChar unicode_text[len+2];
223 FriBidiChar visual_unicode_text[len+2];
224 FriBidiStrIndex textlen = strlen(text);
226 FriBidiCharType base = FRIBIDI_TYPE_LTR;
228 FriBidiParType base = FRIBIDI_PAR_LTR;
231 FriBidiStrIndex unicode_len =
233 fribidi_utf8_to_unicode(text, textlen, unicode_text);
235 fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, text, textlen, unicode_text);
237 fribidi_log2vis(unicode_text, unicode_len, &base, visual_unicode_text, NULL, NULL, NULL);
238 // TODO: check return value
240 fribidi_unicode_to_utf8(visual_unicode_text, unicode_len, visual_text);
242 fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, visual_unicode_text, unicode_len, visual_text);
246 #endif /* USE_FRIBIDI */
248 for (n = 0; n < len; n++) {
252 FT_Glyph cached_glyph;
253 glyph_index = FTC_CMapCache_Lookup(charmap_cache, font->scaler.face_id, font->charmap_index, g_utf8_get_char(p));
254 #if HAVE_LOOKUP_SCALER
255 FTC_ImageCache_LookupScaler(image_cache, &font->scaler, FT_LOAD_DEFAULT, glyph_index, &cached_glyph, &anode);
257 FTC_ImageCache_Lookup(image_cache, &font->scaler, glyph_index, &cached_glyph, &anode);
259 FT_Glyph_Copy(cached_glyph, &glyph);
260 FT_Glyph_Transform(glyph, &matrix, &pen);
261 FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, NULL, TRUE);
263 glyph_index = FT_Get_Char_Index(font->face, g_utf8_get_char(p));
264 FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT);
265 FT_Get_Glyph(font->face->glyph, &glyph);
267 FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, NULL, TRUE);
268 glyph_bitmap = (FT_BitmapGlyph)glyph;
270 w = glyph_bitmap->bitmap.width;
271 h = glyph_bitmap->bitmap.rows;
273 pixmap_len = (w + 2) * (h + 2);
276 curr = g_malloc0(sizeof(*curr) + pixmap_len);
281 curr->pixmap = (unsigned char *) (curr + 1);
282 ret->glyph[n] = curr;
284 curr->x = glyph_bitmap->left << 6;
285 curr->y = -glyph_bitmap->top << 6;
286 for (y = 0; y < h; y++) {
287 gl = glyph_bitmap->bitmap.buffer + y * glyph_bitmap->bitmap.pitch;
288 pm = curr->pixmap + y * w;
292 curr->dx = glyph->advance.x >> 10;
293 curr->dy = -glyph->advance.y >> 10;
294 FT_Done_Glyph(glyph);
296 FTC_Node_Unref(anode, manager);
298 p = g_utf8_next_char(p);
300 ret->glyph_count = len;
305 * List of font families to use, in order of preference
307 static char *fontfamilies[] = {
318 font_destroy(struct graphics_font_priv *font)
321 /* TODO: free font->face */
324 static struct graphics_font_methods font_methods = {
330 font_freetype_text_destroy(struct font_freetype_text *text)
333 struct font_freetype_glyph **gp;
336 i = text->glyph_count;
343 static FT_Error face_requester( FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face* aface )
346 char *fontfile,*fontindex;
348 return FT_Err_Invalid_Handle;
349 fontfile=g_strdup((char *)face_id);
350 dbg(1,"fontfile=%s\n", fontfile);
351 fontindex=strrchr(fontfile,'/');
354 return FT_Err_Invalid_Handle;
357 dbg(1,"new face %s %d\n", fontfile, atoi(fontindex));
358 ret = FT_New_Face( library, fontfile, atoi(fontindex), aface );
360 dbg(0,"Error while creating freetype face: %d\n", ret);
363 if((ret = FT_Select_Charmap(*aface, FT_ENCODING_UNICODE))) {
364 dbg(0,"Error while creating freetype face: %d\n", ret);
371 * Load a new font using the fontconfig library.
372 * First search for each of the font families and require and exact match on family
373 * If no font found, let fontconfig pick the best match
374 * @param graphics_priv FIXME
375 * @param graphics_font_methods FIXME
376 * @param fontfamily the preferred font family
377 * @param size requested size of fonts
378 * @param flags extra flags for the font (bold,etc)
381 static struct font_freetype_font *
382 font_freetype_font_new(struct graphics_priv *gr,
383 struct graphics_font_methods *meth,
384 char *fontfamily, int size, int flags)
386 struct font_freetype_font *font =
387 g_new(struct font_freetype_font, 1);
389 char **family, **family_sav;
394 #ifndef HAVE_FONTCONFIG
397 *meth = font_methods;
400 FT_Init_FreeType(&library);
402 FTC_Manager_New( library, 0, 0, 0, &face_requester, NULL, &manager);
403 FTC_ImageCache_New( manager, &image_cache);
404 FTC_CMapCache_New( manager, &charmap_cache);
405 FTC_SBitCache_New( manager, &sbit_cache);
410 #ifdef HAVE_FONTCONFIG
411 dbg(2, " about to search for fonts, preferred = %s\n", fontfamily);
412 family = g_malloc(sizeof(fontfamilies) + sizeof(fontfamily));
414 memcpy(family, &fontfamily, sizeof(fontfamily));
415 memcpy(family + 1, fontfamilies, sizeof(fontfamilies));
417 memcpy(family, fontfamilies, sizeof(fontfamilies));
420 for (exact = 1; !found && exact >= 0; exact--) {
424 while (*family && !found) {
425 dbg(2, "Looking for font family %s. exact=%d\n",
427 FcPattern *required =
428 FcPatternBuild(NULL, FC_FAMILY, FcTypeString,
431 FcPatternAddInteger(required, FC_WEIGHT,
433 FcConfigSubstitute(FcConfigGetCurrent(), required,
435 FcDefaultSubstitute(required);
438 FcFontMatch(FcConfigGetCurrent(), required,
444 FcPatternGet(required, FC_FAMILY, 0, &v1);
445 FcPatternGet(matched, FC_FAMILY, 0, &v2);
447 FcPatternGetString(matched, FC_FILE, 0,
450 FcPatternGetInteger(matched, FC_INDEX,
452 if ((r1 == FcResultMatch)
453 && (r2 == FcResultMatch)
454 && (FcValueEqual(v1, v2) || !exact)) {
456 "About to load font from file %s index %d\n",
457 fontfile, fontindex);
459 idstr=g_strdup_printf("%s/%d", fontfile, fontindex);
460 font->scaler.face_id=(FTC_FaceID)atom(idstr);
462 #if HAVE_LOOKUP_SCALER
463 font->scaler.width=0;
464 font->scaler.height=size;
465 font->scaler.pixel=0;
466 font->scaler.x_res=300;
467 font->scaler.y_res=300;
469 font->scaler.width=size/15;
470 font->scaler.height=size/15;
471 font->scaler.flags=FT_LOAD_DEFAULT;
473 FTC_Manager_LookupFace(manager, font->scaler.face_id, &face);
474 font->charmap_index=face->charmap ? FT_Get_Charmap_Index(face->charmap) : 0;
475 #else /* USE_CACHING */
480 #endif /* USE_CACHING */
483 FcPatternDestroy(matched);
485 FcPatternDestroy(required);
490 #else /* HAVE_FONTCONFIG */
491 #ifdef FREETYPE_FONTS
493 char *fonts[]={FREETYPE_FONTS};
494 name=g_strdup(fonts[flags ? 1:0]);
497 name=g_strdup_printf("%s/fonts/%s-%s.ttf",getenv("NAVIT_SHAREDIR"),"LiberationSans",flags ? "Bold":"Regular");
501 idstr=g_strdup_printf("%s/%d", name, 0);
502 font->scaler.face_id=(FTC_FaceID)atom(idstr);
504 FTC_Manager_LookupFace(manager, font->scaler.face_id, &face);
505 font->charmap_index=face->charmap ? FT_Get_Charmap_Index(face->charmap) : 0;
506 #if HAVE_LOOKUP_SCALER
507 font->scaler.width=0;
508 font->scaler.height=size;
509 font->scaler.pixel=0;
510 font->scaler.x_res=300;
511 font->scaler.y_res=300;
513 font->scaler.width=size/15;
514 font->scaler.height=size/15;
515 font->scaler.flags=FT_LOAD_DEFAULT;
518 FTC_Manager_LookupFace(manager, font->scaler.face_id, &face);
519 font->charmap_index=face->charmap ? FT_Get_Charmap_Index(face->charmap) : 0;
520 #else /* USE_CACHING */
521 if (!FT_New_Face(library, name, 0, &font->face))
523 #endif /* USE_CACHING */
525 #endif /* HAVE_FONTCONFIG */
527 dbg(0,"Failed to load font, no labelling\n");
532 FT_Set_Char_Size(font->face, 0, size, 300, 300);
533 FT_Select_Charmap(font->face, FT_ENCODING_UNICODE);
539 font_freetype_glyph_get_shadow(struct font_freetype_glyph *g,
540 unsigned char *data, int depth, int stride, struct color *foreground, struct color *background)
542 int mask0, mask1, mask2, x, y, w = g->w, h = g->h;
544 unsigned char *pm, *psp,*ps,*psn;
556 fg=((foreground->a>>8)<<24)|
557 ((foreground->r>>8)<<16)|
558 ((foreground->g>>8)<<8)|
559 ((foreground->b>>8)<<0);
560 bg=((background->a>>8)<<24)|
561 ((background->r>>8)<<16)|
562 ((background->g>>8)<<8)|
563 ((background->b>>8)<<0);
568 for (y = 0; y < h+2; y++) {
570 ps = data + stride * y;
572 unsigned char **dataptr=(unsigned char **)data;
577 memset(ps, bg, (w+9)/2);
583 for (x = 0 ; x < w+2 ; x++) {
590 for (x = 0 ; x < w+2 ; x++)
591 ((unsigned int *)ps)[x]=bg;
595 for (y = 0; y < h; y++) {
596 pm = g->pixmap + y * w;
598 psp = data + stride * y;
602 unsigned char **dataptr=(unsigned char **)data;
612 for (x = 0; x < w; x++) {
614 psp[0] |= (mask0 >> 8);
617 ps[0] |= (mask1 >> 8);
620 psn[0] |= (mask2 >> 8);
628 ((mask0 >> 8) | (mask1 >> 8) |
641 for (x = 0; x < w; x++) {
656 for (x = 0; x < w; x++) {
681 for (x = 0; x < w; x++) {
683 ((unsigned int *)psp)[1]=fg;
684 ((unsigned int *)ps)[0]=fg;
685 ((unsigned int *)ps)[1]=fg;
686 ((unsigned int *)ps)[2]=fg;
687 ((unsigned int *)psn)[1]=fg;
701 font_freetype_glyph_get_glyph(struct font_freetype_glyph *g,
702 unsigned char *data, int depth, int stride, struct color *fg, struct color *bg, struct color *transparent)
704 int x, y, w = g->w, h = g->h;
706 unsigned char v,vi,*pm, *ps;
709 tr=transparent->a>>8;
713 tr=((transparent->a>>8)<<24)|
714 ((transparent->r>>8)<<16)|
715 ((transparent->g>>8)<<8)|
716 ((transparent->b>>8)<<0);
721 for (y = 0; y < h; y++) {
722 pm = g->pixmap + y * w;
724 ps = data + stride*y;
726 unsigned char **dataptr=(unsigned char **)data;
731 for (x = 0; x < w; x++) {
742 for (x = 0; x < w; x++) {
746 ps[0]=(((fg->r*v+bg->r*vi)/255)>>8);
747 ps[1]=(((fg->g*v+bg->g*vi)/255)>>8);
748 ps[2]=(((fg->b*v+bg->b*vi)/255)>>8);
759 for (x = 0; x < w; x++) {
763 ((unsigned int *)ps)[0]=
764 ((((fg->a*v+bg->a*vi)/255)>>8)<<24)|
765 ((((fg->r*v+bg->r*vi)/255)>>8)<<16)|
766 ((((fg->g*v+bg->g*vi)/255)>>8)<<8)|
767 ((((fg->b*v+bg->b*vi)/255)>>8)<<0);
769 ((unsigned int *)ps)[0]=tr;
779 static struct font_freetype_methods methods = {
780 font_freetype_font_new,
781 font_freetype_get_text_bbox,
782 font_freetype_text_new,
783 font_freetype_text_destroy,
784 font_freetype_glyph_get_shadow,
785 font_freetype_glyph_get_glyph,
788 static struct font_priv *
789 font_freetype_new(void *meth)
791 *((struct font_freetype_methods *) meth) = methods;
798 plugin_register_font_type("freetype", font_freetype_new);
799 #ifdef HAVE_FONTCONFIG