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