ieframe: Added IProvideClassInfo::GetClassInfo tests.
[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 width_src, int height_src,
1848                           int x_dst, int y_dst, int width_dst, int height_dst,
1849                           double xscale, double yscale )
1850 {
1851     int x_offset, y_offset;
1852
1853     if (width_src < 0)
1854     {
1855         x_src += width_src + 1;
1856         width_src = -width_src;
1857     }
1858     if (height_src < 0)
1859     {
1860         y_src += height_src + 1;
1861         height_src = -height_src;
1862     }
1863     if (width_dst < 0)
1864     {
1865         x_dst += width_dst + 1;
1866         width_dst = -width_dst;
1867     }
1868     if (height_dst < 0)
1869     {
1870         y_dst += height_dst + 1;
1871         height_dst = -height_dst;
1872     }
1873
1874     /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1875      * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1876      * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1877     wine_tsx11_lock();
1878     if(xscale != 1.0 || yscale != 1.0)
1879     {
1880         /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1881          * in the wrong quadrant of the x-y plane.
1882          */
1883         x_offset = (xscale < 0) ? -width_dst : 0;
1884         y_offset = (yscale < 0) ? -height_dst : 0;
1885         set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1886     }
1887     else
1888     {
1889         x_offset = x_src;
1890         y_offset = y_src;
1891         set_xrender_transformation(src_pict, 1, 1, 0, 0);
1892     }
1893     pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1894                        x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1895     wine_tsx11_unlock();
1896 }
1897
1898 /* Helper function for (stretched) mono->color blitting using xrender */
1899 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1900                                enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1901                                int x_src, int y_src, int width_src, int height_src,
1902                                int x_dst, int y_dst, int width_dst, int height_dst,
1903                                double xscale, double yscale )
1904 {
1905     Picture tile_pict;
1906     int x_offset, y_offset;
1907     XRenderColor color;
1908
1909     if (width_src < 0)
1910     {
1911         x_src += width_src + 1;
1912         width_src = -width_src;
1913     }
1914     if (height_src < 0)
1915     {
1916         y_src += height_src + 1;
1917         height_src = -height_src;
1918     }
1919     if (width_dst < 0)
1920     {
1921         x_dst += width_dst + 1;
1922         width_dst = -width_dst;
1923     }
1924     if (height_dst < 0)
1925     {
1926         y_dst += height_dst + 1;
1927         height_dst = -height_dst;
1928     }
1929
1930     /* When doing a mono->color blit, the source data is used as mask, and the source picture
1931      * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1932      * the tile data.
1933      */
1934     EnterCriticalSection( &xrender_cs );
1935     color = *bg;
1936     color.alpha = 0xffff;  /* tile pict needs 100% alpha */
1937     tile_pict = get_tile_pict( dst_format, &color );
1938
1939     wine_tsx11_lock();
1940     pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1941
1942     if (xscale != 1.0 || yscale != 1.0)
1943     {
1944         /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1945          * in the wrong quadrant of the x-y plane.
1946          */
1947         x_offset = (xscale < 0) ? -width_dst : 0;
1948         y_offset = (yscale < 0) ? -height_dst : 0;
1949         set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1950     }
1951     else
1952     {
1953         x_offset = x_src;
1954         y_offset = y_src;
1955         set_xrender_transformation(src_pict, 1, 1, 0, 0);
1956     }
1957     pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1958                       0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1959     wine_tsx11_unlock();
1960     LeaveCriticalSection( &xrender_cs );
1961
1962     /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1963     if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1964         multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1965                         x_dst, y_dst, width_dst, height_dst );
1966 }
1967
1968 /* create a pixmap and render picture for an image */
1969 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1970                                   struct bitblt_coords *src, enum wxr_format format,
1971                                   Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1972 {
1973     DWORD ret;
1974     int width = src->visrect.right - src->visrect.left;
1975     int height = src->visrect.bottom - src->visrect.top;
1976     int depth = pict_formats[format]->depth;
1977     struct gdi_image_bits dst_bits;
1978     XRenderPictureAttributes pa;
1979     XImage *image;
1980
1981     wine_tsx11_lock();
1982     image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1983                           info->bmiHeader.biWidth, height, 32, 0 );
1984     wine_tsx11_unlock();
1985     if (!image) return ERROR_OUTOFMEMORY;
1986
1987     ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1988     if (ret) return ret;
1989
1990     image->data = dst_bits.ptr;
1991
1992     *use_repeat = (width == 1 && height == 1);
1993     pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1994
1995     wine_tsx11_lock();
1996     *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1997     XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
1998                src->visrect.left, 0, 0, 0, width, height );
1999     *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2000     wine_tsx11_unlock();
2001
2002     /* make coordinates relative to the pixmap */
2003     src->x -= src->visrect.left;
2004     src->y -= src->visrect.top;
2005     OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2006
2007     image->data = NULL;
2008     wine_tsx11_lock();
2009     XDestroyImage( image );
2010     wine_tsx11_unlock();
2011     if (dst_bits.free) dst_bits.free( &dst_bits );
2012     return ret;
2013 }
2014
2015 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2016                                   Drawable drawable, const struct bitblt_coords *src,
2017                                   const struct bitblt_coords *dst )
2018 {
2019     int x_dst, y_dst;
2020     Picture src_pict = 0, dst_pict, mask_pict = 0;
2021     BOOL use_repeat;
2022     double xscale, yscale;
2023
2024     use_repeat = use_source_repeat( physdev_src );
2025     if (!use_repeat)
2026     {
2027         xscale = src->width / (double)dst->width;
2028         yscale = src->height / (double)dst->height;
2029     }
2030     else xscale = yscale = 1;  /* no scaling needed with a repeating source */
2031
2032     if (drawable)  /* using an intermediate pixmap */
2033     {
2034         XRenderPictureAttributes pa;
2035
2036         x_dst = dst->x;
2037         y_dst = dst->y;
2038         pa.repeat = RepeatNone;
2039         wine_tsx11_lock();
2040         dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2041         wine_tsx11_unlock();
2042     }
2043     else
2044     {
2045         x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2046         y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2047         dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2048     }
2049
2050     src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2051
2052     /* mono -> color */
2053     if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2054     {
2055         XRenderColor fg, bg;
2056
2057         get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
2058         get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
2059         fg.alpha = bg.alpha = 0;
2060
2061         xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2062                            physdev_src->x11dev->dc_rect.left + src->x,
2063                            physdev_src->x11dev->dc_rect.top + src->y,
2064                            src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2065     }
2066     else /* color -> color (can be at different depths) or mono -> mono */
2067     {
2068         if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
2069             mask_pict = get_no_alpha_mask();
2070
2071         xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2072                       physdev_src->x11dev->dc_rect.left + src->x,
2073                       physdev_src->x11dev->dc_rect.top + src->y,
2074                       src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2075     }
2076
2077     if (drawable)
2078     {
2079         wine_tsx11_lock();
2080         pXRenderFreePicture( gdi_display, dst_pict );
2081         wine_tsx11_unlock();
2082     }
2083 }
2084
2085
2086 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2087                                XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2088                                Drawable drawable, struct bitblt_coords *src,
2089                                struct bitblt_coords *dst, BOOL use_repeat )
2090 {
2091     int x_dst, y_dst;
2092     Picture dst_pict;
2093     XRenderPictureAttributes pa;
2094     double xscale, yscale;
2095
2096     if (drawable)  /* using an intermediate pixmap */
2097     {
2098         RGNDATA *clip_data = NULL;
2099
2100         if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2101         x_dst = dst->x;
2102         y_dst = dst->y;
2103         pa.repeat = RepeatNone;
2104         wine_tsx11_lock();
2105         dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2106         if (clip_data)
2107             pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2108                                               (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2109         wine_tsx11_unlock();
2110         HeapFree( GetProcessHeap(), 0, clip_data );
2111     }
2112     else
2113     {
2114         x_dst = physdev->x11dev->dc_rect.left + dst->x;
2115         y_dst = physdev->x11dev->dc_rect.top + dst->y;
2116         dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2117     }
2118
2119     if (!use_repeat)
2120     {
2121         xscale = src->width / (double)dst->width;
2122         yscale = src->height / (double)dst->height;
2123     }
2124     else xscale = yscale = 1;  /* no scaling needed with a repeating source */
2125
2126     xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
2127                   x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2128
2129     if (drawable)
2130     {
2131         wine_tsx11_lock();
2132         pXRenderFreePicture( gdi_display, dst_pict );
2133         wine_tsx11_unlock();
2134     }
2135 }
2136
2137
2138 /***********************************************************************
2139  *           xrenderdrv_StretchBlt
2140  */
2141 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2142                                    PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2143 {
2144     struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2145     struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2146     BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2147
2148     if (src_dev->funcs != dst_dev->funcs)
2149     {
2150         dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2151         return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2152     }
2153
2154     /* XRender is of no use for color -> mono */
2155     if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2156         goto x11drv_fallback;
2157
2158     /* if not stretching, we only need to handle format conversion */
2159     if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2160
2161     if (rop != SRCCOPY)
2162     {
2163         GC tmpGC;
2164         Pixmap tmp_pixmap;
2165         struct bitblt_coords tmp;
2166
2167         /* make coordinates relative to tmp pixmap */
2168         tmp = *dst;
2169         tmp.x -= tmp.visrect.left;
2170         tmp.y -= tmp.visrect.top;
2171         OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2172
2173         wine_tsx11_lock();
2174         tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2175         XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2176         XSetGraphicsExposures( gdi_display, tmpGC, False );
2177         tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2178                                     tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
2179         wine_tsx11_unlock();
2180
2181         xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2182         execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2183
2184         wine_tsx11_lock();
2185         XFreePixmap( gdi_display, tmp_pixmap );
2186         XFreeGC( gdi_display, tmpGC );
2187         wine_tsx11_unlock();
2188     }
2189     else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2190
2191     return TRUE;
2192
2193 x11drv_fallback:
2194     return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2195 }
2196
2197
2198 /***********************************************************************
2199  *           xrenderdrv_PutImage
2200  */
2201 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2202                                   const struct gdi_image_bits *bits, struct bitblt_coords *src,
2203                                   struct bitblt_coords *dst, DWORD rop )
2204 {
2205     struct xrender_physdev *physdev;
2206     X_PHYSBITMAP *bitmap;
2207     DWORD ret;
2208     Pixmap tmp_pixmap;
2209     GC gc;
2210     enum wxr_format src_format, dst_format;
2211     XRenderPictFormat *pict_format;
2212     Pixmap src_pixmap;
2213     Picture src_pict, mask_pict = 0;
2214     BOOL use_repeat;
2215
2216     if (hbitmap)
2217     {
2218         if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2219         physdev = NULL;
2220         dst_format = bitmap->format;
2221     }
2222     else
2223     {
2224         physdev = get_xrender_dev( dev );
2225         bitmap = NULL;
2226         dst_format = physdev->format;
2227     }
2228
2229     src_format = get_xrender_format_from_bitmapinfo( info );
2230     if (!(pict_format = pict_formats[src_format])) goto update_format;
2231
2232     /* make sure we can create an image with the same bpp */
2233     if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2234         goto update_format;
2235
2236     /* mono <-> color conversions not supported */
2237     if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2238         goto x11drv_fallback;
2239
2240     if (!bits) return ERROR_SUCCESS;  /* just querying the format */
2241
2242     if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2243
2244     ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2245     if (!ret)
2246     {
2247         struct bitblt_coords tmp;
2248
2249         if (bitmap)
2250         {
2251             HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2252             if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2253
2254             xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2255                                pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2256             DeleteObject( rgn );
2257         }
2258         else
2259         {
2260             if (rop != SRCCOPY)
2261             {
2262                 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2263
2264                 /* make coordinates relative to tmp pixmap */
2265                 tmp = *dst;
2266                 tmp.x -= tmp.visrect.left;
2267                 tmp.y -= tmp.visrect.top;
2268                 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2269
2270                 wine_tsx11_lock();
2271                 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2272                 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2273                 XSetGraphicsExposures( gdi_display, gc, False );
2274                 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2275                                             tmp.visrect.right - tmp.visrect.left,
2276                                             tmp.visrect.bottom - tmp.visrect.top,
2277                                             physdev->pict_format->depth );
2278                 wine_tsx11_unlock();
2279
2280                 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2281                                    NULL, tmp_pixmap, src, &tmp, use_repeat );
2282                 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2283
2284                 wine_tsx11_lock();
2285                 XFreePixmap( gdi_display, tmp_pixmap );
2286                 XFreeGC( gdi_display, gc );
2287                 wine_tsx11_unlock();
2288
2289                 if (restore_region) restore_clipping_region( physdev->x11dev );
2290             }
2291             else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2292                                     physdev->pict_format, physdev, 0, src, dst, use_repeat );
2293         }
2294
2295         wine_tsx11_lock();
2296         pXRenderFreePicture( gdi_display, src_pict );
2297         XFreePixmap( gdi_display, src_pixmap );
2298         wine_tsx11_unlock();
2299     }
2300     return ret;
2301
2302 update_format:
2303     if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2304     set_color_info( pict_formats[dst_format], info );
2305     return ERROR_BAD_FORMAT;
2306
2307 x11drv_fallback:
2308     if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2309     dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2310     return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2311 }
2312
2313
2314 /***********************************************************************
2315  *           xrenderdrv_BlendImage
2316  */
2317 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2318                                     struct bitblt_coords *src, struct bitblt_coords *dst,
2319                                     BLENDFUNCTION func )
2320 {
2321     struct xrender_physdev *physdev = get_xrender_dev( dev );
2322     DWORD ret;
2323     enum wxr_format format;
2324     XRenderPictFormat *pict_format;
2325     Picture dst_pict, src_pict, mask_pict;
2326     Pixmap src_pixmap;
2327     BOOL use_repeat;
2328
2329     format = get_xrender_format_from_bitmapinfo( info );
2330     if (!(func.AlphaFormat & AC_SRC_ALPHA))
2331         format = get_format_without_alpha( format );
2332     else if (format != WXR_FORMAT_A8R8G8B8)
2333         return ERROR_INVALID_PARAMETER;
2334
2335     if (!(pict_format = pict_formats[format])) goto update_format;
2336
2337     /* make sure we can create an image with the same bpp */
2338     if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2339         goto update_format;
2340
2341     if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2342         goto update_format;
2343
2344     if (!bits) return ERROR_SUCCESS;  /* just querying the format */
2345
2346     ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2347     if (!ret)
2348     {
2349         double xscale, yscale;
2350
2351         if (!use_repeat)
2352         {
2353             xscale = src->width / (double)dst->width;
2354             yscale = src->height / (double)dst->height;
2355         }
2356         else xscale = yscale = 1;  /* no scaling needed with a repeating source */
2357
2358         dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2359
2360         EnterCriticalSection( &xrender_cs );
2361         mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2362
2363         xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2364                       src->x, src->y, src->width, src->height,
2365                       physdev->x11dev->dc_rect.left + dst->x,
2366                       physdev->x11dev->dc_rect.top + dst->y,
2367                       dst->width, dst->height, xscale, yscale );
2368
2369         wine_tsx11_lock();
2370         pXRenderFreePicture( gdi_display, src_pict );
2371         XFreePixmap( gdi_display, src_pixmap );
2372         wine_tsx11_unlock();
2373
2374         LeaveCriticalSection( &xrender_cs );
2375     }
2376     return ret;
2377
2378 update_format:
2379     if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2380     set_color_info( physdev->pict_format, info );
2381     return ERROR_BAD_FORMAT;
2382 }
2383
2384
2385 /***********************************************************************
2386  *           xrenderdrv_AlphaBlend
2387  */
2388 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2389                                    PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2390 {
2391     struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2392     struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2393     Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2394     XRenderPictureAttributes pa;
2395     Pixmap tmp_pixmap = 0;
2396     double xscale, yscale;
2397     BOOL use_repeat;
2398
2399     if (src_dev->funcs != dst_dev->funcs)
2400     {
2401         dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2402         return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2403     }
2404
2405     if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2406     {
2407         SetLastError( ERROR_INVALID_PARAMETER );
2408         return FALSE;
2409     }
2410
2411     dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2412
2413     use_repeat = use_source_repeat( physdev_src );
2414     if (!use_repeat)
2415     {
2416         xscale = src->width / (double)dst->width;
2417         yscale = src->height / (double)dst->height;
2418     }
2419     else xscale = yscale = 1;  /* no scaling needed with a repeating source */
2420
2421     src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2422
2423     if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2424     {
2425         /* mono -> color blending needs an intermediate color pixmap */
2426         XRenderColor fg, bg;
2427         int width = src->visrect.right - src->visrect.left;
2428         int height = src->visrect.bottom - src->visrect.top;
2429
2430         /* blending doesn't use the destination DC colors */
2431         fg.red = fg.green = fg.blue = 0;
2432         bg.red = bg.green = bg.blue = 0xffff;
2433         fg.alpha = bg.alpha = 0xffff;
2434
2435         wine_tsx11_lock();
2436         tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2437                                     physdev_dst->pict_format->depth );
2438         pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2439         tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2440                                           CPRepeat, &pa );
2441         wine_tsx11_unlock();
2442
2443         xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2444                            src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
2445     }
2446     else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2447     {
2448         /* we need a source picture with no alpha */
2449         enum wxr_format format = get_format_without_alpha( physdev_src->format );
2450         if (format != physdev_src->format)
2451         {
2452             wine_tsx11_lock();
2453             pa.subwindow_mode = IncludeInferiors;
2454             pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2455             tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2456                                               pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2457             wine_tsx11_unlock();
2458         }
2459     }
2460
2461     if (tmp_pict) src_pict = tmp_pict;
2462
2463     EnterCriticalSection( &xrender_cs );
2464     mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2465
2466     xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2467                   physdev_src->x11dev->dc_rect.left + src->x,
2468                   physdev_src->x11dev->dc_rect.top + src->y,
2469                   src->width, src->height,
2470                   physdev_dst->x11dev->dc_rect.left + dst->x,
2471                   physdev_dst->x11dev->dc_rect.top + dst->y,
2472                   dst->width, dst->height, xscale, yscale );
2473
2474     wine_tsx11_lock();
2475     if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2476     if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2477     wine_tsx11_unlock();
2478
2479     LeaveCriticalSection( &xrender_cs );
2480     return TRUE;
2481 }
2482
2483 /***********************************************************************
2484  *           xrenderdrv_GradientFill
2485  */
2486 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2487                                      void * grad_array, ULONG ngrad, ULONG mode )
2488 {
2489 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2490     static const XFixed stops[2] = { 0, 1 << 16 };
2491     struct xrender_physdev *physdev = get_xrender_dev( dev );
2492     XLinearGradient gradient;
2493     XRenderColor colors[2];
2494     Picture src_pict, dst_pict;
2495     unsigned int i;
2496     const GRADIENT_RECT *rect = grad_array;
2497     POINT pt[2];
2498
2499     if (!pXRenderCreateLinearGradient) goto fallback;
2500
2501     /* <= 16-bpp uses dithering */
2502     if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2503
2504     switch (mode)
2505     {
2506     case GRADIENT_FILL_RECT_H:
2507     case GRADIENT_FILL_RECT_V:
2508         for (i = 0; i < ngrad; i++, rect++)
2509         {
2510             const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2511             const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2512
2513             colors[0].red   = v1->Red * 257 / 256;
2514             colors[0].green = v1->Green * 257 / 256;
2515             colors[0].blue  = v1->Blue * 257 / 256;
2516             colors[1].red   = v2->Red * 257 / 256;
2517             colors[1].green = v2->Green * 257 / 256;
2518             colors[1].blue  = v2->Blue * 257 / 256;
2519             /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2520             colors[0].alpha = colors[1].alpha = 65535;
2521
2522             pt[0].x = v1->x;
2523             pt[0].y = v1->y;
2524             pt[1].x = v2->x;
2525             pt[1].y = v2->y;
2526             LPtoDP( dev->hdc, pt, 2 );
2527             if (mode == GRADIENT_FILL_RECT_H)
2528             {
2529                 gradient.p1.y = gradient.p2.y = 0;
2530                 if (pt[1].x > pt[0].x)
2531                 {
2532                     gradient.p1.x = 0;
2533                     gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2534                 }
2535                 else
2536                 {
2537                     gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2538                     gradient.p2.x = 0;
2539                 }
2540             }
2541             else
2542             {
2543                 gradient.p1.x = gradient.p2.x = 0;
2544                 if (pt[1].y > pt[0].y)
2545                 {
2546                     gradient.p1.y = 0;
2547                     gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2548                 }
2549                 else
2550                 {
2551                     gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2552                     gradient.p2.y = 0;
2553                 }
2554             }
2555
2556             TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2557                    mode, pt[0].x, pt[0].y, pt[1].x, pt[1].y,
2558                    colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2559                    colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2560
2561             dst_pict = get_xrender_picture( physdev, 0, NULL );
2562
2563             wine_tsx11_lock();
2564             src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2565             xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2566                           0, 0, abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y),
2567                           physdev->x11dev->dc_rect.left + min( pt[0].x, pt[1].x ),
2568                           physdev->x11dev->dc_rect.top + min( pt[0].y, pt[1].y ),
2569                           abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y), 1, 1 );
2570             pXRenderFreePicture( gdi_display, src_pict );
2571             wine_tsx11_unlock();
2572         }
2573         return TRUE;
2574     }
2575
2576 fallback:
2577 #endif
2578     dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2579     return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2580 }
2581
2582 /***********************************************************************
2583  *           xrenderdrv_SelectBrush
2584  */
2585 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2586 {
2587     struct xrender_physdev *physdev = get_xrender_dev( dev );
2588     X_PHYSBITMAP *physbitmap;
2589     BOOL delete_bitmap = FALSE;
2590     BITMAP bm;
2591     HBITMAP bitmap;
2592     Pixmap pixmap;
2593     XRenderPictFormat *pict_format;
2594     Picture src_pict, dst_pict;
2595     XRenderPictureAttributes pa;
2596
2597     if (!pattern) goto x11drv_fallback;
2598     if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2599
2600     bitmap = pattern->bitmap;
2601     if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2602     {
2603         if (!(bitmap = create_brush_bitmap( physdev->x11dev, pattern ))) return 0;
2604         physbitmap = X11DRV_get_phys_bitmap( bitmap );
2605         delete_bitmap = TRUE;
2606     }
2607
2608     if (physbitmap->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2609     if (!(pict_format = pict_formats[physbitmap->format])) goto x11drv_fallback;
2610
2611     GetObjectW( bitmap, sizeof(bm), &bm );
2612
2613     wine_tsx11_lock();
2614     pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2615                             physdev->pict_format->depth );
2616
2617     pa.repeat = RepeatNone;
2618     src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_format, CPRepeat, &pa);
2619     dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2620
2621     xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, bm.bmWidth, bm.bmHeight,
2622                   0, 0, bm.bmWidth, bm.bmHeight, 1.0, 1.0 );
2623     pXRenderFreePicture( gdi_display, src_pict );
2624     pXRenderFreePicture( gdi_display, dst_pict );
2625
2626     if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2627     physdev->x11dev->brush.pixmap = pixmap;
2628     physdev->x11dev->brush.fillStyle = FillTiled;
2629     physdev->x11dev->brush.pixel = 0;  /* ignored */
2630     physdev->x11dev->brush.style = BS_PATTERN;
2631     wine_tsx11_unlock();
2632
2633     if (delete_bitmap) DeleteObject( bitmap );
2634     return hbrush;
2635
2636 x11drv_fallback:
2637     if (delete_bitmap) DeleteObject( bitmap );
2638     dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2639     return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2640 }
2641
2642
2643 static const struct gdi_dc_funcs xrender_funcs =
2644 {
2645     NULL,                               /* pAbortDoc */
2646     NULL,                               /* pAbortPath */
2647     xrenderdrv_AlphaBlend,              /* pAlphaBlend */
2648     NULL,                               /* pAngleArc */
2649     NULL,                               /* pArc */
2650     NULL,                               /* pArcTo */
2651     NULL,                               /* pBeginPath */
2652     xrenderdrv_BlendImage,              /* pBlendImage */
2653     NULL,                               /* pChoosePixelFormat */
2654     NULL,                               /* pChord */
2655     NULL,                               /* pCloseFigure */
2656     xrenderdrv_CopyBitmap,              /* pCopyBitmap */
2657     xrenderdrv_CreateBitmap,            /* pCreateBitmap */
2658     xrenderdrv_CreateCompatibleDC,      /* pCreateCompatibleDC */
2659     xrenderdrv_CreateDC,                /* pCreateDC */
2660     xrenderdrv_DeleteBitmap,            /* pDeleteBitmap */
2661     xrenderdrv_DeleteDC,                /* pDeleteDC */
2662     NULL,                               /* pDeleteObject */
2663     NULL,                               /* pDescribePixelFormat */
2664     NULL,                               /* pDeviceCapabilities */
2665     NULL,                               /* pEllipse */
2666     NULL,                               /* pEndDoc */
2667     NULL,                               /* pEndPage */
2668     NULL,                               /* pEndPath */
2669     NULL,                               /* pEnumFonts */
2670     NULL,                               /* pEnumICMProfiles */
2671     NULL,                               /* pExcludeClipRect */
2672     NULL,                               /* pExtDeviceMode */
2673     xrenderdrv_ExtEscape,               /* pExtEscape */
2674     NULL,                               /* pExtFloodFill */
2675     NULL,                               /* pExtSelectClipRgn */
2676     xrenderdrv_ExtTextOut,              /* pExtTextOut */
2677     NULL,                               /* pFillPath */
2678     NULL,                               /* pFillRgn */
2679     NULL,                               /* pFlattenPath */
2680     NULL,                               /* pFontIsLinked */
2681     NULL,                               /* pFrameRgn */
2682     NULL,                               /* pGdiComment */
2683     NULL,                               /* pGdiRealizationInfo */
2684     NULL,                               /* pGetCharABCWidths */
2685     NULL,                               /* pGetCharABCWidthsI */
2686     NULL,                               /* pGetCharWidth */
2687     NULL,                               /* pGetDeviceCaps */
2688     NULL,                               /* pGetDeviceGammaRamp */
2689     NULL,                               /* pGetFontData */
2690     NULL,                               /* pGetFontUnicodeRanges */
2691     NULL,                               /* pGetGlyphIndices */
2692     NULL,                               /* pGetGlyphOutline */
2693     NULL,                               /* pGetICMProfile */
2694     xrenderdrv_GetImage,                /* pGetImage */
2695     NULL,                               /* pGetKerningPairs */
2696     NULL,                               /* pGetNearestColor */
2697     NULL,                               /* pGetOutlineTextMetrics */
2698     NULL,                               /* pGetPixel */
2699     NULL,                               /* pGetPixelFormat */
2700     NULL,                               /* pGetSystemPaletteEntries */
2701     NULL,                               /* pGetTextCharsetInfo */
2702     NULL,                               /* pGetTextExtentExPoint */
2703     NULL,                               /* pGetTextExtentExPointI */
2704     NULL,                               /* pGetTextFace */
2705     NULL,                               /* pGetTextMetrics */
2706     xrenderdrv_GradientFill,            /* pGradientFill */
2707     NULL,                               /* pIntersectClipRect */
2708     NULL,                               /* pInvertRgn */
2709     NULL,                               /* pLineTo */
2710     NULL,                               /* pModifyWorldTransform */
2711     NULL,                               /* pMoveTo */
2712     NULL,                               /* pOffsetClipRgn */
2713     NULL,                               /* pOffsetViewportOrg */
2714     NULL,                               /* pOffsetWindowOrg */
2715     NULL,                               /* pPaintRgn */
2716     NULL,                               /* pPatBlt */
2717     NULL,                               /* pPie */
2718     NULL,                               /* pPolyBezier */
2719     NULL,                               /* pPolyBezierTo */
2720     NULL,                               /* pPolyDraw */
2721     NULL,                               /* pPolyPolygon */
2722     NULL,                               /* pPolyPolyline */
2723     NULL,                               /* pPolygon */
2724     NULL,                               /* pPolyline */
2725     NULL,                               /* pPolylineTo */
2726     xrenderdrv_PutImage,                /* pPutImage */
2727     NULL,                               /* pRealizeDefaultPalette */
2728     NULL,                               /* pRealizePalette */
2729     NULL,                               /* pRectangle */
2730     NULL,                               /* pResetDC */
2731     NULL,                               /* pRestoreDC */
2732     NULL,                               /* pRoundRect */
2733     NULL,                               /* pSaveDC */
2734     NULL,                               /* pScaleViewportExt */
2735     NULL,                               /* pScaleWindowExt */
2736     xrenderdrv_SelectBitmap,            /* pSelectBitmap */
2737     xrenderdrv_SelectBrush,             /* pSelectBrush */
2738     NULL,                               /* pSelectClipPath */
2739     xrenderdrv_SelectFont,              /* pSelectFont */
2740     NULL,                               /* pSelectPalette */
2741     NULL,                               /* pSelectPen */
2742     NULL,                               /* pSetArcDirection */
2743     NULL,                               /* pSetBkColor */
2744     NULL,                               /* pSetBkMode */
2745     NULL,                               /* pSetDCBrushColor */
2746     NULL,                               /* pSetDCPenColor */
2747     NULL,                               /* pSetDIBitsToDevice */
2748     xrenderdrv_SetDeviceClipping,       /* pSetDeviceClipping */
2749     NULL,                               /* pSetDeviceGammaRamp */
2750     NULL,                               /* pSetLayout */
2751     NULL,                               /* pSetMapMode */
2752     NULL,                               /* pSetMapperFlags */
2753     NULL,                               /* pSetPixel */
2754     NULL,                               /* pSetPixelFormat */
2755     NULL,                               /* pSetPolyFillMode */
2756     NULL,                               /* pSetROP2 */
2757     NULL,                               /* pSetRelAbs */
2758     NULL,                               /* pSetStretchBltMode */
2759     NULL,                               /* pSetTextAlign */
2760     NULL,                               /* pSetTextCharacterExtra */
2761     NULL,                               /* pSetTextColor */
2762     NULL,                               /* pSetTextJustification */
2763     NULL,                               /* pSetViewportExt */
2764     NULL,                               /* pSetViewportOrg */
2765     NULL,                               /* pSetWindowExt */
2766     NULL,                               /* pSetWindowOrg */
2767     NULL,                               /* pSetWorldTransform */
2768     NULL,                               /* pStartDoc */
2769     NULL,                               /* pStartPage */
2770     xrenderdrv_StretchBlt,              /* pStretchBlt */
2771     NULL,                               /* pStretchDIBits */
2772     NULL,                               /* pStrokeAndFillPath */
2773     NULL,                               /* pStrokePath */
2774     NULL,                               /* pSwapBuffers */
2775     NULL,                               /* pUnrealizePalette */
2776     NULL,                               /* pWidenPath */
2777     /* OpenGL not supported */
2778 };
2779
2780 #else /* SONAME_LIBXRENDER */
2781
2782 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2783 {
2784     TRACE("XRender support not compiled in.\n");
2785     return NULL;
2786 }
2787
2788 void X11DRV_XRender_Finalize(void)
2789 {
2790 }
2791
2792 #endif /* SONAME_LIBXRENDER */