4a3317df51e59357a2ae2e8e5bfe5782a7d2d9f3
[profile/ivi/navit.git] / navit / navit / font / freetype / font_freetype.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2011 Navit Team
4  *
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.
8  *
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.
13  *
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.
18  */
19 #include "config.h"
20 #ifdef HAVE_FONTCONFIG
21 #include <fontconfig/fontconfig.h>
22 #endif
23 #include <ft2build.h>
24 #include <glib.h>
25 #include FT_FREETYPE_H
26 #ifndef USE_CACHING
27 #define USE_CACHING 1
28 #endif
29 #if USE_CACHING
30 #include FT_CACHE_H
31 #endif
32 #if USE_FRIBIDI
33 #include <fribidi.h>
34 #endif
35 #include <freetype/ftglyph.h>
36 #include "point.h"
37 #include "graphics.h"
38 #include "debug.h"
39 #include "plugin.h"
40 #include "color.h"
41 #include "atom.h"
42 #include "font_freetype.h"
43
44 #ifndef HAVE_LOOKUP_SCALER
45 #if FREETYPE_MAJOR * 10000 + FREETYPE_MINOR * 100 + FREETYPE_PATCH > 20304
46 #define HAVE_LOOKUP_SCALER 1
47 #else
48 #define HAVE_LOOKUP_SCALER 0
49 #endif
50 #endif
51
52 struct font_freetype_font {
53         int size;
54 #if USE_CACHING
55 #if HAVE_LOOKUP_SCALER
56         FTC_ScalerRec scaler;
57 #else
58         FTC_ImageTypeRec scaler;
59 #endif
60         int charmap_index;
61 #else
62         FT_Face face;
63 #endif
64 };
65
66 struct font_priv {
67 };
68
69 static struct font_priv dummy;
70 static FT_Library library;
71 #if USE_CACHING
72 static FTC_Manager manager;
73 static FTC_ImageCache image_cache;
74 static FTC_CMapCache charmap_cache;
75 static FTC_SBitCache sbit_cache;
76 #endif
77 static int library_init;
78
79
80 static void
81 font_freetype_get_text_bbox(struct graphics_priv *gr,
82                             struct font_freetype_font *font, char *text,
83                             int dx, int dy, struct point *ret,
84                             int estimate)
85 {
86         char *p = text;
87         FT_BBox bbox;
88         FT_UInt glyph_index;
89         FT_Glyph glyph;
90         FT_Matrix matrix;
91         FT_Vector pen;
92         pen.x = 0 * 64;
93         pen.y = 0 * 64;
94         int i;
95         struct point pt;
96 #if 0
97         matrix.xx = dx;
98         matrix.xy = dy;
99         matrix.yx = -dy;
100         matrix.yy = dx;
101 #else
102         matrix.xx = 0x10000;
103         matrix.xy = 0;
104         matrix.yx = 0;
105         matrix.yy = 0x10000;
106 #endif
107         int n, len, x = 0, y = 0;
108
109         len = g_utf8_strlen(text, -1);
110         if (estimate) {
111                 bbox.xMin = 0;
112                 bbox.yMin = 0;
113                 bbox.yMax = 13*font->size/256;
114                 bbox.xMax = 9*font->size*len/256;
115         } else {
116                 bbox.xMin = bbox.yMin = 32000;
117                 bbox.xMax = bbox.yMax = -32000;
118 #if !USE_CACHING
119                 FT_Set_Transform(font->face, &matrix, &pen);
120 #endif
121                 for (n = 0; n < len; n++) {
122                         FT_BBox glyph_bbox;
123 #if USE_CACHING
124                         FTC_Node anode = NULL;
125                         glyph_index = FTC_CMapCache_Lookup(charmap_cache, font->scaler.face_id, font->charmap_index, g_utf8_get_char(p));
126                         FT_Glyph cached_glyph;
127 #if HAVE_LOOKUP_SCALER
128                         FTC_ImageCache_LookupScaler(image_cache, &font->scaler, FT_LOAD_DEFAULT, glyph_index, &cached_glyph, &anode);
129 #else
130                         FTC_ImageCache_Lookup(image_cache, &font->scaler, glyph_index, &cached_glyph, &anode);
131 #endif
132                         FT_Glyph_Copy(cached_glyph, &glyph);
133                         FT_Glyph_Transform(glyph, &matrix, &pen);
134 #else
135                         glyph_index = FT_Get_Char_Index(font->face, g_utf8_get_char(p));
136                         FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT);
137                         FT_Get_Glyph(font->face->glyph, &glyph);
138 #endif
139                         FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox);
140
141                         glyph_bbox.xMin += x >> 6;
142                         glyph_bbox.xMax += x >> 6;
143                         glyph_bbox.yMin += y >> 6;
144                         glyph_bbox.yMax += y >> 6;
145                         x += glyph->advance.x >> 10;
146                         y -= glyph->advance.y >> 10;
147                         if (glyph_bbox.xMin < bbox.xMin)
148                                 bbox.xMin = glyph_bbox.xMin;
149                         if (glyph_bbox.yMin < bbox.yMin)
150                                 bbox.yMin = glyph_bbox.yMin;
151                         if (glyph_bbox.xMax > bbox.xMax)
152                                 bbox.xMax = glyph_bbox.xMax;
153                         if (glyph_bbox.yMax > bbox.yMax)
154                                 bbox.yMax = glyph_bbox.yMax;
155                         p = g_utf8_next_char(p);
156 #if USE_CACHING
157                         FT_Done_Glyph(glyph);
158                         FTC_Node_Unref(anode, manager);
159 #else
160                         FT_Done_Glyph(glyph);
161 #endif
162                 }
163                 if (bbox.xMin > bbox.xMax) {
164                         bbox.xMin = 0;
165                         bbox.yMin = 0;
166                         bbox.xMax = 0;
167                         bbox.yMax = 0;
168                 }
169         }
170         ret[0].x = bbox.xMin;
171         ret[0].y = -bbox.yMin;
172         ret[1].x = bbox.xMin;
173         ret[1].y = -bbox.yMax;
174         ret[2].x = bbox.xMax;
175         ret[2].y = -bbox.yMax;
176         ret[3].x = bbox.xMax;
177         ret[3].y = -bbox.yMin;
178         if (dy != 0 || dx != 0x10000) {
179                 for (i = 0 ; i < 4 ; i++) {
180                         pt=ret[i];
181                         ret[i].x=(pt.x*dx-pt.y*dy)/0x10000;
182                         ret[i].y=(pt.y*dx+pt.x*dy)/0x10000;
183                 }
184         }
185 }
186
187 static struct font_freetype_text *
188 font_freetype_text_new(char *text, struct font_freetype_font *font, int dx,
189                        int dy)
190 {
191         FT_Matrix matrix;
192         FT_Vector pen;
193         FT_UInt glyph_index;
194         int y, n, len, w, h, pixmap_len;
195         struct font_freetype_text *ret;
196         struct font_freetype_glyph *curr;
197         char *p = text;
198         unsigned char *gl, *pm;
199         FT_BitmapGlyph glyph_bitmap;
200         FT_Glyph glyph;
201
202         len = g_utf8_strlen(text, -1);
203         ret = g_malloc(sizeof(*ret) + len * sizeof(struct text_glyph *));
204         ret->glyph_count = len;
205
206         matrix.xx = dx;
207         matrix.xy = dy;
208         matrix.yx = -dy;
209         matrix.yy = dx;
210
211         pen.x = 0 * 64;
212         pen.y = 0 * 64;
213 #if !USE_CACHING
214         FT_Set_Transform(font->face, &matrix, &pen);
215 #endif
216
217 #if USE_FRIBIDI
218     // Need to use fribidi to handle the string properly
219     char visual_text[len*4+1];
220     {
221         FriBidiChar unicode_text[len+2];
222         FriBidiChar visual_unicode_text[len+2];
223         FriBidiStrIndex textlen =  strlen(text);
224 #ifdef FRIBIDIOLD
225         FriBidiCharType base = FRIBIDI_TYPE_LTR;
226 #else
227         FriBidiParType base = FRIBIDI_PAR_LTR;
228 #endif
229
230         FriBidiStrIndex unicode_len =
231 #ifdef FRIBIDIOLD
232                         fribidi_utf8_to_unicode(text, textlen, unicode_text);
233 #else
234                         fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, text, textlen, unicode_text);
235 #endif
236         fribidi_log2vis(unicode_text, unicode_len, &base, visual_unicode_text, NULL, NULL, NULL);
237         // TODO: check return value
238 #ifdef FRIBIDIOLD
239         fribidi_unicode_to_utf8(visual_unicode_text, unicode_len, visual_text);
240 #else
241         fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, visual_unicode_text, unicode_len, visual_text);
242 #endif
243         p = visual_text;
244     }
245 #endif /* USE_FRIBIDI */
246
247         for (n = 0; n < len; n++) {
248
249 #if USE_CACHING
250                 FTC_Node anode=NULL;
251                 FT_Glyph cached_glyph;
252                 glyph_index = FTC_CMapCache_Lookup(charmap_cache, font->scaler.face_id, font->charmap_index, g_utf8_get_char(p));
253 #if HAVE_LOOKUP_SCALER
254                 FTC_ImageCache_LookupScaler(image_cache, &font->scaler, FT_LOAD_DEFAULT, glyph_index, &cached_glyph, &anode);
255 #else
256                 FTC_ImageCache_Lookup(image_cache, &font->scaler, glyph_index, &cached_glyph, &anode);
257 #endif
258                 FT_Glyph_Copy(cached_glyph, &glyph);
259                 FT_Glyph_Transform(glyph, &matrix, &pen);
260                 FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, NULL, TRUE);
261 #else
262                 glyph_index = FT_Get_Char_Index(font->face, g_utf8_get_char(p));
263                 FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT);
264                 FT_Get_Glyph(font->face->glyph, &glyph);
265 #endif
266                 FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, NULL, TRUE);
267                 glyph_bitmap = (FT_BitmapGlyph)glyph;
268
269                 w = glyph_bitmap->bitmap.width;
270                 h = glyph_bitmap->bitmap.rows;
271                 if (w && h)
272                         pixmap_len = (w + 2) * (h + 2);
273                 else
274                         pixmap_len = 0;
275                 curr = g_malloc0(sizeof(*curr) + pixmap_len);
276                 if (pixmap_len) {
277                         curr->w = w;
278                         curr->h = h;
279                 }
280                 curr->pixmap = (unsigned char *) (curr + 1);
281                 ret->glyph[n] = curr;
282
283                 curr->x = glyph_bitmap->left << 6;
284                 curr->y = -glyph_bitmap->top << 6;
285                 for (y = 0; y < h; y++) {
286                         gl = glyph_bitmap->bitmap.buffer + y * glyph_bitmap->bitmap.pitch;
287                         pm = curr->pixmap + y * w;
288                         memcpy(pm, gl, w);
289                 }
290
291                 curr->dx = glyph->advance.x >> 10;
292                 curr->dy = -glyph->advance.y >> 10;
293                 FT_Done_Glyph(glyph);
294 #if USE_CACHING
295                 FTC_Node_Unref(anode, manager);
296 #endif
297                 p = g_utf8_next_char(p);
298         }
299         ret->glyph_count = len;
300         return ret;
301 }
302
303 /**
304  * List of font families to use, in order of preference
305  */
306 static char *fontfamilies[] = {
307         "Liberation Sans",
308         "Arial",
309         "NcrBI4nh",
310         "luximbi",
311         "FreeSans",
312         "DejaVu Sans",
313         NULL,
314 };
315
316 static void
317 font_destroy(struct graphics_font_priv *font)
318 {
319         g_free(font);
320         /* TODO: free font->face */
321 }
322
323 static struct graphics_font_methods font_methods = {
324         font_destroy
325 };
326
327
328 static void
329 font_freetype_text_destroy(struct font_freetype_text *text)
330 {
331         int i;
332         struct font_freetype_glyph **gp;
333
334         gp = text->glyph;
335         i = text->glyph_count;
336         while (i-- > 0)
337                 g_free(*gp++);
338         g_free(text);
339 }
340
341 #if USE_CACHING
342 static FT_Error face_requester( FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face* aface )
343 {
344         FT_Error ret;
345         char *fontfile,*fontindex;
346         if (! face_id)
347                 return FT_Err_Invalid_Handle;
348         fontfile=g_strdup((char *)face_id);
349         dbg(1,"fontfile=%s\n", fontfile);
350         fontindex=strrchr(fontfile,'/');
351         if (! fontindex) {
352                 g_free(fontfile);
353                 return FT_Err_Invalid_Handle;
354         }
355         *fontindex++='\0';
356         dbg(1,"new face %s %d\n", fontfile, atoi(fontindex));
357         ret = FT_New_Face( library, fontfile, atoi(fontindex), aface );
358         if(ret) {
359                dbg(0,"Error while creating freetype face: %d\n", ret);
360                return ret;
361         }
362         if((ret = FT_Select_Charmap(*aface, FT_ENCODING_UNICODE))) {
363                dbg(0,"Error while creating freetype face: %d\n", ret);
364         }
365         return 0;
366 }
367 #endif
368
369 /**
370  * Load a new font using the fontconfig library.
371  * First search for each of the font families and require and exact match on family
372  * If no font found, let fontconfig pick the best match
373  * @param graphics_priv FIXME
374  * @param graphics_font_methods FIXME
375  * @param fontfamily the preferred font family
376  * @param size requested size of fonts
377  * @param flags extra flags for the font (bold,etc)
378  * @returns <>
379 */
380 static struct font_freetype_font *
381 font_freetype_font_new(struct graphics_priv *gr,
382                        struct graphics_font_methods *meth,
383                        char *fontfamily, int size, int flags)
384 {
385         struct font_freetype_font *font =
386             g_new(struct font_freetype_font, 1);
387
388         *meth = font_methods;
389         int exact, found=0;
390         char **family, **family_sav;
391 #if USE_CACHING
392         char *idstr;
393         FT_Face face;
394 #endif
395 #ifndef HAVE_FONTCONFIG
396         char *name;
397 #endif
398
399         if (!library_init) {
400                 FT_Init_FreeType(&library);
401 #if USE_CACHING
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);
406 #endif
407                 library_init = 1;
408         }
409         font->size=size;
410 #ifdef HAVE_FONTCONFIG
411         dbg(2, " about to search for fonts, preferred = %s\n", fontfamily);
412         family = g_malloc(sizeof(fontfamilies) + sizeof(fontfamily));
413         if (fontfamily) {
414                 memcpy(family, &fontfamily, sizeof(fontfamily));
415                 memcpy(family + 1, fontfamilies, sizeof(fontfamilies));
416         } else {
417                 memcpy(family, fontfamilies, sizeof(fontfamilies));
418         }
419         family_sav=family;
420         for (exact = 1; !found && exact >= 0; exact--) {
421                 family=family_sav;
422
423
424                 while (*family && !found) {
425                         dbg(2, "Looking for font family %s. exact=%d\n",
426                             *family, exact);
427                         FcPattern *required =
428                             FcPatternBuild(NULL, FC_FAMILY, FcTypeString,
429                                            *family, NULL);
430                         if (flags)
431                                 FcPatternAddInteger(required, FC_WEIGHT,
432                                                     FC_WEIGHT_BOLD);
433                         FcConfigSubstitute(FcConfigGetCurrent(), required,
434                                            FcMatchFont);
435                         FcDefaultSubstitute(required);
436                         FcResult result;
437                         FcPattern *matched =
438                             FcFontMatch(FcConfigGetCurrent(), required,
439                                         &result);
440                         if (matched) {
441                                 FcValue v1, v2;
442                                 FcChar8 *fontfile;
443                                 int fontindex;
444                                 FcPatternGet(required, FC_FAMILY, 0, &v1);
445                                 FcPatternGet(matched, FC_FAMILY, 0, &v2);
446                                 FcResult r1 =
447                                     FcPatternGetString(matched, FC_FILE, 0,
448                                                        &fontfile);
449                                 FcResult r2 =
450                                     FcPatternGetInteger(matched, FC_INDEX,
451                                                         0, &fontindex);
452                                 if ((r1 == FcResultMatch)
453                                     && (r2 == FcResultMatch)
454                                     && (FcValueEqual(v1, v2) || !exact)) {
455                                         dbg(2,
456                                             "About to load font from file %s index %d\n",
457                                             fontfile, fontindex);
458 #if USE_CACHING
459                                         idstr=g_strdup_printf("%s/%d", fontfile, fontindex);
460                                         font->scaler.face_id=(FTC_FaceID)atom(idstr);
461                                         g_free(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;
468 #else
469                                         font->scaler.width=size/15;
470                                         font->scaler.height=size/15;
471                                         font->scaler.flags=FT_LOAD_DEFAULT;
472 #endif
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 */
476                                         FT_New_Face(library,
477                                                     (char *) fontfile,
478                                                     fontindex,
479                                                     &font->face);
480 #endif /* USE_CACHING */
481                                         found = 1;
482                                 }
483                                 FcPatternDestroy(matched);
484                         }
485                         FcPatternDestroy(required);
486                         family++;
487                 }
488         }
489         g_free(family_sav);
490 #else /* HAVE_FONTCONFIG */
491 #ifdef FREETYPE_FONTS
492         {
493                 char *fonts[]={FREETYPE_FONTS};
494                 name=g_strdup(fonts[flags ? 1:0]);
495         }
496 #else
497         name=g_strdup_printf("%s/fonts/%s-%s.ttf",getenv("NAVIT_SHAREDIR"),"LiberationSans",flags ? "Bold":"Regular");
498 #endif
499
500 #if USE_CACHING
501         idstr=g_strdup_printf("%s/%d", name, 0);
502         font->scaler.face_id=(FTC_FaceID)atom(idstr);
503         g_free(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;
512 #else
513         font->scaler.width=size/15;
514         font->scaler.height=size/15;
515         font->scaler.flags=FT_LOAD_DEFAULT;
516 #endif
517         found=1;
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))
522                 found=1;
523 #endif /* USE_CACHING */
524         g_free(name);
525 #endif /* HAVE_FONTCONFIG */
526         if (!found) {
527                 dbg(0,"Failed to load font, no labelling\n");
528                 g_free(font);
529                 return NULL;
530         }
531 #if !USE_CACHING
532         FT_Set_Char_Size(font->face, 0, size, 300, 300);
533         FT_Select_Charmap(font->face, FT_ENCODING_UNICODE);
534 #endif
535         return font;
536 }
537
538 static int
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)
541 {
542         int mask0, mask1, mask2, x, y, w = g->w, h = g->h;
543         unsigned int bg, fg;
544         unsigned char *pm, *psp,*ps,*psn;
545         switch (depth) {
546         case 1:
547                 fg=0xff;
548                 bg=0x00;
549                 break;
550         case 8:
551                 fg=foreground->a>>8;
552                 bg=background->a>>8;
553                 break;
554         case 24:
555         case 32:
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);
564                 break;
565         default:
566                 return 0;
567         }
568         for (y = 0; y < h+2; y++) {
569                 if (stride) {
570                         ps = data + stride * y;
571                 } else {
572                         unsigned char **dataptr=(unsigned char **)data;
573                         ps = dataptr[y];
574                 }
575                 switch (depth) {
576                 case 1:
577                         memset(ps, bg, (w+9)/2);
578                         break;
579                 case 8:
580                         memset(ps, bg, w+2);
581                         break;
582                 case 24:
583                         for (x = 0 ; x < w+2 ; x++) {
584                                 ps[x*3]=bg>>16;
585                                 ps[x*3+1]=bg>>8;
586                                 ps[x*3+2]=bg;
587                         }
588                         break;
589                 case 32:
590                         for (x = 0 ; x < w+2 ; x++) 
591                                 ((unsigned int *)ps)[x]=bg;
592                         break;
593                 }
594         }
595         for (y = 0; y < h; y++) {
596                 pm = g->pixmap + y * w;
597                 if (stride) {
598                         psp = data + stride * y;
599                         ps = psp + stride;
600                         psn = ps + stride;
601                 } else {
602                         unsigned char **dataptr=(unsigned char **)data;
603                         psp = dataptr[y];
604                         ps = dataptr[y+1];
605                         psn = dataptr[y+2];
606                 }
607                 switch (depth) {
608                 case 1:
609                         mask0 = 0x4000;
610                         mask1 = 0xe000;
611                         mask2 = 0x4000;
612                         for (x = 0; x < w; x++) {
613                                 if (*pm) {
614                                         psp[0] |= (mask0 >> 8);
615                                         if (mask0 & 0xff)
616                                                 psp[1] |= mask0;
617                                         ps[0] |= (mask1 >> 8);
618                                         if (mask1 & 0xff)
619                                                 ps[1] |= mask1;
620                                         psn[0] |= (mask2 >> 8);
621                                         if (mask2 & 0xff)
622                                                 psn[1] |= mask2;
623                                 }
624                                 mask0 >>= 1;
625                                 mask1 >>= 1;
626                                 mask2 >>= 1;
627                                 if (!
628                                     ((mask0 >> 8) | (mask1 >> 8) |
629                                      (mask2 >> 8))) {
630                                         mask0 <<= 8;
631                                         mask1 <<= 8;
632                                         mask2 <<= 8;
633                                         psp++;
634                                         ps++;
635                                         psn++;
636                                 }
637                                 pm++;
638                         }
639                         break;
640                 case 8:
641                         for (x = 0; x < w; x++) {
642                                 if (*pm) {
643                                         psp[1] = fg;
644                                         ps[0] = fg;
645                                         ps[1] = fg;
646                                         ps[2] = fg;
647                                         psn[1] = fg;
648                                 }
649                                 psp++;
650                                 ps++;
651                                 psn++;
652                                 pm++;
653                         }
654                         break;
655                 case 24:
656                         for (x = 0; x < w; x++) {
657                                 if (*pm) {
658                                         psp[3]=fg>>16;
659                                         psp[4]=fg>>8;
660                                         psp[5]=fg;
661                                         ps[0]=fg>>16;
662                                         ps[1]=fg>>8;
663                                         ps[2]=fg;
664                                         ps[3]=fg>>16;
665                                         ps[4]=fg>>8;
666                                         ps[5]=fg;
667                                         ps[6]=fg>>16;
668                                         ps[7]=fg>>8;
669                                         ps[8]=fg;
670                                         psn[3]=fg>>16;
671                                         psn[4]=fg>>8;
672                                         psn[5]=fg;
673                                 }
674                                 psp+=3;
675                                 ps+=3;
676                                 psn+=3;
677                                 pm++;
678                         }
679                         break;
680                 case 32:
681                         for (x = 0; x < w; x++) {
682                                 if (*pm) {
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;
688                                 }
689                                 psp+=4;
690                                 ps+=4;
691                                 psn+=4;
692                                 pm++;
693                         }
694                         break;
695                 }
696         }
697         return 1;
698 }
699
700 static int
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)
703 {
704         int x, y, w = g->w, h = g->h;
705         unsigned int tr;
706         unsigned char v,vi,*pm, *ps;
707         switch (depth) {
708         case 8:
709                 tr=transparent->a>>8;
710                 break;
711         case 24:
712         case 32:
713                 tr=((transparent->a>>8)<<24)|
714                    ((transparent->r>>8)<<16)|
715                    ((transparent->g>>8)<<8)|
716                    ((transparent->b>>8)<<0);
717                 break;
718         default:
719                 return 0;
720         }
721         for (y = 0; y < h; y++) {
722                 pm = g->pixmap + y * w;
723                 if (stride) {
724                         ps = data + stride*y;
725                 } else {
726                         unsigned char **dataptr=(unsigned char **)data;
727                         ps = dataptr[y];
728                 }
729                 switch (depth) {
730                 case 8:
731                         for (x = 0; x < w; x++) {
732                                 v=*pm;
733                                 if (v) 
734                                         *ps=fg->a;
735                                 else 
736                                         *ps=tr;
737                                 ps++;
738                                 pm++;
739                         }
740                         break;
741                 case 24:
742                         for (x = 0; x < w; x++) {
743                                 v=*pm;
744                                 if (v) {
745                                         vi=255-v;
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);
749                                 } else {
750                                         ps[0]=tr >> 16;
751                                         ps[1]=tr >> 8;
752                                         ps[2]=tr;
753                                 }
754                                 ps+=3;
755                                 pm++;
756                         }
757                         break;
758                 case 32:
759                         for (x = 0; x < w; x++) {
760                                 v=*pm;
761                                 if (v) {
762                                         vi=255-v;
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);
768                                 } else
769                                         ((unsigned int *)ps)[0]=tr;
770                                 ps+=4;
771                                 pm++;
772                         }
773                         break;
774                 }
775         }
776         return 1;
777 }
778
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,  
786 };
787
788 static struct font_priv *
789 font_freetype_new(void *meth)
790 {
791         *((struct font_freetype_methods *) meth) = methods;
792         return &dummy;
793 }
794
795 void
796 plugin_init(void)
797 {
798         plugin_register_font_type("freetype", font_freetype_new);
799 #ifdef HAVE_FONTCONFIG
800         FcInit();
801 #endif
802 }