d3d9: Don't expose wined3d internal flags to the application.
[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  * Copyright 2009 Roderick Colenbrander
6  * Copyright 2011 Alexandre Julliard
7  *
8  * Some parts also:
9  * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <stdlib.h>
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "x11drv.h"
36 #include "winternl.h"
37 #include "wine/library.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
40
41 int using_client_side_fonts = FALSE;
42
43 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
44
45 #ifdef SONAME_LIBXRENDER
46
47 WINE_DECLARE_DEBUG_CHANNEL(winediag);
48
49 #include <X11/Xlib.h>
50 #include <X11/extensions/Xrender.h>
51
52 #ifndef RepeatNone  /* added in 0.10 */
53 #define RepeatNone    0
54 #define RepeatNormal  1
55 #define RepeatPad     2
56 #define RepeatReflect 3
57 #endif
58
59 enum wxr_format
60 {
61   WXR_FORMAT_MONO,
62   WXR_FORMAT_GRAY,
63   WXR_FORMAT_X1R5G5B5,
64   WXR_FORMAT_X1B5G5R5,
65   WXR_FORMAT_R5G6B5,
66   WXR_FORMAT_B5G6R5,
67   WXR_FORMAT_R8G8B8,
68   WXR_FORMAT_B8G8R8,
69   WXR_FORMAT_A8R8G8B8,
70   WXR_FORMAT_B8G8R8A8,
71   WXR_FORMAT_X8R8G8B8,
72   WXR_FORMAT_B8G8R8X8,
73   WXR_NB_FORMATS,
74   WXR_INVALID_FORMAT = WXR_NB_FORMATS
75 };
76
77 typedef struct wine_xrender_format_template
78 {
79     unsigned int depth;
80     unsigned int alpha;
81     unsigned int alphaMask;
82     unsigned int red;
83     unsigned int redMask;
84     unsigned int green;
85     unsigned int greenMask;
86     unsigned int blue;
87     unsigned int blueMask;
88 } WineXRenderFormatTemplate;
89
90 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
91 {
92     /* Format               depth   alpha   mask    red     mask    green   mask    blue    mask*/
93 /* WXR_FORMAT_MONO     */ { 1,      0,      0x01,   0,      0,      0,      0,      0,      0       },
94 /* WXR_FORMAT_GRAY     */ { 8,      0,      0xff,   0,      0,      0,      0,      0,      0       },
95 /* WXR_FORMAT_X1R5G5B5 */ { 16,     0,      0,      10,     0x1f,   5,      0x1f,   0,      0x1f    },
96 /* WXR_FORMAT_X1B5G5R5 */ { 16,     0,      0,      0,      0x1f,   5,      0x1f,   10,     0x1f    },
97 /* WXR_FORMAT_R5G6B5   */ { 16,     0,      0,      11,     0x1f,   5,      0x3f,   0,      0x1f    },
98 /* WXR_FORMAT_B5G6R5   */ { 16,     0,      0,      0,      0x1f,   5,      0x3f,   11,     0x1f    },
99 /* WXR_FORMAT_R8G8B8   */ { 24,     0,      0,      16,     0xff,   8,      0xff,   0,      0xff    },
100 /* WXR_FORMAT_B8G8R8   */ { 24,     0,      0,      0,      0xff,   8,      0xff,   16,     0xff    },
101 /* WXR_FORMAT_A8R8G8B8 */ { 32,     24,     0xff,   16,     0xff,   8,      0xff,   0,      0xff    },
102 /* WXR_FORMAT_B8G8R8A8 */ { 32,     0,      0xff,   8,      0xff,   16,     0xff,   24,     0xff    },
103 /* WXR_FORMAT_X8R8G8B8 */ { 32,     0,      0,      16,     0xff,   8,      0xff,   0,      0xff    },
104 /* WXR_FORMAT_B8G8R8X8 */ { 32,     0,      0,      8,      0xff,   16,     0xff,   24,     0xff    },
105 };
106
107 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
108 {
109     /* format                phys red    phys green  phys blue   log red     log green   log blue */
110 /* WXR_FORMAT_MONO     */ { { 0,0,0 },  { 0,0,0 },  { 0,0,0 },  { 0,0,0 },  { 0,0,0 },  { 0,0,0 }  },
111 /* WXR_FORMAT_GRAY     */ { { 0,0,0 },  { 0,0,0 },  { 0,0,0 },  { 0,0,0 },  { 0,0,0 },  { 0,0,0 }  },
112 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31},  { 5,5,31},  { 0,5,31},  {10,5,31},  { 5,5,31},  { 0,5,31}  },
113 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31},  { 5,5,31},  {10,5,31},  { 0,5,31},  { 5,5,31},  {10,5,31}  },
114 /* WXR_FORMAT_R5G6B5   */ { {11,5,31},  { 5,6,63},  { 0,5,31},  {11,5,31},  { 5,6,63},  { 0,5,31}  },
115 /* WXR_FORMAT_B5G6R5   */ { { 0,5,31},  { 5,6,63},  {11,5,31},  { 0,5,31},  { 5,6,63},  {11,5,31}  },
116 /* WXR_FORMAT_R8G8B8   */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8   */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
118 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
120 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
122 };
123
124 static enum wxr_format default_format = WXR_INVALID_FORMAT;
125 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
126
127 typedef struct
128 {
129     LOGFONTW lf;
130     XFORM    xform;
131     SIZE     devsize;  /* size in device coords */
132     DWORD    hash;
133 } LFANDSIZE;
134
135 #define INITIAL_REALIZED_BUF_SIZE 128
136
137 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
138
139 typedef struct
140 {
141     GlyphSet glyphset;
142     XRenderPictFormat *font_format;
143     int nrealized;
144     BOOL *realized;
145     XGlyphInfo *gis;
146 } gsCacheEntryFormat;
147
148 typedef struct
149 {
150     LFANDSIZE lfsz;
151     AA_Type aa_default;
152     gsCacheEntryFormat * format[AA_MAXVALUE];
153     INT count;
154     INT next;
155 } gsCacheEntry;
156
157 struct xrender_physdev
158 {
159     struct gdi_physdev dev;
160     X11DRV_PDEVICE    *x11dev;
161     HRGN               region;
162     enum wxr_format    format;
163     int                cache_index;
164     BOOL               update_clip;
165     Picture            pict;
166     Picture            pict_src;
167     XRenderPictFormat *pict_format;
168 };
169
170 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
171 {
172     return (struct xrender_physdev *)dev;
173 }
174
175 static const struct gdi_dc_funcs xrender_funcs;
176
177 static gsCacheEntry *glyphsetCache = NULL;
178 static DWORD glyphsetCacheSize = 0;
179 static INT lastfree = -1;
180 static INT mru = -1;
181
182 #define INIT_CACHE_SIZE 10
183
184 static int antialias = 1;
185
186 static void *xrender_handle;
187
188 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
189 MAKE_FUNCPTR(XRenderAddGlyphs)
190 MAKE_FUNCPTR(XRenderChangePicture)
191 MAKE_FUNCPTR(XRenderComposite)
192 MAKE_FUNCPTR(XRenderCompositeText16)
193 MAKE_FUNCPTR(XRenderCreateGlyphSet)
194 MAKE_FUNCPTR(XRenderCreatePicture)
195 MAKE_FUNCPTR(XRenderFillRectangle)
196 MAKE_FUNCPTR(XRenderFindFormat)
197 MAKE_FUNCPTR(XRenderFindVisualFormat)
198 MAKE_FUNCPTR(XRenderFreeGlyphSet)
199 MAKE_FUNCPTR(XRenderFreePicture)
200 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
201 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
202 MAKE_FUNCPTR(XRenderCreateLinearGradient)
203 #endif
204 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
205 MAKE_FUNCPTR(XRenderSetPictureTransform)
206 #endif
207 MAKE_FUNCPTR(XRenderQueryExtension)
208
209 #ifdef SONAME_LIBFONTCONFIG
210 #include <fontconfig/fontconfig.h>
211 MAKE_FUNCPTR(FcConfigSubstitute)
212 MAKE_FUNCPTR(FcDefaultSubstitute)
213 MAKE_FUNCPTR(FcFontMatch)
214 MAKE_FUNCPTR(FcInit)
215 MAKE_FUNCPTR(FcPatternCreate)
216 MAKE_FUNCPTR(FcPatternDestroy)
217 MAKE_FUNCPTR(FcPatternAddInteger)
218 MAKE_FUNCPTR(FcPatternAddString)
219 MAKE_FUNCPTR(FcPatternGetBool)
220 MAKE_FUNCPTR(FcPatternGetInteger)
221 MAKE_FUNCPTR(FcPatternGetString)
222 static void *fontconfig_handle;
223 static BOOL fontconfig_installed;
224 #endif
225
226 #undef MAKE_FUNCPTR
227
228 static CRITICAL_SECTION xrender_cs;
229 static CRITICAL_SECTION_DEBUG critsect_debug =
230 {
231     0, 0, &xrender_cs,
232     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
233       0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
234 };
235 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
236
237 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
238           ( ( (ULONG)_x4 << 24 ) |     \
239             ( (ULONG)_x3 << 16 ) |     \
240             ( (ULONG)_x2 <<  8 ) |     \
241               (ULONG)_x1         )
242
243 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
244
245 #define GASP_GRIDFIT 0x01
246 #define GASP_DOGRAY  0x02
247
248 #ifdef WORDS_BIGENDIAN
249 #define get_be_word(x) (x)
250 #define NATIVE_BYTE_ORDER MSBFirst
251 #else
252 #define get_be_word(x) RtlUshortByteSwap(x)
253 #define NATIVE_BYTE_ORDER LSBFirst
254 #endif
255
256 static BOOL has_alpha( enum wxr_format format )
257 {
258     return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
259 }
260
261 static enum wxr_format get_format_without_alpha( enum wxr_format format )
262 {
263     switch (format)
264     {
265     case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
266     case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
267     default: return format;
268     }
269 }
270
271 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
272 {
273     templ->id = 0;
274     templ->type = PictTypeDirect;
275     templ->depth = fmt->depth;
276     templ->direct.alpha = fmt->alpha;
277     templ->direct.alphaMask = fmt->alphaMask;
278     templ->direct.red = fmt->red;
279     templ->direct.redMask = fmt->redMask;
280     templ->direct.green = fmt->green;
281     templ->direct.greenMask = fmt->greenMask;
282     templ->direct.blue = fmt->blue;
283     templ->direct.blueMask = fmt->blueMask;
284     templ->colormap = 0;
285
286     *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
287
288     return TRUE;
289 }
290
291 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
292 {
293     if(fmt->depth != screen_depth)
294         return FALSE;
295     if( (fmt->redMask << fmt->red) != visual->red_mask)
296         return FALSE;
297     if( (fmt->greenMask << fmt->green) != visual->green_mask)
298         return FALSE;
299     if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
300         return FALSE;
301
302     /* We never select a default ARGB visual */
303     if(fmt->alphaMask)
304         return FALSE;
305
306     return TRUE;
307 }
308
309 static int load_xrender_formats(void)
310 {
311     int count = 0;
312     unsigned int i;
313
314     for (i = 0; i < WXR_NB_FORMATS; i++)
315     {
316         XRenderPictFormat templ;
317
318         if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
319         {
320             wine_tsx11_lock();
321             pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
322             if (!pict_formats[i])
323             {
324                 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
325                 if (visual->class == DirectColor)
326                 {
327                     XVisualInfo info;
328                     if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
329                                           screen_depth, TrueColor, &info ))
330                     {
331                         pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
332                         if (pict_formats[i]) visual = info.visual;
333                     }
334                 }
335             }
336             wine_tsx11_unlock();
337             if (pict_formats[i]) default_format = i;
338         }
339         else
340         {
341             unsigned long mask = 0;
342             get_xrender_template(&wxr_formats_template[i], &templ, &mask);
343
344             wine_tsx11_lock();
345             pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
346             wine_tsx11_unlock();
347         }
348         if (pict_formats[i])
349         {
350             count++;
351             TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
352         }
353     }
354     return count;
355 }
356
357 /***********************************************************************
358  *   X11DRV_XRender_Init
359  *
360  * Let's see if our XServer has the extension available
361  *
362  */
363 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
364 {
365     int event_base, i;
366     BOOL ok;
367
368     using_client_side_fonts = client_side_with_render || client_side_with_core;
369
370     if (!client_side_with_render) return NULL;
371     if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
372
373 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
374 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
375     LOAD_FUNCPTR(XRenderAddGlyphs);
376     LOAD_FUNCPTR(XRenderChangePicture);
377     LOAD_FUNCPTR(XRenderComposite);
378     LOAD_FUNCPTR(XRenderCompositeText16);
379     LOAD_FUNCPTR(XRenderCreateGlyphSet);
380     LOAD_FUNCPTR(XRenderCreatePicture);
381     LOAD_FUNCPTR(XRenderFillRectangle);
382     LOAD_FUNCPTR(XRenderFindFormat);
383     LOAD_FUNCPTR(XRenderFindVisualFormat);
384     LOAD_FUNCPTR(XRenderFreeGlyphSet);
385     LOAD_FUNCPTR(XRenderFreePicture);
386     LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
387     LOAD_FUNCPTR(XRenderQueryExtension);
388 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
389     LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
390 #endif
391 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
392     LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
393 #endif
394 #undef LOAD_OPTIONAL_FUNCPTR
395 #undef LOAD_FUNCPTR
396
397     wine_tsx11_lock();
398     ok = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
399     wine_tsx11_unlock();
400     if (!ok) return NULL;
401
402     TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
403     if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
404     {
405         ERR_(winediag)("Wine has detected that you probably have a buggy version "
406                        "of libXrender.  Because of this client side font rendering "
407                        "will be disabled.  Please upgrade this library.\n");
408         return NULL;
409     }
410
411     if (!visual->red_mask || !visual->green_mask || !visual->blue_mask)
412     {
413         WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
414         return NULL;
415     }
416
417 #ifdef SONAME_LIBFONTCONFIG
418     if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
419     {
420 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fontconfig_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
421         LOAD_FUNCPTR(FcConfigSubstitute);
422         LOAD_FUNCPTR(FcDefaultSubstitute);
423         LOAD_FUNCPTR(FcFontMatch);
424         LOAD_FUNCPTR(FcInit);
425         LOAD_FUNCPTR(FcPatternCreate);
426         LOAD_FUNCPTR(FcPatternDestroy);
427         LOAD_FUNCPTR(FcPatternAddInteger);
428         LOAD_FUNCPTR(FcPatternAddString);
429         LOAD_FUNCPTR(FcPatternGetBool);
430         LOAD_FUNCPTR(FcPatternGetInteger);
431         LOAD_FUNCPTR(FcPatternGetString);
432 #undef LOAD_FUNCPTR
433         fontconfig_installed = pFcInit();
434     }
435     else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
436
437 sym_not_found:
438 #endif
439
440     glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
441                               sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
442
443     glyphsetCacheSize = INIT_CACHE_SIZE;
444     lastfree = 0;
445     for(i = 0; i < INIT_CACHE_SIZE; i++) {
446         glyphsetCache[i].next = i + 1;
447         glyphsetCache[i].count = -1;
448     }
449     glyphsetCache[i-1].next = -1;
450
451     if(screen_depth <= 8 || !client_side_antialias_with_render) antialias = 0;
452
453     return &xrender_funcs;
454 }
455
456 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
457 static void get_xrender_color( struct xrender_physdev *physdev, COLORREF src_color, XRenderColor *dst_color )
458 {
459     if (src_color & (1 << 24))  /* PALETTEINDEX */
460     {
461         HPALETTE pal = GetCurrentObject( physdev->dev.hdc, OBJ_PAL );
462         PALETTEENTRY pal_ent;
463
464         if (!GetPaletteEntries( pal, LOWORD(src_color), 1, &pal_ent ))
465             GetPaletteEntries( pal, 0, 1, &pal_ent );
466         dst_color->red   = pal_ent.peRed   * 257;
467         dst_color->green = pal_ent.peGreen * 257;
468         dst_color->blue  = pal_ent.peBlue  * 257;
469     }
470     else
471     {
472         if (src_color >> 16 == 0x10ff) src_color = 0; /* DIBINDEX */
473
474         dst_color->red   = GetRValue( src_color ) * 257;
475         dst_color->green = GetGValue( src_color ) * 257;
476         dst_color->blue  = GetBValue( src_color ) * 257;
477     }
478
479     if (physdev->format == WXR_FORMAT_MONO && !dst_color->red && !dst_color->green && !dst_color->blue)
480         dst_color->alpha = 0;
481     else
482         dst_color->alpha = 0xffff;
483 }
484
485 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
486 {
487     if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
488
489     switch (info->bmiHeader.biBitCount)
490     {
491     case 1:
492         return WXR_FORMAT_MONO;
493     case 4:
494     case 8:
495         break;
496     case 24:
497         if (info->bmiHeader.biCompression != BI_RGB) break;
498         return WXR_FORMAT_R8G8B8;
499     case 16:
500     case 32:
501         if (info->bmiHeader.biCompression == BI_BITFIELDS)
502         {
503             DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
504             unsigned int i;
505
506             for (i = 0; i < WXR_NB_FORMATS; i++)
507             {
508                 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
509                     colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
510                     colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
511                     colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
512                     return i;
513             }
514             break;
515         }
516         if (info->bmiHeader.biCompression != BI_RGB) break;
517         return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
518     }
519     return WXR_INVALID_FORMAT;
520 }
521
522 static enum wxr_format get_bitmap_format( int bpp )
523 {
524     enum wxr_format format = WXR_INVALID_FORMAT;
525
526     if (bpp == screen_bpp)
527     {
528         switch (bpp)
529         {
530         case 16: format = WXR_FORMAT_R5G6B5; break;
531         case 24: format = WXR_FORMAT_R8G8B8; break;
532         case 32: format = WXR_FORMAT_A8R8G8B8; break;
533         }
534     }
535     return format;
536 }
537
538 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
539 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
540 {
541 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
542     XTransform xform = {{
543         { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
544         { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
545         { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
546     }};
547
548     pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
549 #endif
550 }
551
552 /* check if we can use repeating instead of scaling for the specified source DC */
553 static BOOL use_source_repeat( struct xrender_physdev *dev )
554 {
555     return (dev->x11dev->bitmap &&
556             dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
557             dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
558 }
559
560 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
561 {
562     XRenderPictureAttributes pa;
563     RGNDATA *data;
564
565     if (!rgn)
566     {
567         wine_tsx11_lock();
568         pa.clip_mask = None;
569         pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
570         wine_tsx11_unlock();
571     }
572     else if ((data = X11DRV_GetRegionData( rgn, 0 )))
573     {
574         wine_tsx11_lock();
575         pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
576                                           dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
577                                           (XRectangle *)data->Buffer, data->rdh.nCount );
578         wine_tsx11_unlock();
579         HeapFree( GetProcessHeap(), 0, data );
580     }
581 }
582
583
584 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
585 {
586     if (!dev->pict && dev->pict_format)
587     {
588         XRenderPictureAttributes pa;
589
590         wine_tsx11_lock();
591         pa.subwindow_mode = IncludeInferiors;
592         dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
593                                            dev->pict_format, CPSubwindowMode, &pa );
594         wine_tsx11_unlock();
595         TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
596                dev->pict, dev->dev.hdc, dev->x11dev->drawable );
597         dev->update_clip = (dev->region != 0);
598     }
599
600     if (clip_rect)
601     {
602         HRGN rgn = CreateRectRgnIndirect( clip_rect );
603         if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
604         if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
605         update_xrender_clipping( dev, rgn );
606         DeleteObject( rgn );
607     }
608     else if (clip_rgn)
609     {
610         if (dev->region)
611         {
612             HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
613             CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
614             update_xrender_clipping( dev, rgn );
615             DeleteObject( rgn );
616         }
617         else update_xrender_clipping( dev, clip_rgn );
618     }
619     else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
620
621     dev->update_clip = (clip_rect || clip_rgn);  /* have to update again if we are using a custom region */
622     return dev->pict;
623 }
624
625 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
626 {
627     if (!dev->pict_src && dev->pict_format)
628     {
629         XRenderPictureAttributes pa;
630
631         wine_tsx11_lock();
632         pa.subwindow_mode = IncludeInferiors;
633         pa.repeat = repeat ? RepeatNormal : RepeatNone;
634         dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
635                                                dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
636         wine_tsx11_unlock();
637
638         TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
639               dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
640     }
641
642     return dev->pict_src;
643 }
644
645 static void free_xrender_picture( struct xrender_physdev *dev )
646 {
647     if (dev->pict || dev->pict_src)
648     {
649         wine_tsx11_lock();
650         XFlush( gdi_display );
651         if (dev->pict)
652         {
653             TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
654             pXRenderFreePicture(gdi_display, dev->pict);
655             dev->pict = 0;
656         }
657         if(dev->pict_src)
658         {
659             TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
660             pXRenderFreePicture(gdi_display, dev->pict_src);
661             dev->pict_src = 0;
662         }
663         wine_tsx11_unlock();
664     }
665 }
666
667 /* return a mask picture used to force alpha to 0 */
668 static Picture get_no_alpha_mask(void)
669 {
670     static Pixmap pixmap;
671     static Picture pict;
672
673     wine_tsx11_lock();
674     if (!pict)
675     {
676         XRenderPictureAttributes pa;
677         XRenderColor col;
678
679         pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
680         pa.repeat = RepeatNormal;
681         pa.component_alpha = True;
682         pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
683                                       CPRepeat|CPComponentAlpha, &pa );
684         col.red = col.green = col.blue = 0xffff;
685         col.alpha = 0;
686         pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
687     }
688     wine_tsx11_unlock();
689     return pict;
690 }
691
692 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
693 {
694   if(p1->hash != p2->hash) return TRUE;
695   if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
696   if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
697   if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
698   return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
699 }
700
701 #if 0
702 static void walk_cache(void)
703 {
704   int i;
705
706   EnterCriticalSection(&xrender_cs);
707   for(i=mru; i >= 0; i = glyphsetCache[i].next)
708     TRACE("item %d\n", i);
709   LeaveCriticalSection(&xrender_cs);
710 }
711 #endif
712
713 static int LookupEntry(LFANDSIZE *plfsz)
714 {
715   int i, prev_i = -1;
716
717   for(i = mru; i >= 0; i = glyphsetCache[i].next) {
718     TRACE("%d\n", i);
719     if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
720
721     if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
722       glyphsetCache[i].count++;
723       if(prev_i >= 0) {
724         glyphsetCache[prev_i].next = glyphsetCache[i].next;
725         glyphsetCache[i].next = mru;
726         mru = i;
727       }
728       TRACE("found font in cache %d\n", i);
729       return i;
730     }
731     prev_i = i;
732   }
733   TRACE("font not in cache\n");
734   return -1;
735 }
736
737 static void FreeEntry(int entry)
738 {
739     int format;
740
741     for(format = 0; format < AA_MAXVALUE; format++) {
742         gsCacheEntryFormat * formatEntry;
743
744         if( !glyphsetCache[entry].format[format] )
745             continue;
746
747         formatEntry = glyphsetCache[entry].format[format];
748
749         if(formatEntry->glyphset) {
750             wine_tsx11_lock();
751             pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
752             wine_tsx11_unlock();
753             formatEntry->glyphset = 0;
754         }
755         if(formatEntry->nrealized) {
756             HeapFree(GetProcessHeap(), 0, formatEntry->realized);
757             formatEntry->realized = NULL;
758             HeapFree(GetProcessHeap(), 0, formatEntry->gis);
759             formatEntry->gis = NULL;
760             formatEntry->nrealized = 0;
761         }
762
763         HeapFree(GetProcessHeap(), 0, formatEntry);
764         glyphsetCache[entry].format[format] = NULL;
765     }
766 }
767
768 static int AllocEntry(void)
769 {
770   int best = -1, prev_best = -1, i, prev_i = -1;
771
772   if(lastfree >= 0) {
773     assert(glyphsetCache[lastfree].count == -1);
774     glyphsetCache[lastfree].count = 1;
775     best = lastfree;
776     lastfree = glyphsetCache[lastfree].next;
777     assert(best != mru);
778     glyphsetCache[best].next = mru;
779     mru = best;
780
781     TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
782     return mru;
783   }
784
785   for(i = mru; i >= 0; i = glyphsetCache[i].next) {
786     if(glyphsetCache[i].count == 0) {
787       best = i;
788       prev_best = prev_i;
789     }
790     prev_i = i;
791   }
792
793   if(best >= 0) {
794     TRACE("freeing unused glyphset at cache %d\n", best);
795     FreeEntry(best);
796     glyphsetCache[best].count = 1;
797     if(prev_best >= 0) {
798       glyphsetCache[prev_best].next = glyphsetCache[best].next;
799       glyphsetCache[best].next = mru;
800       mru = best;
801     } else {
802       assert(mru == best);
803     }
804     return mru;
805   }
806
807   TRACE("Growing cache\n");
808   
809   if (glyphsetCache)
810     glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
811                               glyphsetCache,
812                               (glyphsetCacheSize + INIT_CACHE_SIZE)
813                               * sizeof(*glyphsetCache));
814   else
815     glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
816                               (glyphsetCacheSize + INIT_CACHE_SIZE)
817                               * sizeof(*glyphsetCache));
818
819   for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
820       i++) {
821     glyphsetCache[i].next = i + 1;
822     glyphsetCache[i].count = -1;
823   }
824   glyphsetCache[i-1].next = -1;
825   glyphsetCacheSize += INIT_CACHE_SIZE;
826
827   lastfree = glyphsetCache[best].next;
828   glyphsetCache[best].count = 1;
829   glyphsetCache[best].next = mru;
830   mru = best;
831   TRACE("new free cache slot at %d\n", mru);
832   return mru;
833 }
834
835 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
836 {
837     DWORD size;
838     WORD *gasp, *buffer;
839     WORD num_recs;
840     DWORD ppem;
841     TEXTMETRICW tm;
842
843     *flags = 0;
844
845     size = GetFontData(hdc, MS_GASP_TAG,  0, NULL, 0);
846     if(size == GDI_ERROR)
847         return FALSE;
848
849     gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
850     GetFontData(hdc, MS_GASP_TAG,  0, gasp, size);
851
852     GetTextMetricsW(hdc, &tm);
853     ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
854
855     gasp++;
856     num_recs = get_be_word(*gasp);
857     gasp++;
858     while(num_recs--)
859     {
860         *flags = get_be_word(*(gasp + 1));
861         if(ppem <= get_be_word(*gasp))
862             break;
863         gasp += 2;
864     }
865     TRACE("got flags %04x for ppem %d\n", *flags, ppem);
866
867     HeapFree(GetProcessHeap(), 0, buffer);
868     return TRUE;
869 }
870
871 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
872 {
873     AA_Type ret;
874     WORD flags;
875     UINT font_smoothing_type, font_smoothing_orientation;
876
877     if (subpixel &&
878         SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
879         font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
880     {
881         if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
882                                     &font_smoothing_orientation, 0) &&
883              font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
884         {
885             ret = AA_BGR;
886         }
887         else
888             ret = AA_RGB;
889         /*FIXME
890           If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
891           But, Wine's subpixel rendering can support the portrait mode.
892          */
893     }
894     else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
895         ret = AA_Grey;
896     else
897         ret = AA_None;
898
899     return ret;
900 }
901
902 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
903 {
904     int ret;
905     int format;
906     gsCacheEntry *entry;
907     static int hinter = -1;
908     static int subpixel = -1;
909     BOOL font_smoothing;
910
911     if((ret = LookupEntry(plfsz)) != -1) return ret;
912
913     ret = AllocEntry();
914     entry = glyphsetCache + ret;
915     entry->lfsz = *plfsz;
916     for( format = 0; format < AA_MAXVALUE; format++ ) {
917         assert( !entry->format[format] );
918     }
919
920     if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
921     {
922         if(hinter == -1 || subpixel == -1)
923         {
924             RASTERIZER_STATUS status;
925             GetRasterizerCaps(&status, sizeof(status));
926             hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
927             subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
928         }
929
930         switch (plfsz->lf.lfQuality)
931         {
932             case ANTIALIASED_QUALITY:
933                 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
934                 return ret;  /* ignore further configuration */
935             case CLEARTYPE_QUALITY:
936             case CLEARTYPE_NATURAL_QUALITY:
937                 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
938                 break;
939             case DEFAULT_QUALITY:
940             case DRAFT_QUALITY:
941             case PROOF_QUALITY:
942             default:
943                 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
944                      font_smoothing)
945                 {
946                     entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
947                 }
948                 else
949                     entry->aa_default = AA_None;
950                 break;
951         }
952
953         font_smoothing = TRUE;  /* default to enabled */
954 #ifdef SONAME_LIBFONTCONFIG
955         if (fontconfig_installed)
956         {
957             FcPattern *match, *pattern;
958             FcResult result;
959             char family[LF_FACESIZE * 4];
960
961 #if defined(__i386__) && defined(__GNUC__)
962             /* fontconfig generates floating point exceptions, mask them */
963             WORD cw, default_cw = 0x37f;
964             __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
965 #endif
966
967             WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
968             pattern = pFcPatternCreate();
969             pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
970             if (plfsz->lf.lfWeight != FW_DONTCARE)
971             {
972                 int weight;
973                 switch (plfsz->lf.lfWeight)
974                 {
975                 case FW_THIN:       weight = FC_WEIGHT_THIN; break;
976                 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
977                 case FW_LIGHT:      weight = FC_WEIGHT_LIGHT; break;
978                 case FW_NORMAL:     weight = FC_WEIGHT_NORMAL; break;
979                 case FW_MEDIUM:     weight = FC_WEIGHT_MEDIUM; break;
980                 case FW_SEMIBOLD:   weight = FC_WEIGHT_SEMIBOLD; break;
981                 case FW_BOLD:       weight = FC_WEIGHT_BOLD; break;
982                 case FW_EXTRABOLD:  weight = FC_WEIGHT_EXTRABOLD; break;
983                 case FW_HEAVY:      weight = FC_WEIGHT_HEAVY; break;
984                 default:            weight = (plfsz->lf.lfWeight - 80) / 4; break;
985                 }
986                 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
987             }
988             pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
989             pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
990             pFcDefaultSubstitute( pattern );
991             if ((match = pFcFontMatch( NULL, pattern, &result )))
992             {
993                 int rgba;
994                 FcBool antialias;
995
996                 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
997                     antialias = TRUE;
998                 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
999                 {
1000                     FcChar8 *file;
1001                     if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
1002
1003                     TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
1004                            rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
1005
1006                     switch (rgba)
1007                     {
1008                     case FC_RGBA_RGB:  entry->aa_default = AA_RGB; break;
1009                     case FC_RGBA_BGR:  entry->aa_default = AA_BGR; break;
1010                     case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1011                     case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1012                     case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1013                     }
1014                 }
1015                 if (!antialias) font_smoothing = FALSE;
1016                 pFcPatternDestroy( match );
1017             }
1018             pFcPatternDestroy( pattern );
1019
1020 #if defined(__i386__) && defined(__GNUC__)
1021             __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
1022 #endif
1023         }
1024 #endif  /* SONAME_LIBFONTCONFIG */
1025
1026         /* now check Xft resources */
1027         {
1028             char *value;
1029             BOOL antialias = TRUE;
1030
1031             wine_tsx11_lock();
1032             if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1033             {
1034                 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1035                     value[0] == '0' || !strcasecmp( value, "off" ))
1036                     antialias = FALSE;
1037             }
1038             if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1039             {
1040                 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1041                 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1042                 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1043                 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1044                 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1045                 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1046             }
1047             wine_tsx11_unlock();
1048             if (!antialias) font_smoothing = FALSE;
1049         }
1050
1051         if (!font_smoothing) entry->aa_default = AA_None;
1052     }
1053     else
1054         entry->aa_default = AA_None;
1055
1056     return ret;
1057 }
1058
1059 static void dec_ref_cache(int index)
1060 {
1061     assert(index >= 0);
1062     TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1063     assert(glyphsetCache[index].count > 0);
1064     glyphsetCache[index].count--;
1065 }
1066
1067 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1068 {
1069   DWORD hash = 0, *ptr, two_chars;
1070   WORD *pwc;
1071   int i;
1072
1073   hash ^= plfsz->devsize.cx;
1074   hash ^= plfsz->devsize.cy;
1075   for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1076     hash ^= *ptr;
1077   for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1078     hash ^= *ptr;
1079   for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1080     two_chars = *ptr;
1081     pwc = (WCHAR *)&two_chars;
1082     if(!*pwc) break;
1083     *pwc = toupperW(*pwc);
1084     pwc++;
1085     *pwc = toupperW(*pwc);
1086     hash ^= two_chars;
1087     if(!*pwc) break;
1088   }
1089   plfsz->hash = hash;
1090   return;
1091 }
1092
1093 /***********************************************************************
1094  *   X11DRV_XRender_Finalize
1095  */
1096 void X11DRV_XRender_Finalize(void)
1097 {
1098     int i;
1099
1100     EnterCriticalSection(&xrender_cs);
1101     for(i = mru; i >= 0; i = glyphsetCache[i].next)
1102         FreeEntry(i);
1103     LeaveCriticalSection(&xrender_cs);
1104     DeleteCriticalSection(&xrender_cs);
1105 }
1106
1107 /**********************************************************************
1108  *           xrenderdrv_SelectFont
1109  */
1110 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1111 {
1112     struct xrender_physdev *physdev = get_xrender_dev( dev );
1113     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1114     HFONT ret = next->funcs->pSelectFont( next, hfont );
1115
1116     if (!ret) return 0;
1117
1118     if (physdev->x11dev->has_gdi_font)
1119     {
1120         LFANDSIZE lfsz;
1121
1122         GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1123
1124         TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1125               lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1126               lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1127         lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1128         lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1129         lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1130
1131         GetTransform( dev->hdc, 0x204, &lfsz.xform );
1132         TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1133               lfsz.xform.eM21, lfsz.xform.eM22);
1134
1135         /* Not used fields, would break hashing */
1136         lfsz.xform.eDx = lfsz.xform.eDy = 0;
1137
1138         lfsz_calc_hash(&lfsz);
1139
1140         EnterCriticalSection(&xrender_cs);
1141         if (physdev->cache_index != -1)
1142             dec_ref_cache( physdev->cache_index );
1143         physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1144         LeaveCriticalSection(&xrender_cs);
1145     }
1146     else
1147     {
1148         EnterCriticalSection( &xrender_cs );
1149         if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1150         physdev->cache_index = -1;
1151         LeaveCriticalSection( &xrender_cs );
1152     }
1153     return ret;
1154 }
1155
1156 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1157 {
1158     X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1159     struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1160
1161     if (!physdev) return FALSE;
1162     physdev->x11dev = x11dev;
1163     physdev->cache_index = -1;
1164     physdev->format = format;
1165     physdev->pict_format = pict_formats[format];
1166     push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1167     return TRUE;
1168 }
1169
1170 /* store the color mask data in the bitmap info structure */
1171 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1172 {
1173     DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1174
1175     info->bmiHeader.biPlanes      = 1;
1176     info->bmiHeader.biBitCount    = pixmap_formats[format->depth]->bits_per_pixel;
1177     info->bmiHeader.biCompression = BI_RGB;
1178     info->bmiHeader.biClrUsed     = 0;
1179
1180     switch (info->bmiHeader.biBitCount)
1181     {
1182     case 16:
1183         colors[0] = format->direct.redMask   << format->direct.red;
1184         colors[1] = format->direct.greenMask << format->direct.green;
1185         colors[2] = format->direct.blueMask  << format->direct.blue;
1186         info->bmiHeader.biCompression = BI_BITFIELDS;
1187         break;
1188     case 32:
1189         colors[0] = format->direct.redMask   << format->direct.red;
1190         colors[1] = format->direct.greenMask << format->direct.green;
1191         colors[2] = format->direct.blueMask  << format->direct.blue;
1192         if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1193             info->bmiHeader.biCompression = BI_BITFIELDS;
1194         break;
1195     }
1196 }
1197
1198
1199 /**********************************************************************
1200  *           xrenderdrv_CreateDC
1201  */
1202 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1203                                  LPCWSTR output, const DEVMODEW* initData )
1204 {
1205     return create_xrender_dc( pdev, default_format );
1206 }
1207
1208 /**********************************************************************
1209  *           xrenderdrv_CreateCompatibleDC
1210  */
1211 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1212 {
1213     if (orig)  /* chain to x11drv first */
1214     {
1215         orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1216         if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1217     }
1218     /* otherwise we have been called by x11drv */
1219
1220     return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1221 }
1222
1223 /**********************************************************************
1224  *           xrenderdrv_DeleteDC
1225  */
1226 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1227 {
1228     struct xrender_physdev *physdev = get_xrender_dev( dev );
1229
1230     free_xrender_picture( physdev );
1231
1232     EnterCriticalSection( &xrender_cs );
1233     if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1234     LeaveCriticalSection( &xrender_cs );
1235
1236     HeapFree( GetProcessHeap(), 0, physdev );
1237     return TRUE;
1238 }
1239
1240 /**********************************************************************
1241  *           xrenderdrv_ExtEscape
1242  */
1243 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1244                                  INT out_count, LPVOID out_data )
1245 {
1246     struct xrender_physdev *physdev = get_xrender_dev( dev );
1247
1248     dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1249
1250     if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1251     {
1252         if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1253         {
1254             BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1255             if (ret) free_xrender_picture( physdev );  /* pict format doesn't change, only drawable */
1256             return ret;
1257         }
1258     }
1259     return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1260 }
1261
1262 /****************************************************************************
1263  *        xrenderdrv_CopyBitmap
1264  */
1265 static BOOL xrenderdrv_CopyBitmap( HBITMAP src, HBITMAP dst )
1266 {
1267     return X11DRV_CopyBitmap( src, dst );
1268 }
1269
1270 /****************************************************************************
1271  *        xrenderdrv_CreateBitmap
1272  */
1273 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1274 {
1275     enum wxr_format format = WXR_INVALID_FORMAT;
1276     X_PHYSBITMAP *phys_bitmap;
1277     BITMAP bitmap;
1278
1279     if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1280
1281     if (bitmap.bmBitsPixel == 1)
1282     {
1283         if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, 1 ))) return FALSE;
1284         phys_bitmap->format = WXR_FORMAT_MONO;
1285         phys_bitmap->trueColor = FALSE;
1286     }
1287     else
1288     {
1289         format = get_bitmap_format( bitmap.bmBitsPixel );
1290
1291         if (pict_formats[format])
1292         {
1293             if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth )))
1294                 return FALSE;
1295             phys_bitmap->format = format;
1296             phys_bitmap->trueColor = TRUE;
1297             phys_bitmap->color_shifts = wxr_color_shifts[format];
1298         }
1299         else
1300         {
1301             if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, screen_depth )))
1302                 return FALSE;
1303             phys_bitmap->format = WXR_INVALID_FORMAT;
1304             phys_bitmap->trueColor = (visual->class == TrueColor || visual->class == DirectColor);
1305             phys_bitmap->color_shifts = X11DRV_PALETTE_default_shifts;
1306         }
1307     }
1308     return TRUE;
1309 }
1310
1311 /****************************************************************************
1312  *        xrenderdrv_DeleteBitmap
1313  */
1314 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1315 {
1316     return X11DRV_DeleteBitmap( hbitmap );
1317 }
1318
1319 /***********************************************************************
1320  *           xrenderdrv_SelectBitmap
1321  */
1322 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1323 {
1324     HBITMAP ret;
1325     struct xrender_physdev *physdev = get_xrender_dev( dev );
1326
1327     dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1328     ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1329     if (ret)
1330     {
1331         free_xrender_picture( physdev );
1332         if (hbitmap == BITMAP_stock_phys_bitmap.hbitmap) physdev->format = WXR_FORMAT_MONO;
1333         else physdev->format = X11DRV_get_phys_bitmap(hbitmap)->format;
1334         physdev->pict_format = pict_formats[physdev->format];
1335     }
1336     return ret;
1337 }
1338
1339 /***********************************************************************
1340  *           xrenderdrv_GetImage
1341  */
1342 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1343                                   struct gdi_image_bits *bits, struct bitblt_coords *src )
1344 {
1345     if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1346     dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1347     return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1348 }
1349
1350 /***********************************************************************
1351  *           xrenderdrv_SetDeviceClipping
1352  */
1353 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1354 {
1355     struct xrender_physdev *physdev = get_xrender_dev( dev );
1356
1357     physdev->region = rgn;
1358     physdev->update_clip = TRUE;
1359
1360     dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1361     dev->funcs->pSetDeviceClipping( dev, rgn );
1362 }
1363
1364
1365 /************************************************************************
1366  *   UploadGlyph
1367  *
1368  * Helper to ExtTextOut.  Must be called inside xrender_cs
1369  */
1370 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1371 {
1372     unsigned int buflen;
1373     char *buf;
1374     Glyph gid;
1375     GLYPHMETRICS gm;
1376     XGlyphInfo gi;
1377     gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1378     gsCacheEntryFormat *formatEntry;
1379     UINT ggo_format = GGO_GLYPH_INDEX;
1380     enum wxr_format wxr_format;
1381     static const char zero[4];
1382     static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1383
1384     switch(format) {
1385     case AA_Grey:
1386         ggo_format |= WINE_GGO_GRAY16_BITMAP;
1387         break;
1388     case AA_RGB:
1389         ggo_format |= WINE_GGO_HRGB_BITMAP;
1390         break;
1391     case AA_BGR:
1392         ggo_format |= WINE_GGO_HBGR_BITMAP;
1393         break;
1394     case AA_VRGB:
1395         ggo_format |= WINE_GGO_VRGB_BITMAP;
1396         break;
1397     case AA_VBGR:
1398         ggo_format |= WINE_GGO_VBGR_BITMAP;
1399         break;
1400
1401     default:
1402         ERR("aa = %d - not implemented\n", format);
1403     case AA_None:
1404         ggo_format |= GGO_BITMAP;
1405         break;
1406     }
1407
1408     buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1409     if(buflen == GDI_ERROR) {
1410         if(format != AA_None) {
1411             format = AA_None;
1412             entry->aa_default = AA_None;
1413             ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1414             buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1415         }
1416         if(buflen == GDI_ERROR) {
1417             WARN("GetGlyphOutlineW failed using default glyph\n");
1418             buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1419             if(buflen == GDI_ERROR) {
1420                 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1421                 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1422                 if(buflen == GDI_ERROR) {
1423                     ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1424                     return;
1425                 }
1426             }
1427         }
1428         TRACE("Turning off antialiasing for this monochrome font\n");
1429     }
1430
1431     /* If there is nothing for the current type, we create the entry. */
1432     if( !entry->format[format] ) {
1433         entry->format[format] = HeapAlloc(GetProcessHeap(),
1434                                           HEAP_ZERO_MEMORY,
1435                                           sizeof(gsCacheEntryFormat));
1436     }
1437     formatEntry = entry->format[format];
1438
1439     if(formatEntry->nrealized <= glyph) {
1440         formatEntry->nrealized = (glyph / 128 + 1) * 128;
1441
1442         if (formatEntry->realized)
1443             formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1444                                       HEAP_ZERO_MEMORY,
1445                                       formatEntry->realized,
1446                                       formatEntry->nrealized * sizeof(BOOL));
1447         else
1448             formatEntry->realized = HeapAlloc(GetProcessHeap(),
1449                                       HEAP_ZERO_MEMORY,
1450                                       formatEntry->nrealized * sizeof(BOOL));
1451
1452         if (formatEntry->gis)
1453             formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1454                                    HEAP_ZERO_MEMORY,
1455                                    formatEntry->gis,
1456                                    formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1457         else
1458             formatEntry->gis = HeapAlloc(GetProcessHeap(),
1459                                    HEAP_ZERO_MEMORY,
1460                                    formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1461     }
1462
1463
1464     if(formatEntry->glyphset == 0) {
1465         switch(format) {
1466             case AA_Grey:
1467                 wxr_format = WXR_FORMAT_GRAY;
1468                 break;
1469
1470             case AA_RGB:
1471             case AA_BGR:
1472             case AA_VRGB:
1473             case AA_VBGR:
1474                 wxr_format = WXR_FORMAT_A8R8G8B8;
1475                 break;
1476
1477             default:
1478                 ERR("aa = %d - not implemented\n", format);
1479             case AA_None:
1480                 wxr_format = WXR_FORMAT_MONO;
1481                 break;
1482         }
1483
1484         wine_tsx11_lock();
1485         formatEntry->font_format = pict_formats[wxr_format];
1486         formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1487         wine_tsx11_unlock();
1488     }
1489
1490
1491     buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1492     GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1493     formatEntry->realized[glyph] = TRUE;
1494
1495     TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1496           buflen,
1497           gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1498           gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1499
1500     gi.width = gm.gmBlackBoxX;
1501     gi.height = gm.gmBlackBoxY;
1502     gi.x = -gm.gmptGlyphOrigin.x;
1503     gi.y = gm.gmptGlyphOrigin.y;
1504     gi.xOff = gm.gmCellIncX;
1505     gi.yOff = gm.gmCellIncY;
1506
1507     if(TRACE_ON(xrender)) {
1508         int pitch, i, j;
1509         char output[300];
1510         unsigned char *line;
1511
1512         if(format == AA_None) {
1513             pitch = ((gi.width + 31) / 32) * 4;
1514             for(i = 0; i < gi.height; i++) {
1515                 line = (unsigned char*) buf + i * pitch;
1516                 output[0] = '\0';
1517                 for(j = 0; j < pitch * 8; j++) {
1518                     strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1519                 }
1520                 TRACE("%s\n", output);
1521             }
1522         } else {
1523             static const char blks[] = " .:;!o*#";
1524             char str[2];
1525
1526             str[1] = '\0';
1527             pitch = ((gi.width + 3) / 4) * 4;
1528             for(i = 0; i < gi.height; i++) {
1529                 line = (unsigned char*) buf + i * pitch;
1530                 output[0] = '\0';
1531                 for(j = 0; j < pitch; j++) {
1532                     str[0] = blks[line[j] >> 5];
1533                     strcat(output, str);
1534                 }
1535                 TRACE("%s\n", output);
1536             }
1537         }
1538     }
1539
1540
1541     if(formatEntry->glyphset) {
1542         if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1543             unsigned char *byte = (unsigned char*) buf, c;
1544             int i = buflen;
1545
1546             while(i--) {
1547                 c = *byte;
1548
1549                 /* magic to flip bit order */
1550                 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1551                 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1552                 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1553
1554                 *byte++ = c;
1555             }
1556         }
1557         else if ( format != AA_Grey &&
1558                   ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1559         {
1560             unsigned int i, *data = (unsigned int *)buf;
1561             for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1562         }
1563         gid = glyph;
1564
1565         /*
1566           XRenderCompositeText seems to ignore 0x0 glyphs when
1567           AA_None, which means we lose the advance width of glyphs
1568           like the space.  We'll pretend that such glyphs are 1x1
1569           bitmaps.
1570         */
1571
1572         if(buflen == 0)
1573             gi.width = gi.height = 1;
1574
1575         wine_tsx11_lock();
1576         pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1577                           buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1578         wine_tsx11_unlock();
1579         HeapFree(GetProcessHeap(), 0, buf);
1580     }
1581
1582     formatEntry->gis[glyph] = gi;
1583 }
1584
1585 /*************************************************************
1586  *                 get_tile_pict
1587  *
1588  * Returns an appropriate Picture for tiling the text colour.
1589  * Call and use result within the xrender_cs
1590  */
1591 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1592 {
1593     static struct
1594     {
1595         Pixmap xpm;
1596         Picture pict;
1597         XRenderColor current_color;
1598     } tiles[WXR_NB_FORMATS], *tile;
1599
1600     tile = &tiles[wxr_format];
1601
1602     if(!tile->xpm)
1603     {
1604         XRenderPictureAttributes pa;
1605         XRenderPictFormat *pict_format = pict_formats[wxr_format];
1606
1607         wine_tsx11_lock();
1608         tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1609
1610         pa.repeat = RepeatNormal;
1611         tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1612         wine_tsx11_unlock();
1613
1614         /* init current_color to something different from text_pixel */
1615         tile->current_color = *color;
1616         tile->current_color.red ^= 0xffff;
1617
1618         if (wxr_format == WXR_FORMAT_MONO)
1619         {
1620             /* for a 1bpp bitmap we always need a 1 in the tile */
1621             XRenderColor col;
1622             col.red = col.green = col.blue = 0;
1623             col.alpha = 0xffff;
1624             wine_tsx11_lock();
1625             pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1626             wine_tsx11_unlock();
1627         }
1628     }
1629
1630     if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1631     {
1632         wine_tsx11_lock();
1633         pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1634         wine_tsx11_unlock();
1635         tile->current_color = *color;
1636     }
1637     return tile->pict;
1638 }
1639
1640 /*************************************************************
1641  *                 get_mask_pict
1642  *
1643  * Returns an appropriate Picture for masking with the specified alpha.
1644  * Call and use result within the xrender_cs
1645  */
1646 static Picture get_mask_pict( int alpha )
1647 {
1648     static Pixmap pixmap;
1649     static Picture pict;
1650     static int current_alpha;
1651
1652     if (alpha == 0xffff) return 0;  /* don't need a mask for alpha==1.0 */
1653
1654     if (!pixmap)
1655     {
1656         XRenderPictureAttributes pa;
1657
1658         wine_tsx11_lock();
1659         pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1660         pa.repeat = RepeatNormal;
1661         pict = pXRenderCreatePicture( gdi_display, pixmap,
1662                                       pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1663         wine_tsx11_unlock();
1664         current_alpha = -1;
1665     }
1666
1667     if (alpha != current_alpha)
1668     {
1669         XRenderColor col;
1670         col.red = col.green = col.blue = 0;
1671         col.alpha = current_alpha = alpha;
1672         wine_tsx11_lock();
1673         pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1674         wine_tsx11_unlock();
1675     }
1676     return pict;
1677 }
1678
1679 /***********************************************************************
1680  *           xrenderdrv_ExtTextOut
1681  */
1682 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1683                                    const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1684 {
1685     struct xrender_physdev *physdev = get_xrender_dev( dev );
1686     gsCacheEntry *entry;
1687     gsCacheEntryFormat *formatEntry;
1688     AA_Type aa_type = AA_None;
1689     unsigned int idx;
1690     Picture pict, tile_pict = 0;
1691     XGlyphElt16 *elts;
1692     POINT offset, desired, current;
1693     int render_op = PictOpOver;
1694     XRenderColor col;
1695
1696     if (!physdev->x11dev->has_gdi_font)
1697     {
1698         dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1699         return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1700     }
1701
1702     get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1703     pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1704
1705     if(flags & ETO_OPAQUE)
1706     {
1707         XRenderColor bg;
1708
1709         if (physdev->format == WXR_FORMAT_MONO)
1710             /* use the inverse of the text color */
1711             bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1712         else
1713             get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1714
1715         wine_tsx11_lock();
1716         set_xrender_transformation( pict, 1, 1, 0, 0 );
1717         pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1718                                physdev->x11dev->dc_rect.left + lprect->left,
1719                                physdev->x11dev->dc_rect.top + lprect->top,
1720                                lprect->right - lprect->left,
1721                                lprect->bottom - lprect->top );
1722         wine_tsx11_unlock();
1723     }
1724
1725     if(count == 0) return TRUE;
1726
1727     EnterCriticalSection(&xrender_cs);
1728
1729     entry = glyphsetCache + physdev->cache_index;
1730     aa_type = entry->aa_default;
1731     formatEntry = entry->format[aa_type];
1732
1733     for(idx = 0; idx < count; idx++) {
1734         if( !formatEntry ) {
1735             UploadGlyph(physdev, wstr[idx], aa_type);
1736             /* re-evaluate antialias since aa_default may have changed */
1737             aa_type = entry->aa_default;
1738             formatEntry = entry->format[aa_type];
1739         } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1740             UploadGlyph(physdev, wstr[idx], aa_type);
1741         }
1742     }
1743     if (!formatEntry)
1744     {
1745         WARN("could not upload requested glyphs\n");
1746         LeaveCriticalSection(&xrender_cs);
1747         return FALSE;
1748     }
1749
1750     TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1751           physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1752
1753     elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1754
1755     /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1756        So we pass zeros to the function and move to our starting position using the first
1757        element of the elts array. */
1758
1759     desired.x = physdev->x11dev->dc_rect.left + x;
1760     desired.y = physdev->x11dev->dc_rect.top + y;
1761     offset.x = offset.y = 0;
1762     current.x = current.y = 0;
1763
1764     tile_pict = get_tile_pict(physdev->format, &col);
1765
1766     /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1767      */
1768     if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1769         render_op = PictOpOutReverse; /* This gives us 'black' text */
1770
1771     for(idx = 0; idx < count; idx++)
1772     {
1773         elts[idx].glyphset = formatEntry->glyphset;
1774         elts[idx].chars = wstr + idx;
1775         elts[idx].nchars = 1;
1776         elts[idx].xOff = desired.x - current.x;
1777         elts[idx].yOff = desired.y - current.y;
1778
1779         current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1780         current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1781
1782         if(!lpDx)
1783         {
1784             desired.x += formatEntry->gis[wstr[idx]].xOff;
1785             desired.y += formatEntry->gis[wstr[idx]].yOff;
1786         }
1787         else
1788         {
1789             if(flags & ETO_PDY)
1790             {
1791                 offset.x += lpDx[idx * 2];
1792                 offset.y += lpDx[idx * 2 + 1];
1793             }
1794             else
1795                 offset.x += lpDx[idx];
1796             desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1797             desired.y = physdev->x11dev->dc_rect.top  + y + offset.y;
1798         }
1799     }
1800
1801     wine_tsx11_lock();
1802     /* Make sure we don't have any transforms set from a previous call */
1803     set_xrender_transformation(pict, 1, 1, 0, 0);
1804     pXRenderCompositeText16(gdi_display, render_op,
1805                             tile_pict,
1806                             pict,
1807                             formatEntry->font_format,
1808                             0, 0, 0, 0, elts, count);
1809     wine_tsx11_unlock();
1810     HeapFree(GetProcessHeap(), 0, elts);
1811
1812     LeaveCriticalSection(&xrender_cs);
1813     return TRUE;
1814 }
1815
1816 /* multiply the alpha channel of a picture */
1817 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1818                             int x, int y, int width, int height )
1819 {
1820     XRenderPictureAttributes pa;
1821     Pixmap src_pixmap, mask_pixmap;
1822     Picture src_pict, mask_pict;
1823     XRenderColor color;
1824
1825     wine_tsx11_lock();
1826     src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1827     mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1828     pa.repeat = RepeatNormal;
1829     src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1830     pa.component_alpha = True;
1831     mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1832     color.red = color.green = color.blue = color.alpha = 0xffff;
1833     pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1834     color.alpha = alpha;
1835     pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1836     pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1837                        0, 0, 0, 0, x, y, width, height );
1838     pXRenderFreePicture( gdi_display, src_pict );
1839     pXRenderFreePicture( gdi_display, mask_pict );
1840     XFreePixmap( gdi_display, src_pixmap );
1841     XFreePixmap( gdi_display, mask_pixmap );
1842     wine_tsx11_unlock();
1843 }
1844
1845 /* Helper function for (stretched) blitting using xrender */
1846 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1847                           int x_src, int y_src, int x_dst, int y_dst,
1848                           double xscale, double yscale, int width, int height )
1849 {
1850     int x_offset, y_offset;
1851
1852     /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1853      * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1854      * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1855     wine_tsx11_lock();
1856     if(xscale != 1.0 || yscale != 1.0)
1857     {
1858         /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1859          * in the wrong quadrant of the x-y plane.
1860          */
1861         x_offset = (xscale < 0) ? -width : 0;
1862         y_offset = (yscale < 0) ? -height : 0;
1863         set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1864     }
1865     else
1866     {
1867         x_offset = x_src;
1868         y_offset = y_src;
1869         set_xrender_transformation(src_pict, 1, 1, 0, 0);
1870     }
1871     pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1872                        x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
1873     wine_tsx11_unlock();
1874 }
1875
1876 /* Helper function for (stretched) mono->color blitting using xrender */
1877 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1878                                enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1879                                int x_src, int y_src, int x_dst, int y_dst,
1880                                double xscale, double yscale, int width, int height )
1881 {
1882     Picture tile_pict;
1883     int x_offset, y_offset;
1884     XRenderColor color;
1885
1886     /* When doing a mono->color blit, the source data is used as mask, and the source picture
1887      * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1888      * the tile data.
1889      */
1890     EnterCriticalSection( &xrender_cs );
1891     color = *bg;
1892     color.alpha = 0xffff;  /* tile pict needs 100% alpha */
1893     tile_pict = get_tile_pict( dst_format, &color );
1894
1895     wine_tsx11_lock();
1896     pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
1897
1898     if (xscale != 1.0 || yscale != 1.0)
1899     {
1900         /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1901          * in the wrong quadrant of the x-y plane.
1902          */
1903         x_offset = (xscale < 0) ? -width : 0;
1904         y_offset = (yscale < 0) ? -height : 0;
1905         set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1906     }
1907     else
1908     {
1909         x_offset = x_src;
1910         y_offset = y_src;
1911         set_xrender_transformation(src_pict, 1, 1, 0, 0);
1912     }
1913     pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1914                       0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
1915     wine_tsx11_unlock();
1916     LeaveCriticalSection( &xrender_cs );
1917
1918     /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1919     if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1920         multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
1921 }
1922
1923 /* create a pixmap and render picture for an image */
1924 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1925                                   struct bitblt_coords *src, enum wxr_format format,
1926                                   Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1927 {
1928     DWORD ret;
1929     int width = src->visrect.right - src->visrect.left;
1930     int height = src->visrect.bottom - src->visrect.top;
1931     int depth = pict_formats[format]->depth;
1932     struct gdi_image_bits dst_bits;
1933     XRenderPictureAttributes pa;
1934     XImage *image;
1935
1936     wine_tsx11_lock();
1937     image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1938                           info->bmiHeader.biWidth, height, 32, 0 );
1939     wine_tsx11_unlock();
1940     if (!image) return ERROR_OUTOFMEMORY;
1941
1942     ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1943     if (ret) return ret;
1944
1945     image->data = dst_bits.ptr;
1946
1947     *use_repeat = (width == 1 && height == 1);
1948     pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1949
1950     wine_tsx11_lock();
1951     *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1952     XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
1953                src->visrect.left, 0, 0, 0, width, height );
1954     *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1955     wine_tsx11_unlock();
1956
1957     /* make coordinates relative to the pixmap */
1958     src->x -= src->visrect.left;
1959     src->y -= src->visrect.top;
1960     OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1961
1962     image->data = NULL;
1963     wine_tsx11_lock();
1964     XDestroyImage( image );
1965     wine_tsx11_unlock();
1966     if (dst_bits.free) dst_bits.free( &dst_bits );
1967     return ret;
1968 }
1969
1970 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1971                                   Drawable drawable, const struct bitblt_coords *src,
1972                                   const struct bitblt_coords *dst )
1973 {
1974     int width = abs( dst->width );
1975     int height = abs( dst->height );
1976     int x_src = physdev_src->x11dev->dc_rect.left + src->x;
1977     int y_src = physdev_src->x11dev->dc_rect.top + src->y;
1978     int x_dst, y_dst;
1979     Picture src_pict = 0, dst_pict, mask_pict = 0;
1980     BOOL use_repeat;
1981     double xscale, yscale;
1982
1983     use_repeat = use_source_repeat( physdev_src );
1984     if (!use_repeat)
1985     {
1986         xscale = src->width / (double)dst->width;
1987         yscale = src->height / (double)dst->height;
1988     }
1989     else xscale = yscale = 1;  /* no scaling needed with a repeating source */
1990
1991     if (drawable)  /* using an intermediate pixmap */
1992     {
1993         XRenderPictureAttributes pa;
1994
1995         x_dst = dst->x;
1996         y_dst = dst->y;
1997         pa.repeat = RepeatNone;
1998         wine_tsx11_lock();
1999         dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2000         wine_tsx11_unlock();
2001     }
2002     else
2003     {
2004         x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2005         y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2006         dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2007     }
2008
2009     if (src->width < 0) x_src += src->width + 1;
2010     if (src->height < 0) y_src += src->height + 1;
2011     if (dst->width < 0) x_dst += dst->width + 1;
2012     if (dst->height < 0) y_dst += dst->height + 1;
2013
2014     src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2015
2016     /* mono -> color */
2017     if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2018     {
2019         XRenderColor fg, bg;
2020
2021         get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
2022         get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
2023         fg.alpha = bg.alpha = 0;
2024
2025         xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2026                            x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2027     }
2028     else /* color -> color (can be at different depths) or mono -> mono */
2029     {
2030         if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
2031             mask_pict = get_no_alpha_mask();
2032
2033         xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2034                       x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2035     }
2036
2037     if (drawable)
2038     {
2039         wine_tsx11_lock();
2040         pXRenderFreePicture( gdi_display, dst_pict );
2041         wine_tsx11_unlock();
2042     }
2043 }
2044
2045
2046 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2047                                XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2048                                Drawable drawable, struct bitblt_coords *src,
2049                                struct bitblt_coords *dst, BOOL use_repeat )
2050 {
2051     int x_src, y_src, x_dst, y_dst;
2052     Picture dst_pict;
2053     XRenderPictureAttributes pa;
2054     double xscale, yscale;
2055
2056     if (drawable)  /* using an intermediate pixmap */
2057     {
2058         RGNDATA *clip_data = NULL;
2059
2060         if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2061         x_dst = dst->x;
2062         y_dst = dst->y;
2063         pa.repeat = RepeatNone;
2064         wine_tsx11_lock();
2065         dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2066         if (clip_data)
2067             pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2068                                               (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2069         wine_tsx11_unlock();
2070         HeapFree( GetProcessHeap(), 0, clip_data );
2071     }
2072     else
2073     {
2074         x_dst = physdev->x11dev->dc_rect.left + dst->x;
2075         y_dst = physdev->x11dev->dc_rect.top + dst->y;
2076         dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2077     }
2078
2079     if (!use_repeat)
2080     {
2081         xscale = src->width / (double)dst->width;
2082         yscale = src->height / (double)dst->height;
2083     }
2084     else xscale = yscale = 1;  /* no scaling needed with a repeating source */
2085
2086     x_src = src->x;
2087     y_src = src->y;
2088     if (src->width < 0) x_src += src->width + 1;
2089     if (src->height < 0) y_src += src->height + 1;
2090     if (dst->width < 0) x_dst += dst->width + 1;
2091     if (dst->height < 0) y_dst += dst->height + 1;
2092
2093     xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2094                   xscale, yscale, abs( dst->width ), abs( dst->height ));
2095
2096     if (drawable)
2097     {
2098         wine_tsx11_lock();
2099         pXRenderFreePicture( gdi_display, dst_pict );
2100         wine_tsx11_unlock();
2101     }
2102 }
2103
2104
2105 /***********************************************************************
2106  *           xrenderdrv_StretchBlt
2107  */
2108 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2109                                    PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2110 {
2111     struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2112     struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2113     BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2114
2115     if (src_dev->funcs != dst_dev->funcs)
2116     {
2117         dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2118         return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2119     }
2120
2121     /* XRender is of no use for color -> mono */
2122     if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2123         goto x11drv_fallback;
2124
2125     /* if not stretching, we only need to handle format conversion */
2126     if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2127
2128     if (rop != SRCCOPY)
2129     {
2130         GC tmpGC;
2131         Pixmap tmp_pixmap;
2132         struct bitblt_coords tmp;
2133
2134         /* make coordinates relative to tmp pixmap */
2135         tmp = *dst;
2136         tmp.x -= tmp.visrect.left;
2137         tmp.y -= tmp.visrect.top;
2138         OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2139
2140         wine_tsx11_lock();
2141         tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2142         XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2143         XSetGraphicsExposures( gdi_display, tmpGC, False );
2144         tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2145                                     tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
2146         wine_tsx11_unlock();
2147
2148         xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2149         execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2150
2151         wine_tsx11_lock();
2152         XFreePixmap( gdi_display, tmp_pixmap );
2153         XFreeGC( gdi_display, tmpGC );
2154         wine_tsx11_unlock();
2155     }
2156     else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2157
2158     return TRUE;
2159
2160 x11drv_fallback:
2161     return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2162 }
2163
2164
2165 /***********************************************************************
2166  *           xrenderdrv_PutImage
2167  */
2168 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2169                                   const struct gdi_image_bits *bits, struct bitblt_coords *src,
2170                                   struct bitblt_coords *dst, DWORD rop )
2171 {
2172     struct xrender_physdev *physdev;
2173     X_PHYSBITMAP *bitmap;
2174     DWORD ret;
2175     Pixmap tmp_pixmap;
2176     GC gc;
2177     enum wxr_format src_format, dst_format;
2178     XRenderPictFormat *pict_format;
2179     Pixmap src_pixmap;
2180     Picture src_pict, mask_pict = 0;
2181     BOOL use_repeat;
2182
2183     if (hbitmap)
2184     {
2185         if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2186         physdev = NULL;
2187         dst_format = bitmap->format;
2188     }
2189     else
2190     {
2191         physdev = get_xrender_dev( dev );
2192         bitmap = NULL;
2193         dst_format = physdev->format;
2194     }
2195
2196     src_format = get_xrender_format_from_bitmapinfo( info );
2197     if (!(pict_format = pict_formats[src_format])) goto update_format;
2198
2199     /* make sure we can create an image with the same bpp */
2200     if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2201         goto update_format;
2202
2203     /* mono <-> color conversions not supported */
2204     if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2205         goto x11drv_fallback;
2206
2207     if (!bits) return ERROR_SUCCESS;  /* just querying the format */
2208
2209     if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2210
2211     ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2212     if (!ret)
2213     {
2214         struct bitblt_coords tmp;
2215
2216         if (bitmap)
2217         {
2218             HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2219             if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2220
2221             xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2222                                pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2223             DeleteObject( rgn );
2224         }
2225         else
2226         {
2227             if (rop != SRCCOPY)
2228             {
2229                 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2230
2231                 /* make coordinates relative to tmp pixmap */
2232                 tmp = *dst;
2233                 tmp.x -= tmp.visrect.left;
2234                 tmp.y -= tmp.visrect.top;
2235                 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2236
2237                 wine_tsx11_lock();
2238                 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2239                 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2240                 XSetGraphicsExposures( gdi_display, gc, False );
2241                 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2242                                             tmp.visrect.right - tmp.visrect.left,
2243                                             tmp.visrect.bottom - tmp.visrect.top,
2244                                             physdev->pict_format->depth );
2245                 wine_tsx11_unlock();
2246
2247                 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2248                                    NULL, tmp_pixmap, src, &tmp, use_repeat );
2249                 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2250
2251                 wine_tsx11_lock();
2252                 XFreePixmap( gdi_display, tmp_pixmap );
2253                 XFreeGC( gdi_display, gc );
2254                 wine_tsx11_unlock();
2255
2256                 if (restore_region) restore_clipping_region( physdev->x11dev );
2257             }
2258             else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2259                                     physdev->pict_format, physdev, 0, src, dst, use_repeat );
2260         }
2261
2262         wine_tsx11_lock();
2263         pXRenderFreePicture( gdi_display, src_pict );
2264         XFreePixmap( gdi_display, src_pixmap );
2265         wine_tsx11_unlock();
2266     }
2267     return ret;
2268
2269 update_format:
2270     if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2271     set_color_info( pict_formats[dst_format], info );
2272     return ERROR_BAD_FORMAT;
2273
2274 x11drv_fallback:
2275     if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2276     dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2277     return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2278 }
2279
2280
2281 /***********************************************************************
2282  *           xrenderdrv_BlendImage
2283  */
2284 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2285                                     struct bitblt_coords *src, struct bitblt_coords *dst,
2286                                     BLENDFUNCTION func )
2287 {
2288     struct xrender_physdev *physdev = get_xrender_dev( dev );
2289     DWORD ret;
2290     enum wxr_format format;
2291     XRenderPictFormat *pict_format;
2292     Picture dst_pict, src_pict, mask_pict;
2293     Pixmap src_pixmap;
2294     BOOL use_repeat;
2295
2296     format = get_xrender_format_from_bitmapinfo( info );
2297     if (!(func.AlphaFormat & AC_SRC_ALPHA))
2298         format = get_format_without_alpha( format );
2299     else if (format != WXR_FORMAT_A8R8G8B8)
2300         return ERROR_INVALID_PARAMETER;
2301
2302     if (!(pict_format = pict_formats[format])) goto update_format;
2303
2304     /* make sure we can create an image with the same bpp */
2305     if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2306         goto update_format;
2307
2308     if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2309         goto update_format;
2310
2311     if (!bits) return ERROR_SUCCESS;  /* just querying the format */
2312
2313     ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2314     if (!ret)
2315     {
2316         double xscale, yscale;
2317
2318         if (!use_repeat)
2319         {
2320             xscale = src->width / (double)dst->width;
2321             yscale = src->height / (double)dst->height;
2322         }
2323         else xscale = yscale = 1;  /* no scaling needed with a repeating source */
2324
2325         dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2326
2327         EnterCriticalSection( &xrender_cs );
2328         mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2329
2330         xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2331                       physdev->x11dev->dc_rect.left + dst->x,
2332                       physdev->x11dev->dc_rect.top + dst->y,
2333                       xscale, yscale, dst->width, dst->height );
2334
2335         wine_tsx11_lock();
2336         pXRenderFreePicture( gdi_display, src_pict );
2337         XFreePixmap( gdi_display, src_pixmap );
2338         wine_tsx11_unlock();
2339
2340         LeaveCriticalSection( &xrender_cs );
2341     }
2342     return ret;
2343
2344 update_format:
2345     if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2346     set_color_info( physdev->pict_format, info );
2347     return ERROR_BAD_FORMAT;
2348 }
2349
2350
2351 /***********************************************************************
2352  *           xrenderdrv_AlphaBlend
2353  */
2354 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2355                                    PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2356 {
2357     struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2358     struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2359     Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2360     XRenderPictureAttributes pa;
2361     Pixmap tmp_pixmap = 0;
2362     double xscale, yscale;
2363     BOOL use_repeat;
2364
2365     if (src_dev->funcs != dst_dev->funcs)
2366     {
2367         dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2368         return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2369     }
2370
2371     if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2372     {
2373         SetLastError( ERROR_INVALID_PARAMETER );
2374         return FALSE;
2375     }
2376
2377     dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2378
2379     use_repeat = use_source_repeat( physdev_src );
2380     if (!use_repeat)
2381     {
2382         xscale = src->width / (double)dst->width;
2383         yscale = src->height / (double)dst->height;
2384     }
2385     else xscale = yscale = 1;  /* no scaling needed with a repeating source */
2386
2387     src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2388
2389     if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2390     {
2391         /* mono -> color blending needs an intermediate color pixmap */
2392         XRenderColor fg, bg;
2393         int width = src->visrect.right - src->visrect.left;
2394         int height = src->visrect.bottom - src->visrect.top;
2395
2396         /* blending doesn't use the destination DC colors */
2397         fg.red = fg.green = fg.blue = 0;
2398         bg.red = bg.green = bg.blue = 0xffff;
2399         fg.alpha = bg.alpha = 0xffff;
2400
2401         wine_tsx11_lock();
2402         tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2403                                     physdev_dst->pict_format->depth );
2404         pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2405         tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2406                                           CPRepeat, &pa );
2407         wine_tsx11_unlock();
2408
2409         xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2410                            src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2411     }
2412     else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2413     {
2414         /* we need a source picture with no alpha */
2415         enum wxr_format format = get_format_without_alpha( physdev_src->format );
2416         if (format != physdev_src->format)
2417         {
2418             wine_tsx11_lock();
2419             pa.subwindow_mode = IncludeInferiors;
2420             pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2421             tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2422                                               pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2423             wine_tsx11_unlock();
2424         }
2425     }
2426
2427     if (tmp_pict) src_pict = tmp_pict;
2428
2429     EnterCriticalSection( &xrender_cs );
2430     mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2431
2432     xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2433                   physdev_src->x11dev->dc_rect.left + src->x,
2434                   physdev_src->x11dev->dc_rect.top + src->y,
2435                   physdev_dst->x11dev->dc_rect.left + dst->x,
2436                   physdev_dst->x11dev->dc_rect.top + dst->y,
2437                   xscale, yscale, dst->width, dst->height );
2438
2439     wine_tsx11_lock();
2440     if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2441     if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2442     wine_tsx11_unlock();
2443
2444     LeaveCriticalSection( &xrender_cs );
2445     return TRUE;
2446 }
2447
2448 /***********************************************************************
2449  *           xrenderdrv_GradientFill
2450  */
2451 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2452                                      void * grad_array, ULONG ngrad, ULONG mode )
2453 {
2454 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2455     static const XFixed stops[2] = { 0, 1 << 16 };
2456     struct xrender_physdev *physdev = get_xrender_dev( dev );
2457     XLinearGradient gradient;
2458     XRenderColor colors[2];
2459     Picture src_pict, dst_pict;
2460     unsigned int i;
2461     const GRADIENT_RECT *rect = grad_array;
2462     POINT pt[2];
2463
2464     if (!pXRenderCreateLinearGradient) goto fallback;
2465
2466     /* <= 16-bpp uses dithering */
2467     if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2468
2469     switch (mode)
2470     {
2471     case GRADIENT_FILL_RECT_H:
2472     case GRADIENT_FILL_RECT_V:
2473         for (i = 0; i < ngrad; i++, rect++)
2474         {
2475             const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2476             const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2477
2478             colors[0].red   = v1->Red * 257 / 256;
2479             colors[0].green = v1->Green * 257 / 256;
2480             colors[0].blue  = v1->Blue * 257 / 256;
2481             colors[1].red   = v2->Red * 257 / 256;
2482             colors[1].green = v2->Green * 257 / 256;
2483             colors[1].blue  = v2->Blue * 257 / 256;
2484             /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2485             colors[0].alpha = colors[1].alpha = 65535;
2486
2487             pt[0].x = v1->x;
2488             pt[0].y = v1->y;
2489             pt[1].x = v2->x;
2490             pt[1].y = v2->y;
2491             LPtoDP( dev->hdc, pt, 2 );
2492             if (mode == GRADIENT_FILL_RECT_H)
2493             {
2494                 gradient.p1.y = gradient.p2.y = 0;
2495                 if (pt[1].x > pt[0].x)
2496                 {
2497                     gradient.p1.x = 0;
2498                     gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2499                 }
2500                 else
2501                 {
2502                     gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2503                     gradient.p2.x = 0;
2504                 }
2505             }
2506             else
2507             {
2508                 gradient.p1.x = gradient.p2.x = 0;
2509                 if (pt[1].y > pt[0].y)
2510                 {
2511                     gradient.p1.y = 0;
2512                     gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2513                 }
2514                 else
2515                 {
2516                     gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2517                     gradient.p2.y = 0;
2518                 }
2519             }
2520
2521             TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2522                    mode, pt[0].x, pt[0].y, pt[1].x, pt[1].y,
2523                    colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2524                    colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2525
2526             dst_pict = get_xrender_picture( physdev, 0, NULL );
2527
2528             wine_tsx11_lock();
2529             src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2530             xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0,
2531                           physdev->x11dev->dc_rect.left + min( pt[0].x, pt[1].x ),
2532                           physdev->x11dev->dc_rect.top + min( pt[0].y, pt[1].y ),
2533                           1, 1, abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y) );
2534             pXRenderFreePicture( gdi_display, src_pict );
2535             wine_tsx11_unlock();
2536         }
2537         return TRUE;
2538     }
2539
2540 fallback:
2541 #endif
2542     dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2543     return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2544 }
2545
2546 /***********************************************************************
2547  *           xrenderdrv_SelectBrush
2548  */
2549 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2550 {
2551     struct xrender_physdev *physdev = get_xrender_dev( dev );
2552     X_PHYSBITMAP *physbitmap;
2553     BOOL delete_bitmap = FALSE;
2554     BITMAP bm;
2555     HBITMAP bitmap;
2556     Pixmap pixmap;
2557     XRenderPictFormat *pict_format;
2558     Picture src_pict, dst_pict;
2559     XRenderPictureAttributes pa;
2560
2561     if (!pattern) goto x11drv_fallback;
2562     if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2563
2564     bitmap = pattern->bitmap;
2565     if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2566     {
2567         if (!(bitmap = create_brush_bitmap( physdev->x11dev, pattern ))) return 0;
2568         physbitmap = X11DRV_get_phys_bitmap( bitmap );
2569         delete_bitmap = TRUE;
2570     }
2571
2572     if (physbitmap->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2573     if (!(pict_format = pict_formats[physbitmap->format])) goto x11drv_fallback;
2574
2575     GetObjectW( bitmap, sizeof(bm), &bm );
2576
2577     wine_tsx11_lock();
2578     pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2579                             physdev->pict_format->depth );
2580
2581     pa.repeat = RepeatNone;
2582     src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_format, CPRepeat, &pa);
2583     dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2584
2585     xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, bm.bmWidth, bm.bmHeight );
2586     pXRenderFreePicture( gdi_display, src_pict );
2587     pXRenderFreePicture( gdi_display, dst_pict );
2588
2589     if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2590     physdev->x11dev->brush.pixmap = pixmap;
2591     physdev->x11dev->brush.fillStyle = FillTiled;
2592     physdev->x11dev->brush.pixel = 0;  /* ignored */
2593     physdev->x11dev->brush.style = BS_PATTERN;
2594     wine_tsx11_unlock();
2595
2596     if (delete_bitmap) DeleteObject( bitmap );
2597     return hbrush;
2598
2599 x11drv_fallback:
2600     if (delete_bitmap) DeleteObject( bitmap );
2601     dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2602     return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2603 }
2604
2605
2606 static const struct gdi_dc_funcs xrender_funcs =
2607 {
2608     NULL,                               /* pAbortDoc */
2609     NULL,                               /* pAbortPath */
2610     xrenderdrv_AlphaBlend,              /* pAlphaBlend */
2611     NULL,                               /* pAngleArc */
2612     NULL,                               /* pArc */
2613     NULL,                               /* pArcTo */
2614     NULL,                               /* pBeginPath */
2615     xrenderdrv_BlendImage,              /* pBlendImage */
2616     NULL,                               /* pChoosePixelFormat */
2617     NULL,                               /* pChord */
2618     NULL,                               /* pCloseFigure */
2619     xrenderdrv_CopyBitmap,              /* pCopyBitmap */
2620     xrenderdrv_CreateBitmap,            /* pCreateBitmap */
2621     xrenderdrv_CreateCompatibleDC,      /* pCreateCompatibleDC */
2622     xrenderdrv_CreateDC,                /* pCreateDC */
2623     xrenderdrv_DeleteBitmap,            /* pDeleteBitmap */
2624     xrenderdrv_DeleteDC,                /* pDeleteDC */
2625     NULL,                               /* pDeleteObject */
2626     NULL,                               /* pDescribePixelFormat */
2627     NULL,                               /* pDeviceCapabilities */
2628     NULL,                               /* pEllipse */
2629     NULL,                               /* pEndDoc */
2630     NULL,                               /* pEndPage */
2631     NULL,                               /* pEndPath */
2632     NULL,                               /* pEnumFonts */
2633     NULL,                               /* pEnumICMProfiles */
2634     NULL,                               /* pExcludeClipRect */
2635     NULL,                               /* pExtDeviceMode */
2636     xrenderdrv_ExtEscape,               /* pExtEscape */
2637     NULL,                               /* pExtFloodFill */
2638     NULL,                               /* pExtSelectClipRgn */
2639     xrenderdrv_ExtTextOut,              /* pExtTextOut */
2640     NULL,                               /* pFillPath */
2641     NULL,                               /* pFillRgn */
2642     NULL,                               /* pFlattenPath */
2643     NULL,                               /* pFontIsLinked */
2644     NULL,                               /* pFrameRgn */
2645     NULL,                               /* pGdiComment */
2646     NULL,                               /* pGdiRealizationInfo */
2647     NULL,                               /* pGetCharABCWidths */
2648     NULL,                               /* pGetCharABCWidthsI */
2649     NULL,                               /* pGetCharWidth */
2650     NULL,                               /* pGetDeviceCaps */
2651     NULL,                               /* pGetDeviceGammaRamp */
2652     NULL,                               /* pGetFontData */
2653     NULL,                               /* pGetFontUnicodeRanges */
2654     NULL,                               /* pGetGlyphIndices */
2655     NULL,                               /* pGetGlyphOutline */
2656     NULL,                               /* pGetICMProfile */
2657     xrenderdrv_GetImage,                /* pGetImage */
2658     NULL,                               /* pGetKerningPairs */
2659     NULL,                               /* pGetNearestColor */
2660     NULL,                               /* pGetOutlineTextMetrics */
2661     NULL,                               /* pGetPixel */
2662     NULL,                               /* pGetPixelFormat */
2663     NULL,                               /* pGetSystemPaletteEntries */
2664     NULL,                               /* pGetTextCharsetInfo */
2665     NULL,                               /* pGetTextExtentExPoint */
2666     NULL,                               /* pGetTextExtentExPointI */
2667     NULL,                               /* pGetTextFace */
2668     NULL,                               /* pGetTextMetrics */
2669     xrenderdrv_GradientFill,            /* pGradientFill */
2670     NULL,                               /* pIntersectClipRect */
2671     NULL,                               /* pInvertRgn */
2672     NULL,                               /* pLineTo */
2673     NULL,                               /* pModifyWorldTransform */
2674     NULL,                               /* pMoveTo */
2675     NULL,                               /* pOffsetClipRgn */
2676     NULL,                               /* pOffsetViewportOrg */
2677     NULL,                               /* pOffsetWindowOrg */
2678     NULL,                               /* pPaintRgn */
2679     NULL,                               /* pPatBlt */
2680     NULL,                               /* pPie */
2681     NULL,                               /* pPolyBezier */
2682     NULL,                               /* pPolyBezierTo */
2683     NULL,                               /* pPolyDraw */
2684     NULL,                               /* pPolyPolygon */
2685     NULL,                               /* pPolyPolyline */
2686     NULL,                               /* pPolygon */
2687     NULL,                               /* pPolyline */
2688     NULL,                               /* pPolylineTo */
2689     xrenderdrv_PutImage,                /* pPutImage */
2690     NULL,                               /* pRealizeDefaultPalette */
2691     NULL,                               /* pRealizePalette */
2692     NULL,                               /* pRectangle */
2693     NULL,                               /* pResetDC */
2694     NULL,                               /* pRestoreDC */
2695     NULL,                               /* pRoundRect */
2696     NULL,                               /* pSaveDC */
2697     NULL,                               /* pScaleViewportExt */
2698     NULL,                               /* pScaleWindowExt */
2699     xrenderdrv_SelectBitmap,            /* pSelectBitmap */
2700     xrenderdrv_SelectBrush,             /* pSelectBrush */
2701     NULL,                               /* pSelectClipPath */
2702     xrenderdrv_SelectFont,              /* pSelectFont */
2703     NULL,                               /* pSelectPalette */
2704     NULL,                               /* pSelectPen */
2705     NULL,                               /* pSetArcDirection */
2706     NULL,                               /* pSetBkColor */
2707     NULL,                               /* pSetBkMode */
2708     NULL,                               /* pSetDCBrushColor */
2709     NULL,                               /* pSetDCPenColor */
2710     NULL,                               /* pSetDIBitsToDevice */
2711     xrenderdrv_SetDeviceClipping,       /* pSetDeviceClipping */
2712     NULL,                               /* pSetDeviceGammaRamp */
2713     NULL,                               /* pSetLayout */
2714     NULL,                               /* pSetMapMode */
2715     NULL,                               /* pSetMapperFlags */
2716     NULL,                               /* pSetPixel */
2717     NULL,                               /* pSetPixelFormat */
2718     NULL,                               /* pSetPolyFillMode */
2719     NULL,                               /* pSetROP2 */
2720     NULL,                               /* pSetRelAbs */
2721     NULL,                               /* pSetStretchBltMode */
2722     NULL,                               /* pSetTextAlign */
2723     NULL,                               /* pSetTextCharacterExtra */
2724     NULL,                               /* pSetTextColor */
2725     NULL,                               /* pSetTextJustification */
2726     NULL,                               /* pSetViewportExt */
2727     NULL,                               /* pSetViewportOrg */
2728     NULL,                               /* pSetWindowExt */
2729     NULL,                               /* pSetWindowOrg */
2730     NULL,                               /* pSetWorldTransform */
2731     NULL,                               /* pStartDoc */
2732     NULL,                               /* pStartPage */
2733     xrenderdrv_StretchBlt,              /* pStretchBlt */
2734     NULL,                               /* pStretchDIBits */
2735     NULL,                               /* pStrokeAndFillPath */
2736     NULL,                               /* pStrokePath */
2737     NULL,                               /* pSwapBuffers */
2738     NULL,                               /* pUnrealizePalette */
2739     NULL,                               /* pWidenPath */
2740     /* OpenGL not supported */
2741 };
2742
2743 #else /* SONAME_LIBXRENDER */
2744
2745 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2746 {
2747     TRACE("XRender support not compiled in.\n");
2748     return NULL;
2749 }
2750
2751 void X11DRV_XRender_Finalize(void)
2752 {
2753 }
2754
2755 #endif /* SONAME_LIBXRENDER */