Release 1.4.1.
[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         if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE && lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
1136             lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
1137
1138         /* Not used fields, would break hashing */
1139         lfsz.xform.eDx = lfsz.xform.eDy = 0;
1140
1141         lfsz_calc_hash(&lfsz);
1142
1143         EnterCriticalSection(&xrender_cs);
1144         if (physdev->cache_index != -1)
1145             dec_ref_cache( physdev->cache_index );
1146         physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1147         LeaveCriticalSection(&xrender_cs);
1148     }
1149     else
1150     {
1151         EnterCriticalSection( &xrender_cs );
1152         if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1153         physdev->cache_index = -1;
1154         LeaveCriticalSection( &xrender_cs );
1155     }
1156     return ret;
1157 }
1158
1159 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1160 {
1161     X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1162     struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1163
1164     if (!physdev) return FALSE;
1165     physdev->x11dev = x11dev;
1166     physdev->cache_index = -1;
1167     physdev->format = format;
1168     physdev->pict_format = pict_formats[format];
1169     push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1170     return TRUE;
1171 }
1172
1173 /* store the color mask data in the bitmap info structure */
1174 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1175 {
1176     DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1177
1178     info->bmiHeader.biPlanes      = 1;
1179     info->bmiHeader.biBitCount    = pixmap_formats[format->depth]->bits_per_pixel;
1180     info->bmiHeader.biCompression = BI_RGB;
1181     info->bmiHeader.biClrUsed     = 0;
1182
1183     switch (info->bmiHeader.biBitCount)
1184     {
1185     case 16:
1186         colors[0] = format->direct.redMask   << format->direct.red;
1187         colors[1] = format->direct.greenMask << format->direct.green;
1188         colors[2] = format->direct.blueMask  << format->direct.blue;
1189         info->bmiHeader.biCompression = BI_BITFIELDS;
1190         break;
1191     case 32:
1192         colors[0] = format->direct.redMask   << format->direct.red;
1193         colors[1] = format->direct.greenMask << format->direct.green;
1194         colors[2] = format->direct.blueMask  << format->direct.blue;
1195         if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1196             info->bmiHeader.biCompression = BI_BITFIELDS;
1197         break;
1198     }
1199 }
1200
1201
1202 /**********************************************************************
1203  *           xrenderdrv_CreateDC
1204  */
1205 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1206                                  LPCWSTR output, const DEVMODEW* initData )
1207 {
1208     return create_xrender_dc( pdev, default_format );
1209 }
1210
1211 /**********************************************************************
1212  *           xrenderdrv_CreateCompatibleDC
1213  */
1214 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1215 {
1216     if (orig)  /* chain to x11drv first */
1217     {
1218         orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1219         if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1220     }
1221     /* otherwise we have been called by x11drv */
1222
1223     return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1224 }
1225
1226 /**********************************************************************
1227  *           xrenderdrv_DeleteDC
1228  */
1229 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1230 {
1231     struct xrender_physdev *physdev = get_xrender_dev( dev );
1232
1233     free_xrender_picture( physdev );
1234
1235     EnterCriticalSection( &xrender_cs );
1236     if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1237     LeaveCriticalSection( &xrender_cs );
1238
1239     HeapFree( GetProcessHeap(), 0, physdev );
1240     return TRUE;
1241 }
1242
1243 /**********************************************************************
1244  *           xrenderdrv_ExtEscape
1245  */
1246 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1247                                  INT out_count, LPVOID out_data )
1248 {
1249     struct xrender_physdev *physdev = get_xrender_dev( dev );
1250
1251     dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1252
1253     if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1254     {
1255         if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1256         {
1257             BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1258             if (ret) free_xrender_picture( physdev );  /* pict format doesn't change, only drawable */
1259             return ret;
1260         }
1261     }
1262     return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1263 }
1264
1265 /****************************************************************************
1266  *        xrenderdrv_CopyBitmap
1267  */
1268 static BOOL xrenderdrv_CopyBitmap( HBITMAP src, HBITMAP dst )
1269 {
1270     return X11DRV_CopyBitmap( src, dst );
1271 }
1272
1273 /****************************************************************************
1274  *        xrenderdrv_CreateBitmap
1275  */
1276 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1277 {
1278     enum wxr_format format = WXR_INVALID_FORMAT;
1279     X_PHYSBITMAP *phys_bitmap;
1280     BITMAP bitmap;
1281
1282     if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1283
1284     if (bitmap.bmBitsPixel == 1)
1285     {
1286         if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, 1 ))) return FALSE;
1287         phys_bitmap->format = WXR_FORMAT_MONO;
1288         phys_bitmap->trueColor = FALSE;
1289     }
1290     else
1291     {
1292         format = get_bitmap_format( bitmap.bmBitsPixel );
1293
1294         if (pict_formats[format])
1295         {
1296             if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth )))
1297                 return FALSE;
1298             phys_bitmap->format = format;
1299             phys_bitmap->trueColor = TRUE;
1300             phys_bitmap->color_shifts = wxr_color_shifts[format];
1301         }
1302         else
1303         {
1304             if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, screen_depth )))
1305                 return FALSE;
1306             phys_bitmap->format = WXR_INVALID_FORMAT;
1307             phys_bitmap->trueColor = (visual->class == TrueColor || visual->class == DirectColor);
1308             phys_bitmap->color_shifts = X11DRV_PALETTE_default_shifts;
1309         }
1310     }
1311     return TRUE;
1312 }
1313
1314 /****************************************************************************
1315  *        xrenderdrv_DeleteBitmap
1316  */
1317 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1318 {
1319     return X11DRV_DeleteBitmap( hbitmap );
1320 }
1321
1322 /***********************************************************************
1323  *           xrenderdrv_SelectBitmap
1324  */
1325 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1326 {
1327     HBITMAP ret;
1328     struct xrender_physdev *physdev = get_xrender_dev( dev );
1329
1330     dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1331     ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1332     if (ret)
1333     {
1334         free_xrender_picture( physdev );
1335         if (hbitmap == BITMAP_stock_phys_bitmap.hbitmap) physdev->format = WXR_FORMAT_MONO;
1336         else physdev->format = X11DRV_get_phys_bitmap(hbitmap)->format;
1337         physdev->pict_format = pict_formats[physdev->format];
1338     }
1339     return ret;
1340 }
1341
1342 /***********************************************************************
1343  *           xrenderdrv_GetImage
1344  */
1345 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1346                                   struct gdi_image_bits *bits, struct bitblt_coords *src )
1347 {
1348     if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1349     dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1350     return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1351 }
1352
1353 /***********************************************************************
1354  *           xrenderdrv_SetDeviceClipping
1355  */
1356 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1357 {
1358     struct xrender_physdev *physdev = get_xrender_dev( dev );
1359
1360     physdev->region = rgn;
1361     physdev->update_clip = TRUE;
1362
1363     dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1364     dev->funcs->pSetDeviceClipping( dev, rgn );
1365 }
1366
1367
1368 /************************************************************************
1369  *   UploadGlyph
1370  *
1371  * Helper to ExtTextOut.  Must be called inside xrender_cs
1372  */
1373 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1374 {
1375     unsigned int buflen;
1376     char *buf;
1377     Glyph gid;
1378     GLYPHMETRICS gm;
1379     XGlyphInfo gi;
1380     gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1381     gsCacheEntryFormat *formatEntry;
1382     UINT ggo_format = GGO_GLYPH_INDEX;
1383     enum wxr_format wxr_format;
1384     static const char zero[4];
1385     static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1386
1387     switch(format) {
1388     case AA_Grey:
1389         ggo_format |= WINE_GGO_GRAY16_BITMAP;
1390         break;
1391     case AA_RGB:
1392         ggo_format |= WINE_GGO_HRGB_BITMAP;
1393         break;
1394     case AA_BGR:
1395         ggo_format |= WINE_GGO_HBGR_BITMAP;
1396         break;
1397     case AA_VRGB:
1398         ggo_format |= WINE_GGO_VRGB_BITMAP;
1399         break;
1400     case AA_VBGR:
1401         ggo_format |= WINE_GGO_VBGR_BITMAP;
1402         break;
1403
1404     default:
1405         ERR("aa = %d - not implemented\n", format);
1406     case AA_None:
1407         ggo_format |= GGO_BITMAP;
1408         break;
1409     }
1410
1411     buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1412     if(buflen == GDI_ERROR) {
1413         if(format != AA_None) {
1414             format = AA_None;
1415             entry->aa_default = AA_None;
1416             ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1417             buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1418         }
1419         if(buflen == GDI_ERROR) {
1420             WARN("GetGlyphOutlineW failed using default glyph\n");
1421             buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1422             if(buflen == GDI_ERROR) {
1423                 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1424                 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1425                 if(buflen == GDI_ERROR) {
1426                     ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1427                     return;
1428                 }
1429             }
1430         }
1431         TRACE("Turning off antialiasing for this monochrome font\n");
1432     }
1433
1434     /* If there is nothing for the current type, we create the entry. */
1435     if( !entry->format[format] ) {
1436         entry->format[format] = HeapAlloc(GetProcessHeap(),
1437                                           HEAP_ZERO_MEMORY,
1438                                           sizeof(gsCacheEntryFormat));
1439     }
1440     formatEntry = entry->format[format];
1441
1442     if(formatEntry->nrealized <= glyph) {
1443         formatEntry->nrealized = (glyph / 128 + 1) * 128;
1444
1445         if (formatEntry->realized)
1446             formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1447                                       HEAP_ZERO_MEMORY,
1448                                       formatEntry->realized,
1449                                       formatEntry->nrealized * sizeof(BOOL));
1450         else
1451             formatEntry->realized = HeapAlloc(GetProcessHeap(),
1452                                       HEAP_ZERO_MEMORY,
1453                                       formatEntry->nrealized * sizeof(BOOL));
1454
1455         if (formatEntry->gis)
1456             formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1457                                    HEAP_ZERO_MEMORY,
1458                                    formatEntry->gis,
1459                                    formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1460         else
1461             formatEntry->gis = HeapAlloc(GetProcessHeap(),
1462                                    HEAP_ZERO_MEMORY,
1463                                    formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1464     }
1465
1466
1467     if(formatEntry->glyphset == 0) {
1468         switch(format) {
1469             case AA_Grey:
1470                 wxr_format = WXR_FORMAT_GRAY;
1471                 break;
1472
1473             case AA_RGB:
1474             case AA_BGR:
1475             case AA_VRGB:
1476             case AA_VBGR:
1477                 wxr_format = WXR_FORMAT_A8R8G8B8;
1478                 break;
1479
1480             default:
1481                 ERR("aa = %d - not implemented\n", format);
1482             case AA_None:
1483                 wxr_format = WXR_FORMAT_MONO;
1484                 break;
1485         }
1486
1487         wine_tsx11_lock();
1488         formatEntry->font_format = pict_formats[wxr_format];
1489         formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1490         wine_tsx11_unlock();
1491     }
1492
1493
1494     buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1495     GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1496     formatEntry->realized[glyph] = TRUE;
1497
1498     TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1499           buflen,
1500           gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1501           gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1502
1503     gi.width = gm.gmBlackBoxX;
1504     gi.height = gm.gmBlackBoxY;
1505     gi.x = -gm.gmptGlyphOrigin.x;
1506     gi.y = gm.gmptGlyphOrigin.y;
1507     gi.xOff = gm.gmCellIncX;
1508     gi.yOff = gm.gmCellIncY;
1509
1510     if(TRACE_ON(xrender)) {
1511         int pitch, i, j;
1512         char output[300];
1513         unsigned char *line;
1514
1515         if(format == AA_None) {
1516             pitch = ((gi.width + 31) / 32) * 4;
1517             for(i = 0; i < gi.height; i++) {
1518                 line = (unsigned char*) buf + i * pitch;
1519                 output[0] = '\0';
1520                 for(j = 0; j < pitch * 8; j++) {
1521                     strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1522                 }
1523                 TRACE("%s\n", output);
1524             }
1525         } else {
1526             static const char blks[] = " .:;!o*#";
1527             char str[2];
1528
1529             str[1] = '\0';
1530             pitch = ((gi.width + 3) / 4) * 4;
1531             for(i = 0; i < gi.height; i++) {
1532                 line = (unsigned char*) buf + i * pitch;
1533                 output[0] = '\0';
1534                 for(j = 0; j < pitch; j++) {
1535                     str[0] = blks[line[j] >> 5];
1536                     strcat(output, str);
1537                 }
1538                 TRACE("%s\n", output);
1539             }
1540         }
1541     }
1542
1543
1544     if(formatEntry->glyphset) {
1545         if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1546             unsigned char *byte = (unsigned char*) buf, c;
1547             int i = buflen;
1548
1549             while(i--) {
1550                 c = *byte;
1551
1552                 /* magic to flip bit order */
1553                 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1554                 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1555                 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1556
1557                 *byte++ = c;
1558             }
1559         }
1560         else if ( format != AA_Grey &&
1561                   ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1562         {
1563             unsigned int i, *data = (unsigned int *)buf;
1564             for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1565         }
1566         gid = glyph;
1567
1568         /*
1569           XRenderCompositeText seems to ignore 0x0 glyphs when
1570           AA_None, which means we lose the advance width of glyphs
1571           like the space.  We'll pretend that such glyphs are 1x1
1572           bitmaps.
1573         */
1574
1575         if(buflen == 0)
1576             gi.width = gi.height = 1;
1577
1578         wine_tsx11_lock();
1579         pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1580                           buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1581         wine_tsx11_unlock();
1582         HeapFree(GetProcessHeap(), 0, buf);
1583     }
1584
1585     formatEntry->gis[glyph] = gi;
1586 }
1587
1588 /*************************************************************
1589  *                 get_tile_pict
1590  *
1591  * Returns an appropriate Picture for tiling the text colour.
1592  * Call and use result within the xrender_cs
1593  */
1594 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1595 {
1596     static struct
1597     {
1598         Pixmap xpm;
1599         Picture pict;
1600         XRenderColor current_color;
1601     } tiles[WXR_NB_FORMATS], *tile;
1602
1603     tile = &tiles[wxr_format];
1604
1605     if(!tile->xpm)
1606     {
1607         XRenderPictureAttributes pa;
1608         XRenderPictFormat *pict_format = pict_formats[wxr_format];
1609
1610         wine_tsx11_lock();
1611         tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1612
1613         pa.repeat = RepeatNormal;
1614         tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1615         wine_tsx11_unlock();
1616
1617         /* init current_color to something different from text_pixel */
1618         tile->current_color = *color;
1619         tile->current_color.red ^= 0xffff;
1620
1621         if (wxr_format == WXR_FORMAT_MONO)
1622         {
1623             /* for a 1bpp bitmap we always need a 1 in the tile */
1624             XRenderColor col;
1625             col.red = col.green = col.blue = 0;
1626             col.alpha = 0xffff;
1627             wine_tsx11_lock();
1628             pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1629             wine_tsx11_unlock();
1630         }
1631     }
1632
1633     if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1634     {
1635         wine_tsx11_lock();
1636         pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1637         wine_tsx11_unlock();
1638         tile->current_color = *color;
1639     }
1640     return tile->pict;
1641 }
1642
1643 /*************************************************************
1644  *                 get_mask_pict
1645  *
1646  * Returns an appropriate Picture for masking with the specified alpha.
1647  * Call and use result within the xrender_cs
1648  */
1649 static Picture get_mask_pict( int alpha )
1650 {
1651     static Pixmap pixmap;
1652     static Picture pict;
1653     static int current_alpha;
1654
1655     if (alpha == 0xffff) return 0;  /* don't need a mask for alpha==1.0 */
1656
1657     if (!pixmap)
1658     {
1659         XRenderPictureAttributes pa;
1660
1661         wine_tsx11_lock();
1662         pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1663         pa.repeat = RepeatNormal;
1664         pict = pXRenderCreatePicture( gdi_display, pixmap,
1665                                       pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1666         wine_tsx11_unlock();
1667         current_alpha = -1;
1668     }
1669
1670     if (alpha != current_alpha)
1671     {
1672         XRenderColor col;
1673         col.red = col.green = col.blue = 0;
1674         col.alpha = current_alpha = alpha;
1675         wine_tsx11_lock();
1676         pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1677         wine_tsx11_unlock();
1678     }
1679     return pict;
1680 }
1681
1682 /***********************************************************************
1683  *           xrenderdrv_ExtTextOut
1684  */
1685 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1686                                    const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1687 {
1688     struct xrender_physdev *physdev = get_xrender_dev( dev );
1689     gsCacheEntry *entry;
1690     gsCacheEntryFormat *formatEntry;
1691     AA_Type aa_type = AA_None;
1692     unsigned int idx;
1693     Picture pict, tile_pict = 0;
1694     XGlyphElt16 *elts;
1695     POINT offset, desired, current;
1696     int render_op = PictOpOver;
1697     XRenderColor col;
1698
1699     if (!physdev->x11dev->has_gdi_font)
1700     {
1701         dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1702         return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1703     }
1704
1705     get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1706     pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1707
1708     if(flags & ETO_OPAQUE)
1709     {
1710         XRenderColor bg;
1711
1712         if (physdev->format == WXR_FORMAT_MONO)
1713             /* use the inverse of the text color */
1714             bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1715         else
1716             get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1717
1718         wine_tsx11_lock();
1719         set_xrender_transformation( pict, 1, 1, 0, 0 );
1720         pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1721                                physdev->x11dev->dc_rect.left + lprect->left,
1722                                physdev->x11dev->dc_rect.top + lprect->top,
1723                                lprect->right - lprect->left,
1724                                lprect->bottom - lprect->top );
1725         wine_tsx11_unlock();
1726     }
1727
1728     if(count == 0) return TRUE;
1729
1730     EnterCriticalSection(&xrender_cs);
1731
1732     entry = glyphsetCache + physdev->cache_index;
1733     aa_type = entry->aa_default;
1734     formatEntry = entry->format[aa_type];
1735
1736     for(idx = 0; idx < count; idx++) {
1737         if( !formatEntry ) {
1738             UploadGlyph(physdev, wstr[idx], aa_type);
1739             /* re-evaluate antialias since aa_default may have changed */
1740             aa_type = entry->aa_default;
1741             formatEntry = entry->format[aa_type];
1742         } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1743             UploadGlyph(physdev, wstr[idx], aa_type);
1744         }
1745     }
1746     if (!formatEntry)
1747     {
1748         WARN("could not upload requested glyphs\n");
1749         LeaveCriticalSection(&xrender_cs);
1750         return FALSE;
1751     }
1752
1753     TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1754           physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1755
1756     elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1757
1758     /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1759        So we pass zeros to the function and move to our starting position using the first
1760        element of the elts array. */
1761
1762     desired.x = physdev->x11dev->dc_rect.left + x;
1763     desired.y = physdev->x11dev->dc_rect.top + y;
1764     offset.x = offset.y = 0;
1765     current.x = current.y = 0;
1766
1767     tile_pict = get_tile_pict(physdev->format, &col);
1768
1769     /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1770      */
1771     if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1772         render_op = PictOpOutReverse; /* This gives us 'black' text */
1773
1774     for(idx = 0; idx < count; idx++)
1775     {
1776         elts[idx].glyphset = formatEntry->glyphset;
1777         elts[idx].chars = wstr + idx;
1778         elts[idx].nchars = 1;
1779         elts[idx].xOff = desired.x - current.x;
1780         elts[idx].yOff = desired.y - current.y;
1781
1782         current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1783         current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1784
1785         if(!lpDx)
1786         {
1787             desired.x += formatEntry->gis[wstr[idx]].xOff;
1788             desired.y += formatEntry->gis[wstr[idx]].yOff;
1789         }
1790         else
1791         {
1792             if(flags & ETO_PDY)
1793             {
1794                 offset.x += lpDx[idx * 2];
1795                 offset.y += lpDx[idx * 2 + 1];
1796             }
1797             else
1798                 offset.x += lpDx[idx];
1799             desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1800             desired.y = physdev->x11dev->dc_rect.top  + y + offset.y;
1801         }
1802     }
1803
1804     wine_tsx11_lock();
1805     /* Make sure we don't have any transforms set from a previous call */
1806     set_xrender_transformation(pict, 1, 1, 0, 0);
1807     pXRenderCompositeText16(gdi_display, render_op,
1808                             tile_pict,
1809                             pict,
1810                             formatEntry->font_format,
1811                             0, 0, 0, 0, elts, count);
1812     wine_tsx11_unlock();
1813     HeapFree(GetProcessHeap(), 0, elts);
1814
1815     LeaveCriticalSection(&xrender_cs);
1816     return TRUE;
1817 }
1818
1819 /* multiply the alpha channel of a picture */
1820 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1821                             int x, int y, int width, int height )
1822 {
1823     XRenderPictureAttributes pa;
1824     Pixmap src_pixmap, mask_pixmap;
1825     Picture src_pict, mask_pict;
1826     XRenderColor color;
1827
1828     wine_tsx11_lock();
1829     src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1830     mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1831     pa.repeat = RepeatNormal;
1832     src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1833     pa.component_alpha = True;
1834     mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1835     color.red = color.green = color.blue = color.alpha = 0xffff;
1836     pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1837     color.alpha = alpha;
1838     pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1839     pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1840                        0, 0, 0, 0, x, y, width, height );
1841     pXRenderFreePicture( gdi_display, src_pict );
1842     pXRenderFreePicture( gdi_display, mask_pict );
1843     XFreePixmap( gdi_display, src_pixmap );
1844     XFreePixmap( gdi_display, mask_pixmap );
1845     wine_tsx11_unlock();
1846 }
1847
1848 /* Helper function for (stretched) blitting using xrender */
1849 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1850                           int x_src, int y_src, int width_src, int height_src,
1851                           int x_dst, int y_dst, int width_dst, int height_dst,
1852                           double xscale, double yscale )
1853 {
1854     int x_offset, y_offset;
1855
1856     if (width_src < 0)
1857     {
1858         x_src += width_src + 1;
1859         width_src = -width_src;
1860     }
1861     if (height_src < 0)
1862     {
1863         y_src += height_src + 1;
1864         height_src = -height_src;
1865     }
1866     if (width_dst < 0)
1867     {
1868         x_dst += width_dst + 1;
1869         width_dst = -width_dst;
1870     }
1871     if (height_dst < 0)
1872     {
1873         y_dst += height_dst + 1;
1874         height_dst = -height_dst;
1875     }
1876
1877     /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1878      * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1879      * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1880     wine_tsx11_lock();
1881     if(xscale != 1.0 || yscale != 1.0)
1882     {
1883         /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1884          * in the wrong quadrant of the x-y plane.
1885          */
1886         x_offset = (xscale < 0) ? -width_dst : 0;
1887         y_offset = (yscale < 0) ? -height_dst : 0;
1888         set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1889     }
1890     else
1891     {
1892         x_offset = x_src;
1893         y_offset = y_src;
1894         set_xrender_transformation(src_pict, 1, 1, 0, 0);
1895     }
1896     pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1897                        x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1898     wine_tsx11_unlock();
1899 }
1900
1901 /* Helper function for (stretched) mono->color blitting using xrender */
1902 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1903                                enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1904                                int x_src, int y_src, int width_src, int height_src,
1905                                int x_dst, int y_dst, int width_dst, int height_dst,
1906                                double xscale, double yscale )
1907 {
1908     Picture tile_pict;
1909     int x_offset, y_offset;
1910     XRenderColor color;
1911
1912     if (width_src < 0)
1913     {
1914         x_src += width_src + 1;
1915         width_src = -width_src;
1916     }
1917     if (height_src < 0)
1918     {
1919         y_src += height_src + 1;
1920         height_src = -height_src;
1921     }
1922     if (width_dst < 0)
1923     {
1924         x_dst += width_dst + 1;
1925         width_dst = -width_dst;
1926     }
1927     if (height_dst < 0)
1928     {
1929         y_dst += height_dst + 1;
1930         height_dst = -height_dst;
1931     }
1932
1933     /* When doing a mono->color blit, the source data is used as mask, and the source picture
1934      * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1935      * the tile data.
1936      */
1937     EnterCriticalSection( &xrender_cs );
1938     color = *bg;
1939     color.alpha = 0xffff;  /* tile pict needs 100% alpha */
1940     tile_pict = get_tile_pict( dst_format, &color );
1941
1942     wine_tsx11_lock();
1943     pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1944
1945     if (xscale != 1.0 || yscale != 1.0)
1946     {
1947         /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1948          * in the wrong quadrant of the x-y plane.
1949          */
1950         x_offset = (xscale < 0) ? -width_dst : 0;
1951         y_offset = (yscale < 0) ? -height_dst : 0;
1952         set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1953     }
1954     else
1955     {
1956         x_offset = x_src;
1957         y_offset = y_src;
1958         set_xrender_transformation(src_pict, 1, 1, 0, 0);
1959     }
1960     pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1961                       0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1962     wine_tsx11_unlock();
1963     LeaveCriticalSection( &xrender_cs );
1964
1965     /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1966     if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1967         multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1968                         x_dst, y_dst, width_dst, height_dst );
1969 }
1970
1971 /* create a pixmap and render picture for an image */
1972 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1973                                   struct bitblt_coords *src, enum wxr_format format,
1974                                   Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1975 {
1976     DWORD ret;
1977     int width = src->visrect.right - src->visrect.left;
1978     int height = src->visrect.bottom - src->visrect.top;
1979     int depth = pict_formats[format]->depth;
1980     struct gdi_image_bits dst_bits;
1981     XRenderPictureAttributes pa;
1982     XImage *image;
1983
1984     wine_tsx11_lock();
1985     image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1986                           info->bmiHeader.biWidth, height, 32, 0 );
1987     wine_tsx11_unlock();
1988     if (!image) return ERROR_OUTOFMEMORY;
1989
1990     ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1991     if (ret) return ret;
1992
1993     image->data = dst_bits.ptr;
1994
1995     *use_repeat = (width == 1 && height == 1);
1996     pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1997
1998     wine_tsx11_lock();
1999     *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2000     XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2001                src->visrect.left, 0, 0, 0, width, height );
2002     *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2003     wine_tsx11_unlock();
2004
2005     /* make coordinates relative to the pixmap */
2006     src->x -= src->visrect.left;
2007     src->y -= src->visrect.top;
2008     OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2009
2010     image->data = NULL;
2011     wine_tsx11_lock();
2012     XDestroyImage( image );
2013     wine_tsx11_unlock();
2014     if (dst_bits.free) dst_bits.free( &dst_bits );
2015     return ret;
2016 }
2017
2018 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2019                                   Drawable drawable, const struct bitblt_coords *src,
2020                                   const struct bitblt_coords *dst )
2021 {
2022     int x_dst, y_dst;
2023     Picture src_pict = 0, dst_pict, mask_pict = 0;
2024     BOOL use_repeat;
2025     double xscale, yscale;
2026
2027     use_repeat = use_source_repeat( physdev_src );
2028     if (!use_repeat)
2029     {
2030         xscale = src->width / (double)dst->width;
2031         yscale = src->height / (double)dst->height;
2032     }
2033     else xscale = yscale = 1;  /* no scaling needed with a repeating source */
2034
2035     if (drawable)  /* using an intermediate pixmap */
2036     {
2037         XRenderPictureAttributes pa;
2038
2039         x_dst = dst->x;
2040         y_dst = dst->y;
2041         pa.repeat = RepeatNone;
2042         wine_tsx11_lock();
2043         dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2044         wine_tsx11_unlock();
2045     }
2046     else
2047     {
2048         x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2049         y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2050         dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2051     }
2052
2053     src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2054
2055     /* mono -> color */
2056     if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2057     {
2058         XRenderColor fg, bg;
2059
2060         get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
2061         get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
2062         fg.alpha = bg.alpha = 0;
2063
2064         xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2065                            physdev_src->x11dev->dc_rect.left + src->x,
2066                            physdev_src->x11dev->dc_rect.top + src->y,
2067                            src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2068     }
2069     else /* color -> color (can be at different depths) or mono -> mono */
2070     {
2071         if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
2072             mask_pict = get_no_alpha_mask();
2073
2074         xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2075                       physdev_src->x11dev->dc_rect.left + src->x,
2076                       physdev_src->x11dev->dc_rect.top + src->y,
2077                       src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2078     }
2079
2080     if (drawable)
2081     {
2082         wine_tsx11_lock();
2083         pXRenderFreePicture( gdi_display, dst_pict );
2084         wine_tsx11_unlock();
2085     }
2086 }
2087
2088
2089 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2090                                XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2091                                Drawable drawable, struct bitblt_coords *src,
2092                                struct bitblt_coords *dst, BOOL use_repeat )
2093 {
2094     int x_dst, y_dst;
2095     Picture dst_pict;
2096     XRenderPictureAttributes pa;
2097     double xscale, yscale;
2098
2099     if (drawable)  /* using an intermediate pixmap */
2100     {
2101         RGNDATA *clip_data = NULL;
2102
2103         if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2104         x_dst = dst->x;
2105         y_dst = dst->y;
2106         pa.repeat = RepeatNone;
2107         wine_tsx11_lock();
2108         dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2109         if (clip_data)
2110             pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2111                                               (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2112         wine_tsx11_unlock();
2113         HeapFree( GetProcessHeap(), 0, clip_data );
2114     }
2115     else
2116     {
2117         x_dst = physdev->x11dev->dc_rect.left + dst->x;
2118         y_dst = physdev->x11dev->dc_rect.top + dst->y;
2119         dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2120     }
2121
2122     if (!use_repeat)
2123     {
2124         xscale = src->width / (double)dst->width;
2125         yscale = src->height / (double)dst->height;
2126     }
2127     else xscale = yscale = 1;  /* no scaling needed with a repeating source */
2128
2129     xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
2130                   x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2131
2132     if (drawable)
2133     {
2134         wine_tsx11_lock();
2135         pXRenderFreePicture( gdi_display, dst_pict );
2136         wine_tsx11_unlock();
2137     }
2138 }
2139
2140
2141 /***********************************************************************
2142  *           xrenderdrv_StretchBlt
2143  */
2144 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2145                                    PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2146 {
2147     struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2148     struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2149     BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2150
2151     if (src_dev->funcs != dst_dev->funcs)
2152     {
2153         dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2154         return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2155     }
2156
2157     /* XRender is of no use for color -> mono */
2158     if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2159         goto x11drv_fallback;
2160
2161     /* if not stretching, we only need to handle format conversion */
2162     if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2163
2164     if (rop != SRCCOPY)
2165     {
2166         GC tmpGC;
2167         Pixmap tmp_pixmap;
2168         struct bitblt_coords tmp;
2169
2170         /* make coordinates relative to tmp pixmap */
2171         tmp = *dst;
2172         tmp.x -= tmp.visrect.left;
2173         tmp.y -= tmp.visrect.top;
2174         OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2175
2176         wine_tsx11_lock();
2177         tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2178         XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2179         XSetGraphicsExposures( gdi_display, tmpGC, False );
2180         tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2181                                     tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
2182         wine_tsx11_unlock();
2183
2184         xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2185         execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2186
2187         wine_tsx11_lock();
2188         XFreePixmap( gdi_display, tmp_pixmap );
2189         XFreeGC( gdi_display, tmpGC );
2190         wine_tsx11_unlock();
2191     }
2192     else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2193
2194     return TRUE;
2195
2196 x11drv_fallback:
2197     return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2198 }
2199
2200
2201 /***********************************************************************
2202  *           xrenderdrv_PutImage
2203  */
2204 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2205                                   const struct gdi_image_bits *bits, struct bitblt_coords *src,
2206                                   struct bitblt_coords *dst, DWORD rop )
2207 {
2208     struct xrender_physdev *physdev;
2209     X_PHYSBITMAP *bitmap;
2210     DWORD ret;
2211     Pixmap tmp_pixmap;
2212     GC gc;
2213     enum wxr_format src_format, dst_format;
2214     XRenderPictFormat *pict_format;
2215     Pixmap src_pixmap;
2216     Picture src_pict, mask_pict = 0;
2217     BOOL use_repeat;
2218
2219     if (hbitmap)
2220     {
2221         if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2222         physdev = NULL;
2223         dst_format = bitmap->format;
2224     }
2225     else
2226     {
2227         physdev = get_xrender_dev( dev );
2228         bitmap = NULL;
2229         dst_format = physdev->format;
2230     }
2231
2232     src_format = get_xrender_format_from_bitmapinfo( info );
2233     if (!(pict_format = pict_formats[src_format])) goto update_format;
2234
2235     /* make sure we can create an image with the same bpp */
2236     if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2237         goto update_format;
2238
2239     /* mono <-> color conversions not supported */
2240     if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2241         goto x11drv_fallback;
2242
2243     if (!bits) return ERROR_SUCCESS;  /* just querying the format */
2244
2245     if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2246
2247     ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2248     if (!ret)
2249     {
2250         struct bitblt_coords tmp;
2251
2252         if (bitmap)
2253         {
2254             HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2255             if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2256
2257             xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2258                                pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2259             DeleteObject( rgn );
2260         }
2261         else
2262         {
2263             if (rop != SRCCOPY)
2264             {
2265                 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2266
2267                 /* make coordinates relative to tmp pixmap */
2268                 tmp = *dst;
2269                 tmp.x -= tmp.visrect.left;
2270                 tmp.y -= tmp.visrect.top;
2271                 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2272
2273                 wine_tsx11_lock();
2274                 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2275                 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2276                 XSetGraphicsExposures( gdi_display, gc, False );
2277                 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2278                                             tmp.visrect.right - tmp.visrect.left,
2279                                             tmp.visrect.bottom - tmp.visrect.top,
2280                                             physdev->pict_format->depth );
2281                 wine_tsx11_unlock();
2282
2283                 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2284                                    NULL, tmp_pixmap, src, &tmp, use_repeat );
2285                 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2286
2287                 wine_tsx11_lock();
2288                 XFreePixmap( gdi_display, tmp_pixmap );
2289                 XFreeGC( gdi_display, gc );
2290                 wine_tsx11_unlock();
2291
2292                 if (restore_region) restore_clipping_region( physdev->x11dev );
2293             }
2294             else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2295                                     physdev->pict_format, physdev, 0, src, dst, use_repeat );
2296         }
2297
2298         wine_tsx11_lock();
2299         pXRenderFreePicture( gdi_display, src_pict );
2300         XFreePixmap( gdi_display, src_pixmap );
2301         wine_tsx11_unlock();
2302     }
2303     return ret;
2304
2305 update_format:
2306     if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2307     set_color_info( pict_formats[dst_format], info );
2308     return ERROR_BAD_FORMAT;
2309
2310 x11drv_fallback:
2311     if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2312     dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2313     return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2314 }
2315
2316
2317 /***********************************************************************
2318  *           xrenderdrv_BlendImage
2319  */
2320 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2321                                     struct bitblt_coords *src, struct bitblt_coords *dst,
2322                                     BLENDFUNCTION func )
2323 {
2324     struct xrender_physdev *physdev = get_xrender_dev( dev );
2325     DWORD ret;
2326     enum wxr_format format;
2327     XRenderPictFormat *pict_format;
2328     Picture dst_pict, src_pict, mask_pict;
2329     Pixmap src_pixmap;
2330     BOOL use_repeat;
2331
2332     format = get_xrender_format_from_bitmapinfo( info );
2333     if (!(func.AlphaFormat & AC_SRC_ALPHA))
2334         format = get_format_without_alpha( format );
2335     else if (format != WXR_FORMAT_A8R8G8B8)
2336         return ERROR_INVALID_PARAMETER;
2337
2338     if (!(pict_format = pict_formats[format])) goto update_format;
2339
2340     /* make sure we can create an image with the same bpp */
2341     if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2342         goto update_format;
2343
2344     if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2345         goto update_format;
2346
2347     if (!bits) return ERROR_SUCCESS;  /* just querying the format */
2348
2349     ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2350     if (!ret)
2351     {
2352         double xscale, yscale;
2353
2354         if (!use_repeat)
2355         {
2356             xscale = src->width / (double)dst->width;
2357             yscale = src->height / (double)dst->height;
2358         }
2359         else xscale = yscale = 1;  /* no scaling needed with a repeating source */
2360
2361         dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2362
2363         EnterCriticalSection( &xrender_cs );
2364         mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2365
2366         xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2367                       src->x, src->y, src->width, src->height,
2368                       physdev->x11dev->dc_rect.left + dst->x,
2369                       physdev->x11dev->dc_rect.top + dst->y,
2370                       dst->width, dst->height, xscale, yscale );
2371
2372         wine_tsx11_lock();
2373         pXRenderFreePicture( gdi_display, src_pict );
2374         XFreePixmap( gdi_display, src_pixmap );
2375         wine_tsx11_unlock();
2376
2377         LeaveCriticalSection( &xrender_cs );
2378     }
2379     return ret;
2380
2381 update_format:
2382     if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2383     set_color_info( physdev->pict_format, info );
2384     return ERROR_BAD_FORMAT;
2385 }
2386
2387
2388 /***********************************************************************
2389  *           xrenderdrv_AlphaBlend
2390  */
2391 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2392                                    PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2393 {
2394     struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2395     struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2396     Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2397     XRenderPictureAttributes pa;
2398     Pixmap tmp_pixmap = 0;
2399     double xscale, yscale;
2400     BOOL use_repeat;
2401
2402     if (src_dev->funcs != dst_dev->funcs)
2403     {
2404         dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2405         return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2406     }
2407
2408     if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2409     {
2410         SetLastError( ERROR_INVALID_PARAMETER );
2411         return FALSE;
2412     }
2413
2414     dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2415
2416     use_repeat = use_source_repeat( physdev_src );
2417     if (!use_repeat)
2418     {
2419         xscale = src->width / (double)dst->width;
2420         yscale = src->height / (double)dst->height;
2421     }
2422     else xscale = yscale = 1;  /* no scaling needed with a repeating source */
2423
2424     src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2425
2426     if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2427     {
2428         /* mono -> color blending needs an intermediate color pixmap */
2429         XRenderColor fg, bg;
2430         int width = src->visrect.right - src->visrect.left;
2431         int height = src->visrect.bottom - src->visrect.top;
2432
2433         /* blending doesn't use the destination DC colors */
2434         fg.red = fg.green = fg.blue = 0;
2435         bg.red = bg.green = bg.blue = 0xffff;
2436         fg.alpha = bg.alpha = 0xffff;
2437
2438         wine_tsx11_lock();
2439         tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2440                                     physdev_dst->pict_format->depth );
2441         pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2442         tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2443                                           CPRepeat, &pa );
2444         wine_tsx11_unlock();
2445
2446         xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2447                            src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
2448     }
2449     else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2450     {
2451         /* we need a source picture with no alpha */
2452         enum wxr_format format = get_format_without_alpha( physdev_src->format );
2453         if (format != physdev_src->format)
2454         {
2455             wine_tsx11_lock();
2456             pa.subwindow_mode = IncludeInferiors;
2457             pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2458             tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2459                                               pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2460             wine_tsx11_unlock();
2461         }
2462     }
2463
2464     if (tmp_pict) src_pict = tmp_pict;
2465
2466     EnterCriticalSection( &xrender_cs );
2467     mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2468
2469     xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2470                   physdev_src->x11dev->dc_rect.left + src->x,
2471                   physdev_src->x11dev->dc_rect.top + src->y,
2472                   src->width, src->height,
2473                   physdev_dst->x11dev->dc_rect.left + dst->x,
2474                   physdev_dst->x11dev->dc_rect.top + dst->y,
2475                   dst->width, dst->height, xscale, yscale );
2476
2477     wine_tsx11_lock();
2478     if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2479     if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2480     wine_tsx11_unlock();
2481
2482     LeaveCriticalSection( &xrender_cs );
2483     return TRUE;
2484 }
2485
2486 /***********************************************************************
2487  *           xrenderdrv_GradientFill
2488  */
2489 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2490                                      void * grad_array, ULONG ngrad, ULONG mode )
2491 {
2492 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2493     static const XFixed stops[2] = { 0, 1 << 16 };
2494     struct xrender_physdev *physdev = get_xrender_dev( dev );
2495     XLinearGradient gradient;
2496     XRenderColor colors[2];
2497     Picture src_pict, dst_pict;
2498     unsigned int i;
2499     const GRADIENT_RECT *rect = grad_array;
2500     POINT pt[2];
2501
2502     if (!pXRenderCreateLinearGradient) goto fallback;
2503
2504     /* <= 16-bpp uses dithering */
2505     if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2506
2507     switch (mode)
2508     {
2509     case GRADIENT_FILL_RECT_H:
2510     case GRADIENT_FILL_RECT_V:
2511         for (i = 0; i < ngrad; i++, rect++)
2512         {
2513             const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2514             const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2515
2516             colors[0].red   = v1->Red * 257 / 256;
2517             colors[0].green = v1->Green * 257 / 256;
2518             colors[0].blue  = v1->Blue * 257 / 256;
2519             colors[1].red   = v2->Red * 257 / 256;
2520             colors[1].green = v2->Green * 257 / 256;
2521             colors[1].blue  = v2->Blue * 257 / 256;
2522             /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2523             colors[0].alpha = colors[1].alpha = 65535;
2524
2525             pt[0].x = v1->x;
2526             pt[0].y = v1->y;
2527             pt[1].x = v2->x;
2528             pt[1].y = v2->y;
2529             LPtoDP( dev->hdc, pt, 2 );
2530             if (mode == GRADIENT_FILL_RECT_H)
2531             {
2532                 gradient.p1.y = gradient.p2.y = 0;
2533                 if (pt[1].x > pt[0].x)
2534                 {
2535                     gradient.p1.x = 0;
2536                     gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2537                 }
2538                 else
2539                 {
2540                     gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2541                     gradient.p2.x = 0;
2542                 }
2543             }
2544             else
2545             {
2546                 gradient.p1.x = gradient.p2.x = 0;
2547                 if (pt[1].y > pt[0].y)
2548                 {
2549                     gradient.p1.y = 0;
2550                     gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2551                 }
2552                 else
2553                 {
2554                     gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2555                     gradient.p2.y = 0;
2556                 }
2557             }
2558
2559             TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2560                    mode, pt[0].x, pt[0].y, pt[1].x, pt[1].y,
2561                    colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2562                    colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2563
2564             dst_pict = get_xrender_picture( physdev, 0, NULL );
2565
2566             wine_tsx11_lock();
2567             src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2568             xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2569                           0, 0, abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y),
2570                           physdev->x11dev->dc_rect.left + min( pt[0].x, pt[1].x ),
2571                           physdev->x11dev->dc_rect.top + min( pt[0].y, pt[1].y ),
2572                           abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y), 1, 1 );
2573             pXRenderFreePicture( gdi_display, src_pict );
2574             wine_tsx11_unlock();
2575         }
2576         return TRUE;
2577     }
2578
2579 fallback:
2580 #endif
2581     dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2582     return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2583 }
2584
2585 /***********************************************************************
2586  *           xrenderdrv_SelectBrush
2587  */
2588 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2589 {
2590     struct xrender_physdev *physdev = get_xrender_dev( dev );
2591     X_PHYSBITMAP *physbitmap;
2592     BOOL delete_bitmap = FALSE;
2593     BITMAP bm;
2594     HBITMAP bitmap;
2595     Pixmap pixmap;
2596     XRenderPictFormat *pict_format;
2597     Picture src_pict, dst_pict;
2598     XRenderPictureAttributes pa;
2599
2600     if (!pattern) goto x11drv_fallback;
2601     if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2602
2603     bitmap = pattern->bitmap;
2604     if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2605     {
2606         if (!(bitmap = create_brush_bitmap( physdev->x11dev, pattern ))) return 0;
2607         physbitmap = X11DRV_get_phys_bitmap( bitmap );
2608         delete_bitmap = TRUE;
2609     }
2610
2611     if (physbitmap->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2612     if (!(pict_format = pict_formats[physbitmap->format])) goto x11drv_fallback;
2613
2614     GetObjectW( bitmap, sizeof(bm), &bm );
2615
2616     wine_tsx11_lock();
2617     pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2618                             physdev->pict_format->depth );
2619
2620     pa.repeat = RepeatNone;
2621     src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_format, CPRepeat, &pa);
2622     dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2623
2624     xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, bm.bmWidth, bm.bmHeight,
2625                   0, 0, bm.bmWidth, bm.bmHeight, 1.0, 1.0 );
2626     pXRenderFreePicture( gdi_display, src_pict );
2627     pXRenderFreePicture( gdi_display, dst_pict );
2628
2629     if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2630     physdev->x11dev->brush.pixmap = pixmap;
2631     physdev->x11dev->brush.fillStyle = FillTiled;
2632     physdev->x11dev->brush.pixel = 0;  /* ignored */
2633     physdev->x11dev->brush.style = BS_PATTERN;
2634     wine_tsx11_unlock();
2635
2636     if (delete_bitmap) DeleteObject( bitmap );
2637     return hbrush;
2638
2639 x11drv_fallback:
2640     if (delete_bitmap) DeleteObject( bitmap );
2641     dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2642     return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2643 }
2644
2645
2646 static const struct gdi_dc_funcs xrender_funcs =
2647 {
2648     NULL,                               /* pAbortDoc */
2649     NULL,                               /* pAbortPath */
2650     xrenderdrv_AlphaBlend,              /* pAlphaBlend */
2651     NULL,                               /* pAngleArc */
2652     NULL,                               /* pArc */
2653     NULL,                               /* pArcTo */
2654     NULL,                               /* pBeginPath */
2655     xrenderdrv_BlendImage,              /* pBlendImage */
2656     NULL,                               /* pChoosePixelFormat */
2657     NULL,                               /* pChord */
2658     NULL,                               /* pCloseFigure */
2659     xrenderdrv_CopyBitmap,              /* pCopyBitmap */
2660     xrenderdrv_CreateBitmap,            /* pCreateBitmap */
2661     xrenderdrv_CreateCompatibleDC,      /* pCreateCompatibleDC */
2662     xrenderdrv_CreateDC,                /* pCreateDC */
2663     xrenderdrv_DeleteBitmap,            /* pDeleteBitmap */
2664     xrenderdrv_DeleteDC,                /* pDeleteDC */
2665     NULL,                               /* pDeleteObject */
2666     NULL,                               /* pDescribePixelFormat */
2667     NULL,                               /* pDeviceCapabilities */
2668     NULL,                               /* pEllipse */
2669     NULL,                               /* pEndDoc */
2670     NULL,                               /* pEndPage */
2671     NULL,                               /* pEndPath */
2672     NULL,                               /* pEnumFonts */
2673     NULL,                               /* pEnumICMProfiles */
2674     NULL,                               /* pExcludeClipRect */
2675     NULL,                               /* pExtDeviceMode */
2676     xrenderdrv_ExtEscape,               /* pExtEscape */
2677     NULL,                               /* pExtFloodFill */
2678     NULL,                               /* pExtSelectClipRgn */
2679     xrenderdrv_ExtTextOut,              /* pExtTextOut */
2680     NULL,                               /* pFillPath */
2681     NULL,                               /* pFillRgn */
2682     NULL,                               /* pFlattenPath */
2683     NULL,                               /* pFontIsLinked */
2684     NULL,                               /* pFrameRgn */
2685     NULL,                               /* pGdiComment */
2686     NULL,                               /* pGdiRealizationInfo */
2687     NULL,                               /* pGetCharABCWidths */
2688     NULL,                               /* pGetCharABCWidthsI */
2689     NULL,                               /* pGetCharWidth */
2690     NULL,                               /* pGetDeviceCaps */
2691     NULL,                               /* pGetDeviceGammaRamp */
2692     NULL,                               /* pGetFontData */
2693     NULL,                               /* pGetFontUnicodeRanges */
2694     NULL,                               /* pGetGlyphIndices */
2695     NULL,                               /* pGetGlyphOutline */
2696     NULL,                               /* pGetICMProfile */
2697     xrenderdrv_GetImage,                /* pGetImage */
2698     NULL,                               /* pGetKerningPairs */
2699     NULL,                               /* pGetNearestColor */
2700     NULL,                               /* pGetOutlineTextMetrics */
2701     NULL,                               /* pGetPixel */
2702     NULL,                               /* pGetPixelFormat */
2703     NULL,                               /* pGetSystemPaletteEntries */
2704     NULL,                               /* pGetTextCharsetInfo */
2705     NULL,                               /* pGetTextExtentExPoint */
2706     NULL,                               /* pGetTextExtentExPointI */
2707     NULL,                               /* pGetTextFace */
2708     NULL,                               /* pGetTextMetrics */
2709     xrenderdrv_GradientFill,            /* pGradientFill */
2710     NULL,                               /* pIntersectClipRect */
2711     NULL,                               /* pInvertRgn */
2712     NULL,                               /* pLineTo */
2713     NULL,                               /* pModifyWorldTransform */
2714     NULL,                               /* pMoveTo */
2715     NULL,                               /* pOffsetClipRgn */
2716     NULL,                               /* pOffsetViewportOrg */
2717     NULL,                               /* pOffsetWindowOrg */
2718     NULL,                               /* pPaintRgn */
2719     NULL,                               /* pPatBlt */
2720     NULL,                               /* pPie */
2721     NULL,                               /* pPolyBezier */
2722     NULL,                               /* pPolyBezierTo */
2723     NULL,                               /* pPolyDraw */
2724     NULL,                               /* pPolyPolygon */
2725     NULL,                               /* pPolyPolyline */
2726     NULL,                               /* pPolygon */
2727     NULL,                               /* pPolyline */
2728     NULL,                               /* pPolylineTo */
2729     xrenderdrv_PutImage,                /* pPutImage */
2730     NULL,                               /* pRealizeDefaultPalette */
2731     NULL,                               /* pRealizePalette */
2732     NULL,                               /* pRectangle */
2733     NULL,                               /* pResetDC */
2734     NULL,                               /* pRestoreDC */
2735     NULL,                               /* pRoundRect */
2736     NULL,                               /* pSaveDC */
2737     NULL,                               /* pScaleViewportExt */
2738     NULL,                               /* pScaleWindowExt */
2739     xrenderdrv_SelectBitmap,            /* pSelectBitmap */
2740     xrenderdrv_SelectBrush,             /* pSelectBrush */
2741     NULL,                               /* pSelectClipPath */
2742     xrenderdrv_SelectFont,              /* pSelectFont */
2743     NULL,                               /* pSelectPalette */
2744     NULL,                               /* pSelectPen */
2745     NULL,                               /* pSetArcDirection */
2746     NULL,                               /* pSetBkColor */
2747     NULL,                               /* pSetBkMode */
2748     NULL,                               /* pSetDCBrushColor */
2749     NULL,                               /* pSetDCPenColor */
2750     NULL,                               /* pSetDIBitsToDevice */
2751     xrenderdrv_SetDeviceClipping,       /* pSetDeviceClipping */
2752     NULL,                               /* pSetDeviceGammaRamp */
2753     NULL,                               /* pSetLayout */
2754     NULL,                               /* pSetMapMode */
2755     NULL,                               /* pSetMapperFlags */
2756     NULL,                               /* pSetPixel */
2757     NULL,                               /* pSetPixelFormat */
2758     NULL,                               /* pSetPolyFillMode */
2759     NULL,                               /* pSetROP2 */
2760     NULL,                               /* pSetRelAbs */
2761     NULL,                               /* pSetStretchBltMode */
2762     NULL,                               /* pSetTextAlign */
2763     NULL,                               /* pSetTextCharacterExtra */
2764     NULL,                               /* pSetTextColor */
2765     NULL,                               /* pSetTextJustification */
2766     NULL,                               /* pSetViewportExt */
2767     NULL,                               /* pSetViewportOrg */
2768     NULL,                               /* pSetWindowExt */
2769     NULL,                               /* pSetWindowOrg */
2770     NULL,                               /* pSetWorldTransform */
2771     NULL,                               /* pStartDoc */
2772     NULL,                               /* pStartPage */
2773     xrenderdrv_StretchBlt,              /* pStretchBlt */
2774     NULL,                               /* pStretchDIBits */
2775     NULL,                               /* pStrokeAndFillPath */
2776     NULL,                               /* pStrokePath */
2777     NULL,                               /* pSwapBuffers */
2778     NULL,                               /* pUnrealizePalette */
2779     NULL,                               /* pWidenPath */
2780     /* OpenGL not supported */
2781 };
2782
2783 #else /* SONAME_LIBXRENDER */
2784
2785 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2786 {
2787     TRACE("XRender support not compiled in.\n");
2788     return NULL;
2789 }
2790
2791 void X11DRV_XRender_Finalize(void)
2792 {
2793 }
2794
2795 #endif /* SONAME_LIBXRENDER */