jscript: Added String_link implementation.
[wine] / dlls / winex11.drv / xrender.c
1 /*
2  * Functions to use the XRender extension
3  *
4  * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5  *
6  * Some parts also:
7  * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "x11drv.h"
34 #include "winternl.h"
35 #include "wine/library.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38
39 int using_client_side_fonts = FALSE;
40
41 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
42
43 #ifdef SONAME_LIBXRENDER
44
45 static BOOL X11DRV_XRender_Installed = FALSE;
46
47 #include <X11/Xlib.h>
48 #include <X11/extensions/Xrender.h>
49
50 #ifndef RepeatNone  /* added in 0.10 */
51 #define RepeatNone    0
52 #define RepeatNormal  1
53 #define RepeatPad     2
54 #define RepeatReflect 3
55 #endif
56
57 #define MAX_FORMATS 10
58 typedef enum wine_xrformat
59 {
60   WXR_FORMAT_MONO,
61   WXR_FORMAT_GRAY,
62   WXR_FORMAT_X1R5G5B5,
63   WXR_FORMAT_X1B5G5R5,
64   WXR_FORMAT_R5G6B5,
65   WXR_FORMAT_B5G6R5,
66   WXR_FORMAT_R8G8B8,
67   WXR_FORMAT_B8G8R8,
68   WXR_FORMAT_A8R8G8B8,
69   WXR_FORMAT_X8R8G8B8,
70 } WXRFormat;
71
72 typedef struct wine_xrender_format_template
73 {
74     WXRFormat wxr_format;
75     unsigned int depth;
76     unsigned int alpha;
77     unsigned int alphaMask;
78     unsigned int red;
79     unsigned int redMask;
80     unsigned int green;
81     unsigned int greenMask;
82     unsigned int blue;
83     unsigned int blueMask;
84 } WineXRenderFormatTemplate;
85
86 static const WineXRenderFormatTemplate wxr_formats_template[] =
87 {
88     /* Format               depth   alpha   mask    red     mask    green   mask    blue    mask*/
89     {WXR_FORMAT_MONO,       1,      0,      0x01,   0,      0,      0,      0,      0,      0       },
90     {WXR_FORMAT_GRAY,       8,      0,      0xff,   0,      0,      0,      0,      0,      0       },
91     {WXR_FORMAT_X1R5G5B5,   16,     0,      0,      10,     0x1f,   5,      0x1f,   0,      0x1f    },
92     {WXR_FORMAT_X1B5G5R5,   16,     0,      0,      0,      0x1f,   5,      0x1f,   10,     0x1f    },
93     {WXR_FORMAT_R5G6B5,     16,     0,      0,      11,     0x1f,   5,      0x3f,   0,      0x1f    },
94     {WXR_FORMAT_B5G6R5,     16,     0,      0,      0,      0x1f,   5,      0x3f,   11,     0x1f    },
95     {WXR_FORMAT_R8G8B8,     24,     0,      0,      16,     0xff,   8,      0xff,   0,      0xff    },
96     {WXR_FORMAT_B8G8R8,     24,     0,      0,      0,      0xff,   8,      0xff,   16,     0xff    },
97     {WXR_FORMAT_A8R8G8B8,   32,     24,     0xff,   16,     0xff,   8,      0xff,   0,      0xff    },
98     {WXR_FORMAT_X8R8G8B8,   32,     0,      0,      16,     0xff,   8,      0xff,   0,      0xff    }
99 };
100
101 typedef struct wine_xrender_format
102 {
103     WXRFormat               format;
104     XRenderPictFormat       *pict_format;
105 } WineXRenderFormat;
106
107 static WineXRenderFormat wxr_formats[MAX_FORMATS];
108 static int WineXRenderFormatsListSize = 0;
109 static WineXRenderFormat *default_format = NULL;
110
111 typedef struct
112 {
113     LOGFONTW lf;
114     XFORM    xform;
115     SIZE     devsize;  /* size in device coords */
116     DWORD    hash;
117 } LFANDSIZE;
118
119 #define INITIAL_REALIZED_BUF_SIZE 128
120
121 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
122
123 typedef struct
124 {
125     GlyphSet glyphset;
126     WineXRenderFormat *font_format;
127     int nrealized;
128     BOOL *realized;
129     void **bitmaps;
130     XGlyphInfo *gis;
131 } gsCacheEntryFormat;
132
133 typedef struct
134 {
135     LFANDSIZE lfsz;
136     AA_Type aa_default;
137     gsCacheEntryFormat * format[AA_MAXVALUE];
138     INT count;
139     INT next;
140 } gsCacheEntry;
141
142 struct tagXRENDERINFO
143 {
144     int                cache_index;
145     Picture            pict;
146 };
147
148
149 static gsCacheEntry *glyphsetCache = NULL;
150 static DWORD glyphsetCacheSize = 0;
151 static INT lastfree = -1;
152 static INT mru = -1;
153
154 #define INIT_CACHE_SIZE 10
155
156 static int antialias = 1;
157
158 static void *xrender_handle;
159
160 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
161 MAKE_FUNCPTR(XRenderAddGlyphs)
162 MAKE_FUNCPTR(XRenderComposite)
163 MAKE_FUNCPTR(XRenderCompositeString8)
164 MAKE_FUNCPTR(XRenderCompositeString16)
165 MAKE_FUNCPTR(XRenderCompositeString32)
166 MAKE_FUNCPTR(XRenderCompositeText16)
167 MAKE_FUNCPTR(XRenderCreateGlyphSet)
168 MAKE_FUNCPTR(XRenderCreatePicture)
169 MAKE_FUNCPTR(XRenderFillRectangle)
170 MAKE_FUNCPTR(XRenderFindFormat)
171 MAKE_FUNCPTR(XRenderFindVisualFormat)
172 MAKE_FUNCPTR(XRenderFreeGlyphSet)
173 MAKE_FUNCPTR(XRenderFreePicture)
174 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
175 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
176 MAKE_FUNCPTR(XRenderSetPictureTransform)
177 #endif
178 MAKE_FUNCPTR(XRenderQueryExtension)
179 #undef MAKE_FUNCPTR
180
181 static CRITICAL_SECTION xrender_cs;
182 static CRITICAL_SECTION_DEBUG critsect_debug =
183 {
184     0, 0, &xrender_cs,
185     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
186       0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
187 };
188 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
189
190 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
191           ( ( (ULONG)_x4 << 24 ) |     \
192             ( (ULONG)_x3 << 16 ) |     \
193             ( (ULONG)_x2 <<  8 ) |     \
194               (ULONG)_x1         )
195
196 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
197
198 #define GASP_GRIDFIT 0x01
199 #define GASP_DOGRAY  0x02
200
201 #ifdef WORDS_BIGENDIAN
202 #define get_be_word(x) (x)
203 #define NATIVE_BYTE_ORDER MSBFirst
204 #else
205 #define get_be_word(x) RtlUshortByteSwap(x)
206 #define NATIVE_BYTE_ORDER LSBFirst
207 #endif
208
209 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
210 {
211     templ->id = 0;
212     templ->type = PictTypeDirect;
213     templ->depth = fmt->depth;
214     templ->direct.alpha = fmt->alpha;
215     templ->direct.alphaMask = fmt->alphaMask;
216     templ->direct.red = fmt->red;
217     templ->direct.redMask = fmt->redMask;
218     templ->direct.green = fmt->green;
219     templ->direct.greenMask = fmt->greenMask;
220     templ->direct.blue = fmt->blue;
221     templ->direct.blueMask = fmt->blueMask;
222     templ->colormap = 0;
223
224     *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
225
226     return TRUE;
227 }
228
229 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
230 {
231     if(fmt->depth != screen_depth)
232         return FALSE;
233     if( (fmt->redMask << fmt->red) != visual->red_mask)
234         return FALSE;
235     if( (fmt->greenMask << fmt->green) != visual->green_mask)
236         return FALSE;
237     if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
238         return FALSE;
239
240     /* We never select a default ARGB visual */
241     if(fmt->alphaMask)
242         return FALSE;
243
244     return TRUE;
245 }
246
247 static int load_xrender_formats(void)
248 {
249     unsigned int i;
250     for(i = 0; i < (sizeof(wxr_formats_template) / sizeof(wxr_formats_template[0])); i++)
251     {
252         XRenderPictFormat templ, *pict_format;
253
254         if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
255         {
256             wine_tsx11_lock();
257             pict_format = pXRenderFindVisualFormat(gdi_display, visual);
258             if(!pict_format)
259             {
260                 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
261                 if (visual->class == DirectColor)
262                 {
263                     XVisualInfo info;
264                     if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
265                                           screen_depth, TrueColor, &info ))
266                     {
267                         pict_format = pXRenderFindVisualFormat(gdi_display, info.visual);
268                         if (pict_format) visual = info.visual;
269                     }
270                 }
271             }
272             wine_tsx11_unlock();
273
274             if(pict_format)
275             {
276                 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
277                 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
278                 default_format = &wxr_formats[WineXRenderFormatsListSize];
279                 WineXRenderFormatsListSize++;
280                 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
281             }
282         }
283         else
284         {
285             unsigned long mask = 0;
286             get_xrender_template(&wxr_formats_template[i], &templ, &mask);
287
288             wine_tsx11_lock();
289             pict_format = pXRenderFindFormat(gdi_display, mask, &templ, 0);
290             wine_tsx11_unlock();
291
292             if(pict_format)
293             {
294                 wxr_formats[WineXRenderFormatsListSize].format = wxr_formats_template[i].wxr_format;
295                 wxr_formats[WineXRenderFormatsListSize].pict_format = pict_format;
296                 WineXRenderFormatsListSize++;
297                 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_format->id, wxr_formats_template[i].wxr_format);
298             }
299         }
300     }
301     return WineXRenderFormatsListSize;
302 }
303
304 /***********************************************************************
305  *   X11DRV_XRender_Init
306  *
307  * Let's see if our XServer has the extension available
308  *
309  */
310 void X11DRV_XRender_Init(void)
311 {
312     int event_base, i;
313
314     if (client_side_with_render &&
315         wine_dlopen(SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, NULL, 0) &&
316         wine_dlopen(SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0) && 
317         (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
318     {
319
320 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
321 LOAD_FUNCPTR(XRenderAddGlyphs)
322 LOAD_FUNCPTR(XRenderComposite)
323 LOAD_FUNCPTR(XRenderCompositeString8)
324 LOAD_FUNCPTR(XRenderCompositeString16)
325 LOAD_FUNCPTR(XRenderCompositeString32)
326 LOAD_FUNCPTR(XRenderCompositeText16)
327 LOAD_FUNCPTR(XRenderCreateGlyphSet)
328 LOAD_FUNCPTR(XRenderCreatePicture)
329 LOAD_FUNCPTR(XRenderFillRectangle)
330 LOAD_FUNCPTR(XRenderFindFormat)
331 LOAD_FUNCPTR(XRenderFindVisualFormat)
332 LOAD_FUNCPTR(XRenderFreeGlyphSet)
333 LOAD_FUNCPTR(XRenderFreePicture)
334 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
335 LOAD_FUNCPTR(XRenderQueryExtension)
336 #undef LOAD_FUNCPTR
337 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
338 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
339 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
340 #undef LOAD_OPTIONAL_FUNCPTR
341 #endif
342
343         wine_tsx11_lock();
344         X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
345         wine_tsx11_unlock();
346         if(X11DRV_XRender_Installed) {
347             TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
348             if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
349             {
350                 wine_tsx11_unlock();
351                 WINE_MESSAGE(
352                     "Wine has detected that you probably have a buggy version\n"
353                     "of libXrender.so .  Because of this client side font rendering\n"
354                     "will be disabled.  Please upgrade this library.\n");
355                 X11DRV_XRender_Installed = FALSE;
356                 return;
357             }
358
359             if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
360                 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
361                 X11DRV_XRender_Installed = FALSE;
362             }
363         }
364     }
365
366 sym_not_found:
367     if(X11DRV_XRender_Installed || client_side_with_core)
368     {
369         glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
370                                   sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
371
372         glyphsetCacheSize = INIT_CACHE_SIZE;
373         lastfree = 0;
374         for(i = 0; i < INIT_CACHE_SIZE; i++) {
375           glyphsetCache[i].next = i + 1;
376           glyphsetCache[i].count = -1;
377         }
378         glyphsetCache[i-1].next = -1;
379         using_client_side_fonts = 1;
380
381         if(!X11DRV_XRender_Installed) {
382             TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
383             if(screen_depth <= 8 || !client_side_antialias_with_core)
384                 antialias = 0;
385         } else {
386             if(screen_depth <= 8 || !client_side_antialias_with_render)
387                 antialias = 0;
388         }
389     }
390     else TRACE("Using X11 core fonts\n");
391 }
392
393 static WineXRenderFormat *get_xrender_format(WXRFormat format)
394 {
395     int i;
396     for(i=0; i<WineXRenderFormatsListSize; i++)
397     {
398         if(wxr_formats[i].format == format)
399         {
400             TRACE("Returning wxr_format=%#x\n", format);
401             return &wxr_formats[i];
402         }
403     }
404     return NULL;
405 }
406
407 static WineXRenderFormat *get_xrender_format_from_pdevice(X11DRV_PDEVICE *physDev)
408 {
409     WXRFormat format;
410
411     switch(physDev->depth)
412     {
413         case 1:
414             format = WXR_FORMAT_MONO;
415             break;
416         default:
417             /* For now fall back to the format of the default visual.
418                In the future we should check if we are using a DDB/DIB and what exact format we need.
419              */
420             return default_format;
421     }
422
423     return get_xrender_format(format);
424 }
425
426 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
427 {
428   if(p1->hash != p2->hash) return TRUE;
429   if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
430   if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
431   if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
432   return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
433 }
434
435 #if 0
436 static void walk_cache(void)
437 {
438   int i;
439
440   EnterCriticalSection(&xrender_cs);
441   for(i=mru; i >= 0; i = glyphsetCache[i].next)
442     TRACE("item %d\n", i);
443   LeaveCriticalSection(&xrender_cs);
444 }
445 #endif
446
447 static int LookupEntry(LFANDSIZE *plfsz)
448 {
449   int i, prev_i = -1;
450
451   for(i = mru; i >= 0; i = glyphsetCache[i].next) {
452     TRACE("%d\n", i);
453     if(glyphsetCache[i].count == -1) { /* reached free list so stop */
454       i = -1;
455       break;
456     }
457
458     if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
459       glyphsetCache[i].count++;
460       if(prev_i >= 0) {
461         glyphsetCache[prev_i].next = glyphsetCache[i].next;
462         glyphsetCache[i].next = mru;
463         mru = i;
464       }
465       TRACE("found font in cache %d\n", i);
466       return i;
467     }
468     prev_i = i;
469   }
470   TRACE("font not in cache\n");
471   return -1;
472 }
473
474 static void FreeEntry(int entry)
475 {
476     int i, format;
477   
478     for(format = 0; format < AA_MAXVALUE; format++) {
479         gsCacheEntryFormat * formatEntry;
480
481         if( !glyphsetCache[entry].format[format] )
482             continue;
483
484         formatEntry = glyphsetCache[entry].format[format];
485
486         if(formatEntry->glyphset) {
487             wine_tsx11_lock();
488             pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
489             wine_tsx11_unlock();
490             formatEntry->glyphset = 0;
491         }
492         if(formatEntry->nrealized) {
493             HeapFree(GetProcessHeap(), 0, formatEntry->realized);
494             formatEntry->realized = NULL;
495             if(formatEntry->bitmaps) {
496                 for(i = 0; i < formatEntry->nrealized; i++)
497                     HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
498                 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
499                 formatEntry->bitmaps = NULL;
500             }
501             HeapFree(GetProcessHeap(), 0, formatEntry->gis);
502             formatEntry->gis = NULL;
503             formatEntry->nrealized = 0;
504         }
505
506         HeapFree(GetProcessHeap(), 0, formatEntry);
507         glyphsetCache[entry].format[format] = NULL;
508     }
509 }
510
511 static int AllocEntry(void)
512 {
513   int best = -1, prev_best = -1, i, prev_i = -1;
514
515   if(lastfree >= 0) {
516     assert(glyphsetCache[lastfree].count == -1);
517     glyphsetCache[lastfree].count = 1;
518     best = lastfree;
519     lastfree = glyphsetCache[lastfree].next;
520     assert(best != mru);
521     glyphsetCache[best].next = mru;
522     mru = best;
523
524     TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
525     return mru;
526   }
527
528   for(i = mru; i >= 0; i = glyphsetCache[i].next) {
529     if(glyphsetCache[i].count == 0) {
530       best = i;
531       prev_best = prev_i;
532     }
533     prev_i = i;
534   }
535
536   if(best >= 0) {
537     TRACE("freeing unused glyphset at cache %d\n", best);
538     FreeEntry(best);
539     glyphsetCache[best].count = 1;
540     if(prev_best >= 0) {
541       glyphsetCache[prev_best].next = glyphsetCache[best].next;
542       glyphsetCache[best].next = mru;
543       mru = best;
544     } else {
545       assert(mru == best);
546     }
547     return mru;
548   }
549
550   TRACE("Growing cache\n");
551   
552   if (glyphsetCache)
553     glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
554                               glyphsetCache,
555                               (glyphsetCacheSize + INIT_CACHE_SIZE)
556                               * sizeof(*glyphsetCache));
557   else
558     glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
559                               (glyphsetCacheSize + INIT_CACHE_SIZE)
560                               * sizeof(*glyphsetCache));
561
562   for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
563       i++) {
564     glyphsetCache[i].next = i + 1;
565     glyphsetCache[i].count = -1;
566   }
567   glyphsetCache[i-1].next = -1;
568   glyphsetCacheSize += INIT_CACHE_SIZE;
569
570   lastfree = glyphsetCache[best].next;
571   glyphsetCache[best].count = 1;
572   glyphsetCache[best].next = mru;
573   mru = best;
574   TRACE("new free cache slot at %d\n", mru);
575   return mru;
576 }
577
578 static BOOL get_gasp_flags(X11DRV_PDEVICE *physDev, WORD *flags)
579 {
580     DWORD size;
581     WORD *gasp, *buffer;
582     WORD num_recs;
583     DWORD ppem;
584     TEXTMETRICW tm;
585
586     *flags = 0;
587
588     size = GetFontData(physDev->hdc, MS_GASP_TAG,  0, NULL, 0);
589     if(size == GDI_ERROR)
590         return FALSE;
591
592     gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
593     GetFontData(physDev->hdc, MS_GASP_TAG,  0, gasp, size);
594
595     GetTextMetricsW(physDev->hdc, &tm);
596     ppem = abs(X11DRV_YWStoDS(physDev, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
597
598     gasp++;
599     num_recs = get_be_word(*gasp);
600     gasp++;
601     while(num_recs--)
602     {
603         *flags = get_be_word(*(gasp + 1));
604         if(ppem <= get_be_word(*gasp))
605             break;
606         gasp += 2;
607     }
608     TRACE("got flags %04x for ppem %d\n", *flags, ppem);
609
610     HeapFree(GetProcessHeap(), 0, buffer);
611     return TRUE;
612 }
613
614 static AA_Type get_antialias_type( X11DRV_PDEVICE *physDev, BOOL subpixel, BOOL hinter)
615 {
616     AA_Type ret;
617     WORD flags;
618     UINT font_smoothing_type, font_smoothing_orientation;
619
620     if (X11DRV_XRender_Installed && subpixel &&
621         SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
622         font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
623     {
624         if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
625                                     &font_smoothing_orientation, 0) &&
626              font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
627         {
628             ret = AA_BGR;
629         }
630         else
631             ret = AA_RGB;
632         /*FIXME
633           If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
634           But, Wine's subpixel rendering can support the portrait mode.
635          */
636     }
637     else if (!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY)
638         ret = AA_Grey;
639     else
640         ret = AA_None;
641
642     return ret;
643 }
644
645 static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz)
646 {
647     int ret;
648     int format;
649     gsCacheEntry *entry;
650     static int hinter = -1;
651     static int subpixel = -1;
652     BOOL font_smoothing;
653
654     if((ret = LookupEntry(plfsz)) != -1) return ret;
655
656     ret = AllocEntry();
657     entry = glyphsetCache + ret;
658     entry->lfsz = *plfsz;
659     for( format = 0; format < AA_MAXVALUE; format++ ) {
660         assert( !entry->format[format] );
661     }
662
663     if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
664     {
665         if(hinter == -1 || subpixel == -1)
666         {
667             RASTERIZER_STATUS status;
668             GetRasterizerCaps(&status, sizeof(status));
669             hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
670             subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
671         }
672
673         switch (plfsz->lf.lfQuality)
674         {
675             case ANTIALIASED_QUALITY:
676                 entry->aa_default = get_antialias_type( physDev, FALSE, hinter );
677                 break;
678             case CLEARTYPE_QUALITY:
679             case CLEARTYPE_NATURAL_QUALITY:
680                 entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
681                 break;
682             case DEFAULT_QUALITY:
683             case DRAFT_QUALITY:
684             case PROOF_QUALITY:
685             default:
686                 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
687                      font_smoothing)
688                 {
689                     entry->aa_default = get_antialias_type( physDev, subpixel, hinter );
690                 }
691                 else
692                     entry->aa_default = AA_None;
693                 break;
694         }
695     }
696     else
697         entry->aa_default = AA_None;
698
699     return ret;
700 }
701
702 static void dec_ref_cache(int index)
703 {
704     assert(index >= 0);
705     TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
706     assert(glyphsetCache[index].count > 0);
707     glyphsetCache[index].count--;
708 }
709
710 static void lfsz_calc_hash(LFANDSIZE *plfsz)
711 {
712   DWORD hash = 0, *ptr, two_chars;
713   WORD *pwc;
714   int i;
715
716   hash ^= plfsz->devsize.cx;
717   hash ^= plfsz->devsize.cy;
718   for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
719     hash ^= *ptr;
720   for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
721     hash ^= *ptr;
722   for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
723     two_chars = *ptr;
724     pwc = (WCHAR *)&two_chars;
725     if(!*pwc) break;
726     *pwc = toupperW(*pwc);
727     pwc++;
728     *pwc = toupperW(*pwc);
729     hash ^= two_chars;
730     if(!*pwc) break;
731   }
732   plfsz->hash = hash;
733   return;
734 }
735
736 /***********************************************************************
737  *   X11DRV_XRender_Finalize
738  */
739 void X11DRV_XRender_Finalize(void)
740 {
741     int i;
742
743     EnterCriticalSection(&xrender_cs);
744     for(i = mru; i >= 0; i = glyphsetCache[i].next)
745         FreeEntry(i);
746     LeaveCriticalSection(&xrender_cs);
747 }
748
749
750 /***********************************************************************
751  *   X11DRV_XRender_SelectFont
752  */
753 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
754 {
755     LFANDSIZE lfsz;
756
757     GetObjectW(hfont, sizeof(lfsz.lf), &lfsz.lf);
758     TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
759           lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
760           lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
761     lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
762     lfsz.devsize.cx = X11DRV_XWStoDS( physDev, lfsz.lf.lfWidth );
763     lfsz.devsize.cy = X11DRV_YWStoDS( physDev, lfsz.lf.lfHeight );
764     GetWorldTransform( physDev->hdc, &lfsz.xform );
765     lfsz_calc_hash(&lfsz);
766
767     EnterCriticalSection(&xrender_cs);
768     if(!physDev->xrender) {
769         physDev->xrender = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
770                                      sizeof(*physDev->xrender));
771         physDev->xrender->cache_index = -1;
772     }
773     else if(physDev->xrender->cache_index != -1)
774         dec_ref_cache(physDev->xrender->cache_index);
775     physDev->xrender->cache_index = GetCacheEntry(physDev, &lfsz);
776     LeaveCriticalSection(&xrender_cs);
777     return 0;
778 }
779
780 /***********************************************************************
781  *   X11DRV_XRender_DeleteDC
782  */
783 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
784 {
785     X11DRV_XRender_UpdateDrawable(physDev);
786
787     EnterCriticalSection(&xrender_cs);
788     if(physDev->xrender->cache_index != -1)
789         dec_ref_cache(physDev->xrender->cache_index);
790     LeaveCriticalSection(&xrender_cs);
791
792     HeapFree(GetProcessHeap(), 0, physDev->xrender);
793     physDev->xrender = NULL;
794     return;
795 }
796
797 /***********************************************************************
798  *   X11DRV_XRender_UpdateDrawable
799  *
800  * Deletes the pict and tile when the drawable changes.
801  */
802 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
803 {
804     wine_tsx11_lock();
805
806     if(physDev->xrender->pict)
807     {
808         TRACE("freeing pict = %lx dc = %p\n", physDev->xrender->pict, physDev->hdc);
809         XFlush(gdi_display);
810         pXRenderFreePicture(gdi_display, physDev->xrender->pict);
811         physDev->xrender->pict = 0;
812     }
813     wine_tsx11_unlock();
814
815     return;
816 }
817
818 /************************************************************************
819  *   UploadGlyph
820  *
821  * Helper to ExtTextOut.  Must be called inside xrender_cs
822  */
823 static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format)
824 {
825     unsigned int buflen;
826     char *buf;
827     Glyph gid;
828     GLYPHMETRICS gm;
829     XGlyphInfo gi;
830     gsCacheEntry *entry = glyphsetCache + physDev->xrender->cache_index;
831     gsCacheEntryFormat *formatEntry;
832     UINT ggo_format = GGO_GLYPH_INDEX;
833     WXRFormat wxr_format;
834     static const char zero[4];
835     static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
836
837     switch(format) {
838     case AA_Grey:
839         ggo_format |= WINE_GGO_GRAY16_BITMAP;
840         break;
841     case AA_RGB:
842         ggo_format |= WINE_GGO_HRGB_BITMAP;
843         break;
844     case AA_BGR:
845         ggo_format |= WINE_GGO_HBGR_BITMAP;
846         break;
847     case AA_VRGB:
848         ggo_format |= WINE_GGO_VRGB_BITMAP;
849         break;
850     case AA_VBGR:
851         ggo_format |= WINE_GGO_VBGR_BITMAP;
852         break;
853
854     default:
855         ERR("aa = %d - not implemented\n", format);
856     case AA_None:
857         ggo_format |= GGO_BITMAP;
858         break;
859     }
860
861     buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
862     if(buflen == GDI_ERROR) {
863         if(format != AA_None) {
864             format = AA_None;
865             entry->aa_default = AA_None;
866             ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
867             buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
868         }
869         if(buflen == GDI_ERROR) {
870             WARN("GetGlyphOutlineW failed\n");
871             return FALSE;
872         }
873         TRACE("Turning off antialiasing for this monochrome font\n");
874     }
875
876     /* If there is nothing for the current type, we create the entry. */
877     if( !entry->format[format] ) {
878         entry->format[format] = HeapAlloc(GetProcessHeap(),
879                                           HEAP_ZERO_MEMORY,
880                                           sizeof(gsCacheEntryFormat));
881     }
882     formatEntry = entry->format[format];
883
884     if(formatEntry->nrealized <= glyph) {
885         formatEntry->nrealized = (glyph / 128 + 1) * 128;
886
887         if (formatEntry->realized)
888             formatEntry->realized = HeapReAlloc(GetProcessHeap(),
889                                       HEAP_ZERO_MEMORY,
890                                       formatEntry->realized,
891                                       formatEntry->nrealized * sizeof(BOOL));
892         else
893             formatEntry->realized = HeapAlloc(GetProcessHeap(),
894                                       HEAP_ZERO_MEMORY,
895                                       formatEntry->nrealized * sizeof(BOOL));
896
897         if(!X11DRV_XRender_Installed) {
898           if (formatEntry->bitmaps)
899             formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
900                                       HEAP_ZERO_MEMORY,
901                                       formatEntry->bitmaps,
902                                       formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
903           else
904             formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
905                                       HEAP_ZERO_MEMORY,
906                                       formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
907         }
908         if (formatEntry->gis)
909             formatEntry->gis = HeapReAlloc(GetProcessHeap(),
910                                    HEAP_ZERO_MEMORY,
911                                    formatEntry->gis,
912                                    formatEntry->nrealized * sizeof(formatEntry->gis[0]));
913         else
914             formatEntry->gis = HeapAlloc(GetProcessHeap(),
915                                    HEAP_ZERO_MEMORY,
916                                    formatEntry->nrealized * sizeof(formatEntry->gis[0]));
917     }
918
919
920     if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
921         switch(format) {
922             case AA_Grey:
923                 wxr_format = WXR_FORMAT_GRAY;
924                 break;
925
926             case AA_RGB:
927             case AA_BGR:
928             case AA_VRGB:
929             case AA_VBGR:
930                 wxr_format = WXR_FORMAT_A8R8G8B8;
931                 break;
932
933             default:
934                 ERR("aa = %d - not implemented\n", format);
935             case AA_None:
936                 wxr_format = WXR_FORMAT_MONO;
937                 break;
938         }
939
940         wine_tsx11_lock();
941         formatEntry->font_format = get_xrender_format(wxr_format);
942         formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format->pict_format);
943         wine_tsx11_unlock();
944     }
945
946
947     buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
948     GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
949     formatEntry->realized[glyph] = TRUE;
950
951     TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
952           buflen,
953           gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
954           gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
955
956     gi.width = gm.gmBlackBoxX;
957     gi.height = gm.gmBlackBoxY;
958     gi.x = -gm.gmptGlyphOrigin.x;
959     gi.y = gm.gmptGlyphOrigin.y;
960     gi.xOff = gm.gmCellIncX;
961     gi.yOff = gm.gmCellIncY;
962
963     if(TRACE_ON(xrender)) {
964         int pitch, i, j;
965         char output[300];
966         unsigned char *line;
967
968         if(format == AA_None) {
969             pitch = ((gi.width + 31) / 32) * 4;
970             for(i = 0; i < gi.height; i++) {
971                 line = (unsigned char*) buf + i * pitch;
972                 output[0] = '\0';
973                 for(j = 0; j < pitch * 8; j++) {
974                     strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
975                 }
976                 TRACE("%s\n", output);
977             }
978         } else {
979             static const char blks[] = " .:;!o*#";
980             char str[2];
981
982             str[1] = '\0';
983             pitch = ((gi.width + 3) / 4) * 4;
984             for(i = 0; i < gi.height; i++) {
985                 line = (unsigned char*) buf + i * pitch;
986                 output[0] = '\0';
987                 for(j = 0; j < pitch; j++) {
988                     str[0] = blks[line[j] >> 5];
989                     strcat(output, str);
990                 }
991                 TRACE("%s\n", output);
992             }
993         }
994     }
995
996
997     if(formatEntry->glyphset) {
998         if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
999             unsigned char *byte = (unsigned char*) buf, c;
1000             int i = buflen;
1001
1002             while(i--) {
1003                 c = *byte;
1004
1005                 /* magic to flip bit order */
1006                 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1007                 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1008                 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1009
1010                 *byte++ = c;
1011             }
1012         }
1013         else if ( format != AA_Grey &&
1014                   ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1015         {
1016             unsigned int i, *data = (unsigned int *)buf;
1017             for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1018         }
1019         gid = glyph;
1020
1021         /*
1022           XRenderCompositeText seems to ignore 0x0 glyphs when
1023           AA_None, which means we lose the advance width of glyphs
1024           like the space.  We'll pretend that such glyphs are 1x1
1025           bitmaps.
1026         */
1027
1028         if(buflen == 0)
1029             gi.width = gi.height = 1;
1030
1031         wine_tsx11_lock();
1032         pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1033                           buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1034         wine_tsx11_unlock();
1035         HeapFree(GetProcessHeap(), 0, buf);
1036     } else {
1037         formatEntry->bitmaps[glyph] = buf;
1038     }
1039
1040     formatEntry->gis[glyph] = gi;
1041
1042     return TRUE;
1043 }
1044
1045 static void SharpGlyphMono(X11DRV_PDEVICE *physDev, INT x, INT y,
1046                             void *bitmap, XGlyphInfo *gi)
1047 {
1048     unsigned char   *srcLine = bitmap, *src;
1049     unsigned char   bits, bitsMask;
1050     int             width = gi->width;
1051     int             stride = ((width + 31) & ~31) >> 3;
1052     int             height = gi->height;
1053     int             w;
1054     int             xspan, lenspan;
1055
1056     TRACE("%d, %d\n", x, y);
1057     x -= gi->x;
1058     y -= gi->y;
1059     while (height--)
1060     {
1061         src = srcLine;
1062         srcLine += stride;
1063         w = width;
1064         
1065         bitsMask = 0x80;    /* FreeType is always MSB first */
1066         bits = *src++;
1067         
1068         xspan = x;
1069         while (w)
1070         {
1071             if (bits & bitsMask)
1072             {
1073                 lenspan = 0;
1074                 do
1075                 {
1076                     lenspan++;
1077                     if (lenspan == w)
1078                         break;
1079                     bitsMask = bitsMask >> 1;
1080                     if (!bitsMask)
1081                     {
1082                         bits = *src++;
1083                         bitsMask = 0x80;
1084                     }
1085                 } while (bits & bitsMask);
1086                 XFillRectangle (gdi_display, physDev->drawable, 
1087                                 physDev->gc, xspan, y, lenspan, 1);
1088                 xspan += lenspan;
1089                 w -= lenspan;
1090             }
1091             else
1092             {
1093                 do
1094                 {
1095                     w--;
1096                     xspan++;
1097                     if (!w)
1098                         break;
1099                     bitsMask = bitsMask >> 1;
1100                     if (!bitsMask)
1101                     {
1102                         bits = *src++;
1103                         bitsMask = 0x80;
1104                     }
1105                 } while (!(bits & bitsMask));
1106             }
1107         }
1108         y++;
1109     }
1110 }
1111
1112 static void SharpGlyphGray(X11DRV_PDEVICE *physDev, INT x, INT y,
1113                             void *bitmap, XGlyphInfo *gi)
1114 {
1115     unsigned char   *srcLine = bitmap, *src, bits;
1116     int             width = gi->width;
1117     int             stride = ((width + 3) & ~3);
1118     int             height = gi->height;
1119     int             w;
1120     int             xspan, lenspan;
1121
1122     x -= gi->x;
1123     y -= gi->y;
1124     while (height--)
1125     {
1126         src = srcLine;
1127         srcLine += stride;
1128         w = width;
1129         
1130         bits = *src++;
1131         xspan = x;
1132         while (w)
1133         {
1134             if (bits >= 0x80)
1135             {
1136                 lenspan = 0;
1137                 do
1138                 {
1139                     lenspan++;
1140                     if (lenspan == w)
1141                         break;
1142                     bits = *src++;
1143                 } while (bits >= 0x80);
1144                 XFillRectangle (gdi_display, physDev->drawable, 
1145                                 physDev->gc, xspan, y, lenspan, 1);
1146                 xspan += lenspan;
1147                 w -= lenspan;
1148             }
1149             else
1150             {
1151                 do
1152                 {
1153                     w--;
1154                     xspan++;
1155                     if (!w)
1156                         break;
1157                     bits = *src++;
1158                 } while (bits < 0x80);
1159             }
1160         }
1161         y++;
1162     }
1163 }
1164
1165
1166 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1167 {
1168     int s, l;
1169
1170     s = 0;
1171     while ((mask & 1) == 0)
1172     {
1173         mask >>= 1;
1174         s++;
1175     }
1176     l = 0;
1177     while ((mask & 1) == 1)
1178     {
1179         mask >>= 1;
1180         l++;
1181     }
1182     *shift = s;
1183     *len = l;
1184 }
1185
1186 static DWORD GetField (DWORD pixel, int shift, int len)
1187 {
1188     pixel = pixel & (((1 << (len)) - 1) << shift);
1189     pixel = pixel << (32 - (shift + len)) >> 24;
1190     while (len < 8)
1191     {
1192         pixel |= (pixel >> len);
1193         len <<= 1;
1194     }
1195     return pixel;
1196 }
1197
1198
1199 static DWORD PutField (DWORD pixel, int shift, int len)
1200 {
1201     shift = shift - (8 - len);
1202     if (len <= 8)
1203         pixel &= (((1 << len) - 1) << (8 - len));
1204     if (shift < 0)
1205         pixel >>= -shift;
1206     else
1207         pixel <<= shift;
1208     return pixel;
1209 }
1210
1211 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1212                             int color)
1213 {
1214     int             r_shift, r_len;
1215     int             g_shift, g_len;
1216     int             b_shift, b_len;
1217     BYTE            *maskLine, *mask, m;
1218     int             maskStride;
1219     DWORD           pixel;
1220     int             width, height;
1221     int             w, tx;
1222     BYTE            src_r, src_g, src_b;
1223
1224     x -= gi->x;
1225     y -= gi->y;
1226     width = gi->width;
1227     height = gi->height;
1228
1229     maskLine = bitmap;
1230     maskStride = (width + 3) & ~3;
1231
1232     ExamineBitfield (image->red_mask, &r_shift, &r_len);
1233     ExamineBitfield (image->green_mask, &g_shift, &g_len);
1234     ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1235
1236     src_r = GetField(color, r_shift, r_len);
1237     src_g = GetField(color, g_shift, g_len);
1238     src_b = GetField(color, b_shift, b_len);
1239     
1240     for(; height--; y++)
1241     {
1242         mask = maskLine;
1243         maskLine += maskStride;
1244         w = width;
1245         tx = x;
1246
1247         if(y < 0) continue;
1248         if(y >= image->height) break;
1249
1250         for(; w--; tx++)
1251         {
1252             if(tx >= image->width) break;
1253
1254             m = *mask++;
1255             if(tx < 0) continue;
1256
1257             if (m == 0xff)
1258                 XPutPixel (image, tx, y, color);
1259             else if (m)
1260             {
1261                 BYTE r, g, b;
1262
1263                 pixel = XGetPixel (image, tx, y);
1264
1265                 r = GetField(pixel, r_shift, r_len);
1266                 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1267                 g = GetField(pixel, g_shift, g_len);
1268                 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1269                 b = GetField(pixel, b_shift, b_len);
1270                 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1271
1272                 pixel = (PutField (r, r_shift, r_len) |
1273                          PutField (g, g_shift, g_len) |
1274                          PutField (b, b_shift, b_len));
1275                 XPutPixel (image, tx, y, pixel);
1276             }
1277         }
1278     }
1279 }
1280
1281 /*************************************************************
1282  *                 get_tile_pict
1283  *
1284  * Returns an appropriate Picture for tiling the text colour.
1285  * Call and use result within the xrender_cs
1286  */
1287 static Picture get_tile_pict(WineXRenderFormat *wxr_format, int text_pixel)
1288 {
1289     static struct
1290     {
1291         Pixmap xpm;
1292         Picture pict;
1293         int current_color;
1294     } tiles[MAX_FORMATS], *tile;
1295     XRenderColor col;
1296
1297     tile = &tiles[wxr_format->format];
1298
1299     if(!tile->xpm)
1300     {
1301         XRenderPictureAttributes pa;
1302
1303         wine_tsx11_lock();
1304         tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, wxr_format->pict_format->depth);
1305
1306         pa.repeat = RepeatNormal;
1307         tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, wxr_format->pict_format, CPRepeat, &pa);
1308         wine_tsx11_unlock();
1309
1310         /* init current_color to something different from text_pixel */
1311         tile->current_color = ~text_pixel;
1312
1313         if(wxr_format->format == WXR_FORMAT_MONO)
1314         {
1315             /* for a 1bpp bitmap we always need a 1 in the tile */
1316             col.red = col.green = col.blue = 0;
1317             col.alpha = 0xffff;
1318             wine_tsx11_lock();
1319             pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1320             wine_tsx11_unlock();
1321         }
1322     }
1323
1324     if(text_pixel != tile->current_color && wxr_format->format != WXR_FORMAT_MONO)
1325     {
1326         /* Map 0 -- 0xff onto 0 -- 0xffff */
1327         int r_shift, r_len;
1328         int g_shift, g_len;
1329         int b_shift, b_len;
1330
1331         ExamineBitfield (visual->red_mask, &r_shift, &r_len );
1332         ExamineBitfield (visual->green_mask, &g_shift, &g_len);
1333         ExamineBitfield (visual->blue_mask, &b_shift, &b_len);
1334
1335         col.red = GetField(text_pixel, r_shift, r_len);
1336         col.red |= col.red << 8;
1337         col.green = GetField(text_pixel, g_shift, g_len);
1338         col.green |= col.green << 8;
1339         col.blue = GetField(text_pixel, b_shift, b_len);
1340         col.blue |= col.blue << 8;
1341         col.alpha = 0xffff;
1342
1343         wine_tsx11_lock();
1344         pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1345         wine_tsx11_unlock();
1346         tile->current_color = text_pixel;
1347     }
1348     return tile->pict;
1349 }
1350
1351 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1352 {
1353     return 1;
1354 }
1355
1356 /***********************************************************************
1357  *   X11DRV_XRender_ExtTextOut
1358  */
1359 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1360                                 const RECT *lprect, LPCWSTR wstr, UINT count,
1361                                 const INT *lpDx )
1362 {
1363     RGNDATA *data;
1364     XGCValues xgcval;
1365     gsCacheEntry *entry;
1366     gsCacheEntryFormat *formatEntry;
1367     BOOL retv = FALSE;
1368     HDC hdc = physDev->hdc;
1369     int textPixel, backgroundPixel;
1370     HRGN saved_region = 0;
1371     BOOL disable_antialias = FALSE;
1372     AA_Type aa_type = AA_None;
1373     DIBSECTION bmp;
1374     unsigned int idx;
1375     double cosEsc, sinEsc;
1376     LOGFONTW lf;
1377     WineXRenderFormat *dst_format = get_xrender_format_from_pdevice(physDev);
1378     Picture tile_pict = 0;
1379
1380     /* Do we need to disable antialiasing because of palette mode? */
1381     if( !physDev->bitmap || GetObjectW( physDev->bitmap->hbitmap, sizeof(bmp), &bmp ) != sizeof(bmp) ) {
1382         TRACE("bitmap is not a DIB\n");
1383     }
1384     else if (bmp.dsBmih.biBitCount <= 8) {
1385         TRACE("Disabling antialiasing\n");
1386         disable_antialias = TRUE;
1387     }
1388
1389     xgcval.function = GXcopy;
1390     xgcval.background = physDev->backgroundPixel;
1391     xgcval.fill_style = FillSolid;
1392     wine_tsx11_lock();
1393     XChangeGC( gdi_display, physDev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1394     wine_tsx11_unlock();
1395
1396     X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1397
1398     if(physDev->depth == 1) {
1399         if((physDev->textPixel & 0xffffff) == 0) {
1400             textPixel = 0;
1401             backgroundPixel = 1;
1402         } else {
1403             textPixel = 1;
1404             backgroundPixel = 0;
1405         }
1406     } else {
1407         textPixel = physDev->textPixel;
1408         backgroundPixel = physDev->backgroundPixel;
1409     }
1410
1411     if(flags & ETO_OPAQUE)
1412     {
1413         wine_tsx11_lock();
1414         XSetForeground( gdi_display, physDev->gc, backgroundPixel );
1415         XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1416                         physDev->dc_rect.left + lprect->left, physDev->dc_rect.top + lprect->top,
1417                         lprect->right - lprect->left, lprect->bottom - lprect->top );
1418         wine_tsx11_unlock();
1419     }
1420
1421     if(count == 0)
1422     {
1423         retv = TRUE;
1424         goto done_unlock;
1425     }
1426
1427     
1428     GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf);
1429     if(lf.lfEscapement != 0) {
1430         cosEsc = cos(lf.lfEscapement * M_PI / 1800);
1431         sinEsc = sin(lf.lfEscapement * M_PI / 1800);
1432     } else {
1433         cosEsc = 1;
1434         sinEsc = 0;
1435     }
1436
1437     if (flags & ETO_CLIPPED)
1438     {
1439         HRGN clip_region;
1440
1441         clip_region = CreateRectRgnIndirect( lprect );
1442         /* make a copy of the current device region */
1443         saved_region = CreateRectRgn( 0, 0, 0, 0 );
1444         CombineRgn( saved_region, physDev->region, 0, RGN_COPY );
1445         X11DRV_SetDeviceClipping( physDev, saved_region, clip_region );
1446         DeleteObject( clip_region );
1447     }
1448
1449     if(X11DRV_XRender_Installed) {
1450         if(!physDev->xrender->pict) {
1451             XRenderPictureAttributes pa;
1452             pa.subwindow_mode = IncludeInferiors;
1453
1454             wine_tsx11_lock();
1455             physDev->xrender->pict = pXRenderCreatePicture(gdi_display,
1456                                                            physDev->drawable, dst_format->pict_format,
1457                                                            CPSubwindowMode, &pa);
1458             wine_tsx11_unlock();
1459
1460             TRACE("allocing pict = %lx dc = %p drawable = %08lx\n",
1461                   physDev->xrender->pict, hdc, physDev->drawable);
1462         } else {
1463             TRACE("using existing pict = %lx dc = %p drawable = %08lx\n",
1464                   physDev->xrender->pict, hdc, physDev->drawable);
1465         }
1466
1467         if ((data = X11DRV_GetRegionData( physDev->region, 0 )))
1468         {
1469             wine_tsx11_lock();
1470             pXRenderSetPictureClipRectangles( gdi_display, physDev->xrender->pict,
1471                                               physDev->dc_rect.left, physDev->dc_rect.top,
1472                                               (XRectangle *)data->Buffer, data->rdh.nCount );
1473             wine_tsx11_unlock();
1474             HeapFree( GetProcessHeap(), 0, data );
1475         }
1476     }
1477
1478     EnterCriticalSection(&xrender_cs);
1479
1480     entry = glyphsetCache + physDev->xrender->cache_index;
1481     if( disable_antialias == FALSE )
1482         aa_type = entry->aa_default;
1483     formatEntry = entry->format[aa_type];
1484
1485     for(idx = 0; idx < count; idx++) {
1486         if( !formatEntry ) {
1487             UploadGlyph(physDev, wstr[idx], aa_type);
1488             /* re-evaluate antialias since aa_default may have changed */
1489             if( disable_antialias == FALSE )
1490                 aa_type = entry->aa_default;
1491             formatEntry = entry->format[aa_type];
1492         } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1493             UploadGlyph(physDev, wstr[idx], aa_type);
1494         }
1495     }
1496     if (!formatEntry)
1497     {
1498         WARN("could not upload requested glyphs\n");
1499         LeaveCriticalSection(&xrender_cs);
1500         goto done_unlock;
1501     }
1502
1503     TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1504           physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1505
1506     if(X11DRV_XRender_Installed)
1507     {
1508         XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1509         INT offset = 0;
1510         POINT desired, current;
1511         int render_op = PictOpOver;
1512
1513         /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1514            So we pass zeros to the function and move to our starting position using the first
1515            element of the elts array. */
1516
1517         desired.x = physDev->dc_rect.left + x;
1518         desired.y = physDev->dc_rect.top + y;
1519         current.x = current.y = 0;
1520
1521         tile_pict = get_tile_pict(dst_format, physDev->textPixel);
1522
1523         /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1524          */
1525         if((dst_format->format == WXR_FORMAT_MONO) && (textPixel == 0))
1526             render_op = PictOpOutReverse; /* This gives us 'black' text */
1527
1528         for(idx = 0; idx < count; idx++)
1529         {
1530             elts[idx].glyphset = formatEntry->glyphset;
1531             elts[idx].chars = wstr + idx;
1532             elts[idx].nchars = 1;
1533             elts[idx].xOff = desired.x - current.x;
1534             elts[idx].yOff = desired.y - current.y;
1535
1536             current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1537             current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1538
1539             if(!lpDx)
1540             {
1541                 desired.x += formatEntry->gis[wstr[idx]].xOff;
1542                 desired.y += formatEntry->gis[wstr[idx]].yOff;
1543             }
1544             else
1545             {
1546                 offset += lpDx[idx];
1547                 desired.x = physDev->dc_rect.left + x + offset * cosEsc;
1548                 desired.y = physDev->dc_rect.top  + y - offset * sinEsc;
1549             }
1550         }
1551         wine_tsx11_lock();
1552         pXRenderCompositeText16(gdi_display, render_op,
1553                                 tile_pict,
1554                                 physDev->xrender->pict,
1555                                 formatEntry->font_format->pict_format,
1556                                 0, 0, 0, 0, elts, count);
1557         wine_tsx11_unlock();
1558         HeapFree(GetProcessHeap(), 0, elts);
1559     } else {
1560         INT offset = 0, xoff = 0, yoff = 0;
1561         wine_tsx11_lock();
1562         XSetForeground( gdi_display, physDev->gc, textPixel );
1563
1564         if(aa_type == AA_None || physDev->depth == 1)
1565         {
1566             void (* sharp_glyph_fn)(X11DRV_PDEVICE *, INT, INT, void *, XGlyphInfo *);
1567
1568             if(aa_type == AA_None)
1569                 sharp_glyph_fn = SharpGlyphMono;
1570             else
1571                 sharp_glyph_fn = SharpGlyphGray;
1572
1573             for(idx = 0; idx < count; idx++) {
1574                 sharp_glyph_fn(physDev, physDev->dc_rect.left + x + xoff,
1575                                physDev->dc_rect.top + y + yoff,
1576                                formatEntry->bitmaps[wstr[idx]],
1577                                &formatEntry->gis[wstr[idx]]);
1578                 if(lpDx) {
1579                     offset += lpDx[idx];
1580                     xoff = offset * cosEsc;
1581                     yoff = offset * -sinEsc;
1582                 } else {
1583                     xoff += formatEntry->gis[wstr[idx]].xOff;
1584                     yoff += formatEntry->gis[wstr[idx]].yOff;
1585                 }
1586             }
1587         } else {
1588             XImage *image;
1589             int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
1590             RECT extents = {0, 0, 0, 0};
1591             POINT cur = {0, 0};
1592             int w = physDev->drawable_rect.right - physDev->drawable_rect.left;
1593             int h = physDev->drawable_rect.bottom - physDev->drawable_rect.top;
1594
1595             TRACE("drawable %dx%d\n", w, h);
1596
1597             for(idx = 0; idx < count; idx++) {
1598                 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
1599                     extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
1600                 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
1601                     extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
1602                 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
1603                     extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
1604                 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
1605                     extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
1606                 if(lpDx) {
1607                     offset += lpDx[idx];
1608                     cur.x = offset * cosEsc;
1609                     cur.y = offset * -sinEsc;
1610                 } else {
1611                     cur.x += formatEntry->gis[wstr[idx]].xOff;
1612                     cur.y += formatEntry->gis[wstr[idx]].yOff;
1613                 }
1614             }
1615             TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
1616                   extents.right, extents.bottom, physDev->dc_rect.left + x, physDev->dc_rect.top + y);
1617
1618             if(physDev->dc_rect.left + x + extents.left >= 0) {
1619                 image_x = physDev->dc_rect.left + x + extents.left;
1620                 image_off_x = 0;
1621             } else {
1622                 image_x = 0;
1623                 image_off_x = physDev->dc_rect.left + x + extents.left;
1624             }
1625             if(physDev->dc_rect.top + y + extents.top >= 0) {
1626                 image_y = physDev->dc_rect.top + y + extents.top;
1627                 image_off_y = 0;
1628             } else {
1629                 image_y = 0;
1630                 image_off_y = physDev->dc_rect.top + y + extents.top;
1631             }
1632             if(physDev->dc_rect.left + x + extents.right < w)
1633                 image_w = physDev->dc_rect.left + x + extents.right - image_x;
1634             else
1635                 image_w = w - image_x;
1636             if(physDev->dc_rect.top + y + extents.bottom < h)
1637                 image_h = physDev->dc_rect.top + y + extents.bottom - image_y;
1638             else
1639                 image_h = h - image_y;
1640
1641             if(image_w <= 0 || image_h <= 0) goto no_image;
1642
1643             X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1644             image = XGetImage(gdi_display, physDev->drawable,
1645                               image_x, image_y, image_w, image_h,
1646                               AllPlanes, ZPixmap);
1647             X11DRV_check_error();
1648
1649             TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
1650                   gdi_display, (int)physDev->drawable, image_x, image_y,
1651                   image_w, image_h, AllPlanes, ZPixmap,
1652                   physDev->depth, image);
1653             if(!image) {
1654                 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
1655                                            physDev->depth);
1656                 GC gc;
1657                 XGCValues gcv;
1658
1659                 gcv.graphics_exposures = False;
1660                 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1661                 XCopyArea(gdi_display, physDev->drawable, xpm, gc, image_x, image_y,
1662                           image_w, image_h, 0, 0);
1663                 XFreeGC(gdi_display, gc);
1664                 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
1665                 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
1666                                   ZPixmap);
1667                 X11DRV_check_error();
1668                 XFreePixmap(gdi_display, xpm);
1669             }
1670             if(!image) goto no_image;
1671
1672             image->red_mask = visual->red_mask;
1673             image->green_mask = visual->green_mask;
1674             image->blue_mask = visual->blue_mask;
1675
1676             offset = xoff = yoff = 0;
1677             for(idx = 0; idx < count; idx++) {
1678                 SmoothGlyphGray(image, xoff + image_off_x - extents.left,
1679                                 yoff + image_off_y - extents.top,
1680                                 formatEntry->bitmaps[wstr[idx]],
1681                                 &formatEntry->gis[wstr[idx]],
1682                                 physDev->textPixel);
1683                 if(lpDx) {
1684                     offset += lpDx[idx];
1685                     xoff = offset * cosEsc;
1686                     yoff = offset * -sinEsc;
1687                 } else {
1688                     xoff += formatEntry->gis[wstr[idx]].xOff;
1689                     yoff += formatEntry->gis[wstr[idx]].yOff;
1690                 }
1691             }
1692             XPutImage(gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1693                       image_x, image_y, image_w, image_h);
1694             XDestroyImage(image);
1695         }
1696     no_image:
1697         wine_tsx11_unlock();
1698     }
1699     LeaveCriticalSection(&xrender_cs);
1700
1701     if (flags & ETO_CLIPPED)
1702     {
1703         /* restore the device region */
1704         X11DRV_SetDeviceClipping( physDev, saved_region, 0 );
1705         DeleteObject( saved_region );
1706     }
1707
1708     retv = TRUE;
1709
1710 done_unlock:
1711     X11DRV_UnlockDIBSection( physDev, TRUE );
1712     return retv;
1713 }
1714
1715 /******************************************************************************
1716  * AlphaBlend         (x11drv.@)
1717  */
1718 BOOL CDECL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1719                              X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1720                              BLENDFUNCTION blendfn)
1721 {
1722     XRenderPictureAttributes pa;
1723     Picture dst_pict, src_pict;
1724     Pixmap xpm;
1725     DIBSECTION dib;
1726     XImage *image;
1727     GC gc;
1728     XGCValues gcv;
1729     DWORD *dstbits, *data;
1730     int y, y2;
1731     POINT pts[2];
1732     BOOL top_down = FALSE;
1733     RGNDATA *rgndata;
1734     WineXRenderFormat *dst_format = get_xrender_format_from_pdevice(devDst);
1735     WineXRenderFormat *src_format;
1736     int repeat_src;
1737
1738     if(!X11DRV_XRender_Installed) {
1739         FIXME("Unable to AlphaBlend without Xrender\n");
1740         return FALSE;
1741     }
1742     pts[0].x = xDst;
1743     pts[0].y = yDst;
1744     pts[1].x = xDst + widthDst;
1745     pts[1].y = yDst + heightDst;
1746     LPtoDP(devDst->hdc, pts, 2);
1747     xDst      = pts[0].x;
1748     yDst      = pts[0].y;
1749     widthDst  = pts[1].x - pts[0].x;
1750     heightDst = pts[1].y - pts[0].y;
1751
1752     pts[0].x = xSrc;
1753     pts[0].y = ySrc;
1754     pts[1].x = xSrc + widthSrc;
1755     pts[1].y = ySrc + heightSrc;
1756     LPtoDP(devSrc->hdc, pts, 2);
1757     xSrc      = pts[0].x;
1758     ySrc      = pts[0].y;
1759     widthSrc  = pts[1].x - pts[0].x;
1760     heightSrc = pts[1].y - pts[0].y;
1761     if (!widthDst || !heightDst || !widthSrc || !heightSrc) return TRUE;
1762
1763     /* If the source is a 1x1 bitmap, tiling is equivalent to stretching, but
1764         tiling is much faster. Therefore, we do no stretching in this case. */
1765     repeat_src = widthSrc == 1 && heightSrc == 1;
1766
1767 #ifndef HAVE_XRENDERSETPICTURETRANSFORM
1768     if((widthDst != widthSrc || heightDst != heightSrc) && !repeat_src)
1769 #else
1770     if(!pXRenderSetPictureTransform && !repeat_src)
1771 #endif
1772     {
1773         FIXME("Unable to Stretch, XRenderSetPictureTransform is currently required\n");
1774         return FALSE;
1775     }
1776
1777     if (!devSrc->bitmap || GetObjectW( devSrc->bitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib))
1778     {
1779         static BOOL out = FALSE;
1780         if (!out)
1781         {
1782             FIXME("not a dibsection\n");
1783             out = TRUE;
1784         }
1785         return FALSE;
1786     }
1787
1788     if (xSrc < 0 || ySrc < 0 || widthSrc < 0 || heightSrc < 0 || xSrc + widthSrc > dib.dsBmih.biWidth
1789         || ySrc + heightSrc > abs(dib.dsBmih.biHeight))
1790     {
1791         WARN("Invalid src coords: (%d,%d), size %dx%d\n", xSrc, ySrc, widthSrc, heightSrc);
1792         SetLastError(ERROR_INVALID_PARAMETER);
1793         return FALSE;
1794     }
1795
1796     if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && blendfn.SourceConstantAlpha != 0xff)
1797         FIXME("Ignoring SourceConstantAlpha %d for AC_SRC_ALPHA\n", blendfn.SourceConstantAlpha);
1798
1799     if(dib.dsBm.bmBitsPixel != 32) {
1800         FIXME("not a 32 bpp dibsection\n");
1801         return FALSE;
1802     }
1803     dstbits = data = HeapAlloc(GetProcessHeap(), 0, heightSrc * widthSrc * 4);
1804
1805     if(dib.dsBmih.biHeight < 0) { /* top-down dib */
1806         top_down = TRUE;
1807         dstbits += widthSrc * (heightSrc - 1);
1808         y2 = ySrc;
1809         y = y2 + heightSrc - 1;
1810     }
1811     else
1812     {
1813         y = dib.dsBmih.biHeight - ySrc - 1;
1814         y2 = y - heightSrc + 1;
1815     }
1816
1817     if (blendfn.AlphaFormat & AC_SRC_ALPHA)
1818     {
1819         for(; y >= y2; y--)
1820         {
1821             memcpy(dstbits, (char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes + xSrc * 4,
1822                    widthSrc * 4);
1823             dstbits += (top_down ? -1 : 1) * widthSrc;
1824         }
1825     }
1826     else
1827     {
1828         DWORD source_alpha = (DWORD)blendfn.SourceConstantAlpha << 24;
1829         int x;
1830
1831         for(; y >= y2; y--)
1832         {
1833             DWORD *srcbits = (DWORD *)((char *)dib.dsBm.bmBits + y * dib.dsBm.bmWidthBytes) + xSrc;
1834             for (x = 0; x < widthSrc; x++)
1835             {
1836                 DWORD argb = *srcbits++;
1837                 argb = (argb & 0xffffff) | source_alpha;
1838                 *dstbits++ = argb;
1839             }
1840             if (top_down)  /* we traversed the row forward so we should go back by two rows */
1841                 dstbits -= 2 * widthSrc;
1842         }
1843
1844     }
1845
1846     rgndata = X11DRV_GetRegionData( devDst->region, 0 );
1847
1848     wine_tsx11_lock();
1849     image = XCreateImage(gdi_display, visual, 32, ZPixmap, 0,
1850                          (char*) data, widthSrc, heightSrc, 32, widthSrc * 4);
1851
1852     src_format = get_xrender_format(WXR_FORMAT_A8R8G8B8);
1853     TRACE("src_format %p\n", src_format);
1854     if(!src_format)
1855     {
1856         WARN("Unable to find a picture format supporting alpha, make sure X is running at 24-bit\n");
1857         return FALSE;
1858     }
1859
1860     pa.subwindow_mode = IncludeInferiors;
1861     pa.repeat = repeat_src ? RepeatNormal : RepeatNone;
1862
1863     /* FIXME use devDst->xrender->pict ? */
1864     dst_pict = pXRenderCreatePicture(gdi_display,
1865                                      devDst->drawable,
1866                                      dst_format->pict_format,
1867                                      CPSubwindowMode, &pa);
1868     TRACE("dst_pict %08lx\n", dst_pict);
1869     TRACE("src_drawable = %08lx\n", devSrc->drawable);
1870     xpm = XCreatePixmap(gdi_display,
1871                         root_window,
1872                         widthSrc, heightSrc, 32);
1873     gcv.graphics_exposures = False;
1874     gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
1875     TRACE("xpm = %08lx\n", xpm);
1876     XPutImage(gdi_display, xpm, gc, image, 0, 0, 0, 0, widthSrc, heightSrc);
1877
1878     src_pict = pXRenderCreatePicture(gdi_display,
1879                                      xpm, src_format->pict_format,
1880                                      CPSubwindowMode|CPRepeat, &pa);
1881     TRACE("src_pict %08lx\n", src_pict);
1882
1883     if (rgndata)
1884     {
1885         pXRenderSetPictureClipRectangles( gdi_display, dst_pict,
1886                                           devDst->dc_rect.left, devDst->dc_rect.top,
1887                                           (XRectangle *)rgndata->Buffer, 
1888                                           rgndata->rdh.nCount );
1889         HeapFree( GetProcessHeap(), 0, rgndata );
1890     }
1891
1892 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
1893     if(!repeat_src && (widthDst != widthSrc || heightDst != heightSrc)) {
1894         double xscale = widthSrc/(double)widthDst;
1895         double yscale = heightSrc/(double)heightDst;
1896         XTransform xform = {{
1897             { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(0) },
1898             { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(0) },
1899             { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
1900         }};
1901         pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
1902     }
1903 #endif
1904     pXRenderComposite(gdi_display, PictOpOver, src_pict, 0, dst_pict,
1905                       0, 0, 0, 0,
1906                       xDst + devDst->dc_rect.left, yDst + devDst->dc_rect.top, widthDst, heightDst);
1907
1908
1909     pXRenderFreePicture(gdi_display, src_pict);
1910     XFreePixmap(gdi_display, xpm);
1911     XFreeGC(gdi_display, gc);
1912     pXRenderFreePicture(gdi_display, dst_pict);
1913     image->data = NULL;
1914     XDestroyImage(image);
1915
1916     wine_tsx11_unlock();
1917     HeapFree(GetProcessHeap(), 0, data);
1918     return TRUE;
1919 }
1920
1921 #else /* SONAME_LIBXRENDER */
1922
1923 void X11DRV_XRender_Init(void)
1924 {
1925     TRACE("XRender support not compiled in.\n");
1926     return;
1927 }
1928
1929 void X11DRV_XRender_Finalize(void)
1930 {
1931 }
1932
1933 BOOL X11DRV_XRender_SelectFont(X11DRV_PDEVICE *physDev, HFONT hfont)
1934 {
1935   assert(0);
1936   return FALSE;
1937 }
1938
1939 void X11DRV_XRender_DeleteDC(X11DRV_PDEVICE *physDev)
1940 {
1941   assert(0);
1942   return;
1943 }
1944
1945 BOOL X11DRV_XRender_ExtTextOut( X11DRV_PDEVICE *physDev, INT x, INT y, UINT flags,
1946                                 const RECT *lprect, LPCWSTR wstr, UINT count,
1947                                 const INT *lpDx )
1948 {
1949   assert(0);
1950   return FALSE;
1951 }
1952
1953 void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev)
1954 {
1955   assert(0);
1956   return;
1957 }
1958
1959 /******************************************************************************
1960  * AlphaBlend         (x11drv.@)
1961  */
1962 BOOL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1963                        X11DRV_PDEVICE *devSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1964                        BLENDFUNCTION blendfn)
1965 {
1966   FIXME("not supported - XRENDER headers were missing at compile time\n");
1967   return FALSE;
1968 }
1969
1970 #endif /* SONAME_LIBXRENDER */