Simple fixes to get navit compiling with MSVC
[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         int data;
68 };
69
70 static struct font_priv dummy;
71 static FT_Library library;
72 #if USE_CACHING
73 static FTC_Manager manager;
74 static FTC_ImageCache image_cache;
75 static FTC_CMapCache charmap_cache;
76 static FTC_SBitCache sbit_cache;
77 #endif
78 static int library_init;
79
80
81 static void
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,
85                             int estimate)
86 {
87         char *p = text;
88         FT_BBox bbox;
89         FT_UInt glyph_index;
90         FT_Glyph glyph;
91         FT_Matrix matrix;
92         FT_Vector pen;
93         int i;
94         struct point pt;
95         int n, len, x = 0, y = 0;
96         pen.x = 0 * 64;
97         pen.y = 0 * 64;
98 #if 0
99         matrix.xx = dx;
100         matrix.xy = dy;
101         matrix.yx = -dy;
102         matrix.yy = dx;
103 #else
104         matrix.xx = 0x10000;
105         matrix.xy = 0;
106         matrix.yx = 0;
107         matrix.yy = 0x10000;
108 #endif
109
110         len = g_utf8_strlen(text, -1);
111         if (estimate) {
112                 bbox.xMin = 0;
113                 bbox.yMin = 0;
114                 bbox.yMax = 13*font->size/256;
115                 bbox.xMax = 9*font->size*len/256;
116         } else {
117                 bbox.xMin = bbox.yMin = 32000;
118                 bbox.xMax = bbox.yMax = -32000;
119 #if !USE_CACHING
120                 FT_Set_Transform(font->face, &matrix, &pen);
121 #endif
122                 for (n = 0; n < len; n++) {
123                         FT_BBox glyph_bbox;
124 #if USE_CACHING
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);
130 #else
131                         FTC_ImageCache_Lookup(image_cache, &font->scaler, glyph_index, &cached_glyph, &anode);
132 #endif
133                         FT_Glyph_Copy(cached_glyph, &glyph);
134                         FT_Glyph_Transform(glyph, &matrix, &pen);
135 #else
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);
139 #endif
140                         FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox);
141
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);
157 #if USE_CACHING
158                         FT_Done_Glyph(glyph);
159                         FTC_Node_Unref(anode, manager);
160 #else
161                         FT_Done_Glyph(glyph);
162 #endif
163                 }
164                 if (bbox.xMin > bbox.xMax) {
165                         bbox.xMin = 0;
166                         bbox.yMin = 0;
167                         bbox.xMax = 0;
168                         bbox.yMax = 0;
169                 }
170         }
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++) {
181                         pt=ret[i];
182                         ret[i].x=(pt.x*dx-pt.y*dy)/0x10000;
183                         ret[i].y=(pt.y*dx+pt.x*dy)/0x10000;
184                 }
185         }
186 }
187
188 static struct font_freetype_text *
189 font_freetype_text_new(char *text, struct font_freetype_font *font, int dx,
190                        int dy)
191 {
192         FT_Matrix matrix;
193         FT_Vector pen;
194         FT_UInt glyph_index;
195         int y, n, len, w, h, pixmap_len;
196         struct font_freetype_text *ret;
197         struct font_freetype_glyph *curr;
198         char *p = text;
199         unsigned char *gl, *pm;
200         FT_BitmapGlyph glyph_bitmap;
201         FT_Glyph glyph;
202
203         len = g_utf8_strlen(text, -1);
204         ret = g_malloc(sizeof(*ret) + len * sizeof(struct text_glyph *));
205         ret->glyph_count = len;
206
207         matrix.xx = dx;
208         matrix.xy = dy;
209         matrix.yx = -dy;
210         matrix.yy = dx;
211
212         pen.x = 0 * 64;
213         pen.y = 0 * 64;
214 #if !USE_CACHING
215         FT_Set_Transform(font->face, &matrix, &pen);
216 #endif
217
218 #if USE_FRIBIDI
219     // Need to use fribidi to handle the string properly
220     char visual_text[len*4+1];
221     {
222         FriBidiChar unicode_text[len+2];
223         FriBidiChar visual_unicode_text[len+2];
224         FriBidiStrIndex textlen =  strlen(text);
225 #ifdef FRIBIDIOLD
226         FriBidiCharType base = FRIBIDI_TYPE_LTR;
227 #else
228         FriBidiParType base = FRIBIDI_PAR_LTR;
229 #endif
230
231         FriBidiStrIndex unicode_len =
232 #ifdef FRIBIDIOLD
233                         fribidi_utf8_to_unicode(text, textlen, unicode_text);
234 #else
235                         fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, text, textlen, unicode_text);
236 #endif
237         fribidi_log2vis(unicode_text, unicode_len, &base, visual_unicode_text, NULL, NULL, NULL);
238         // TODO: check return value
239 #ifdef FRIBIDIOLD
240         fribidi_unicode_to_utf8(visual_unicode_text, unicode_len, visual_text);
241 #else
242         fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, visual_unicode_text, unicode_len, visual_text);
243 #endif
244         p = visual_text;
245     }
246 #endif /* USE_FRIBIDI */
247
248         for (n = 0; n < len; n++) {
249
250 #if USE_CACHING
251                 FTC_Node anode=NULL;
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);
256 #else
257                 FTC_ImageCache_Lookup(image_cache, &font->scaler, glyph_index, &cached_glyph, &anode);
258 #endif
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);
262 #else
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);
266 #endif
267                 FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, NULL, TRUE);
268                 glyph_bitmap = (FT_BitmapGlyph)glyph;
269
270                 w = glyph_bitmap->bitmap.width;
271                 h = glyph_bitmap->bitmap.rows;
272                 if (w && h)
273                         pixmap_len = (w + 2) * (h + 2);
274                 else
275                         pixmap_len = 0;
276                 curr = g_malloc0(sizeof(*curr) + pixmap_len);
277                 if (pixmap_len) {
278                         curr->w = w;
279                         curr->h = h;
280                 }
281                 curr->pixmap = (unsigned char *) (curr + 1);
282                 ret->glyph[n] = curr;
283
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;
289                         memcpy(pm, gl, w);
290                 }
291
292                 curr->dx = glyph->advance.x >> 10;
293                 curr->dy = -glyph->advance.y >> 10;
294                 FT_Done_Glyph(glyph);
295 #if USE_CACHING
296                 FTC_Node_Unref(anode, manager);
297 #endif
298                 p = g_utf8_next_char(p);
299         }
300         ret->glyph_count = len;
301         return ret;
302 }
303
304 /**
305  * List of font families to use, in order of preference
306  */
307 static char *fontfamilies[] = {
308         "Liberation Sans",
309         "Arial",
310         "NcrBI4nh",
311         "luximbi",
312         "FreeSans",
313         "DejaVu Sans",
314         NULL,
315 };
316
317 static void
318 font_destroy(struct graphics_font_priv *font)
319 {
320         g_free(font);
321         /* TODO: free font->face */
322 }
323
324 static struct graphics_font_methods font_methods = {
325         font_destroy
326 };
327
328
329 static void
330 font_freetype_text_destroy(struct font_freetype_text *text)
331 {
332         int i;
333         struct font_freetype_glyph **gp;
334
335         gp = text->glyph;
336         i = text->glyph_count;
337         while (i-- > 0)
338                 g_free(*gp++);
339         g_free(text);
340 }
341
342 #if USE_CACHING
343 static FT_Error face_requester( FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face* aface )
344 {
345         FT_Error ret;
346         char *fontfile,*fontindex;
347         if (! face_id)
348                 return FT_Err_Invalid_Handle;
349         fontfile=g_strdup((char *)face_id);
350         dbg(1,"fontfile=%s\n", fontfile);
351         fontindex=strrchr(fontfile,'/');
352         if (! fontindex) {
353                 g_free(fontfile);
354                 return FT_Err_Invalid_Handle;
355         }
356         *fontindex++='\0';
357         dbg(1,"new face %s %d\n", fontfile, atoi(fontindex));
358         ret = FT_New_Face( library, fontfile, atoi(fontindex), aface );
359         if(ret) {
360                dbg(0,"Error while creating freetype face: %d\n", ret);
361                return ret;
362         }
363         if((ret = FT_Select_Charmap(*aface, FT_ENCODING_UNICODE))) {
364                dbg(0,"Error while creating freetype face: %d\n", ret);
365         }
366         return 0;
367 }
368 #endif
369
370 /**
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)
379  * @returns <>
380 */
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)
385 {
386         struct font_freetype_font *font =
387             g_new(struct font_freetype_font, 1);
388         int exact, found=0;
389         char **family, **family_sav;
390 #if USE_CACHING
391         char *idstr;
392         FT_Face face;
393 #endif
394 #ifndef HAVE_FONTCONFIG
395         char *name;
396 #endif
397         *meth = font_methods;
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 }