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