server: Fix propagation of the pixel format flag when the parent window is changed.
[wine.git] / dlls / winex11.drv / xrender.c
blobd7f05081083d023b7141566202916fdb6f6809ab
1 /*
2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
6 * Copyright 2011 Alexandre Julliard
8 * Some parts also:
9 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
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.
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.
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
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <stdlib.h>
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"
41 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
43 #ifdef SONAME_LIBXRENDER
45 WINE_DECLARE_DEBUG_CHANNEL(winediag);
47 #include <X11/Xlib.h>
48 #include <X11/extensions/Xrender.h>
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
57 enum wxr_format
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
75 typedef struct wine_xrender_format_template
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;
88 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
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 },
105 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
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} },
122 static enum wxr_format default_format = WXR_INVALID_FORMAT;
123 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
125 typedef struct
127 LOGFONTW lf;
128 XFORM xform;
129 SIZE devsize; /* size in device coords */
130 DWORD hash;
131 } LFANDSIZE;
133 #define INITIAL_REALIZED_BUF_SIZE 128
135 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
137 typedef struct
139 GlyphSet glyphset;
140 XRenderPictFormat *font_format;
141 int nrealized;
142 BOOL *realized;
143 XGlyphInfo *gis;
144 } gsCacheEntryFormat;
146 typedef struct
148 LFANDSIZE lfsz;
149 AA_Type aa_default;
150 gsCacheEntryFormat * format[AA_MAXVALUE];
151 INT count;
152 INT next;
153 } gsCacheEntry;
155 struct xrender_physdev
157 struct gdi_physdev dev;
158 X11DRV_PDEVICE *x11dev;
159 HRGN region;
160 enum wxr_format format;
161 int cache_index;
162 BOOL update_clip;
163 Picture pict;
164 Picture pict_src;
165 XRenderPictFormat *pict_format;
168 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
170 return (struct xrender_physdev *)dev;
173 static const struct gdi_dc_funcs xrender_funcs;
175 static gsCacheEntry *glyphsetCache = NULL;
176 static DWORD glyphsetCacheSize = 0;
177 static INT lastfree = -1;
178 static INT mru = -1;
180 #define INIT_CACHE_SIZE 10
182 static int antialias = 1;
184 static void *xrender_handle;
186 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
187 MAKE_FUNCPTR(XRenderAddGlyphs)
188 MAKE_FUNCPTR(XRenderChangePicture)
189 MAKE_FUNCPTR(XRenderComposite)
190 MAKE_FUNCPTR(XRenderCompositeText16)
191 MAKE_FUNCPTR(XRenderCreateGlyphSet)
192 MAKE_FUNCPTR(XRenderCreatePicture)
193 MAKE_FUNCPTR(XRenderFillRectangle)
194 MAKE_FUNCPTR(XRenderFindFormat)
195 MAKE_FUNCPTR(XRenderFindVisualFormat)
196 MAKE_FUNCPTR(XRenderFreeGlyphSet)
197 MAKE_FUNCPTR(XRenderFreePicture)
198 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
199 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
200 MAKE_FUNCPTR(XRenderCreateLinearGradient)
201 #endif
202 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
203 MAKE_FUNCPTR(XRenderSetPictureTransform)
204 #endif
205 MAKE_FUNCPTR(XRenderQueryExtension)
207 #ifdef SONAME_LIBFONTCONFIG
208 #include <fontconfig/fontconfig.h>
209 MAKE_FUNCPTR(FcConfigSubstitute)
210 MAKE_FUNCPTR(FcDefaultSubstitute)
211 MAKE_FUNCPTR(FcFontMatch)
212 MAKE_FUNCPTR(FcInit)
213 MAKE_FUNCPTR(FcPatternCreate)
214 MAKE_FUNCPTR(FcPatternDestroy)
215 MAKE_FUNCPTR(FcPatternAddInteger)
216 MAKE_FUNCPTR(FcPatternAddString)
217 MAKE_FUNCPTR(FcPatternGetBool)
218 MAKE_FUNCPTR(FcPatternGetInteger)
219 MAKE_FUNCPTR(FcPatternGetString)
220 static void *fontconfig_handle;
221 static BOOL fontconfig_installed;
222 #endif
224 #undef MAKE_FUNCPTR
226 static CRITICAL_SECTION xrender_cs;
227 static CRITICAL_SECTION_DEBUG critsect_debug =
229 0, 0, &xrender_cs,
230 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
231 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
233 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
235 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
236 ( ( (ULONG)_x4 << 24 ) | \
237 ( (ULONG)_x3 << 16 ) | \
238 ( (ULONG)_x2 << 8 ) | \
239 (ULONG)_x1 )
241 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
243 #define GASP_GRIDFIT 0x01
244 #define GASP_DOGRAY 0x02
246 #ifdef WORDS_BIGENDIAN
247 #define get_be_word(x) (x)
248 #define NATIVE_BYTE_ORDER MSBFirst
249 #else
250 #define get_be_word(x) RtlUshortByteSwap(x)
251 #define NATIVE_BYTE_ORDER LSBFirst
252 #endif
254 static BOOL has_alpha( enum wxr_format format )
256 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
259 static enum wxr_format get_format_without_alpha( enum wxr_format format )
261 switch (format)
263 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
264 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
265 default: return format;
269 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
271 templ->id = 0;
272 templ->type = PictTypeDirect;
273 templ->depth = fmt->depth;
274 templ->direct.alpha = fmt->alpha;
275 templ->direct.alphaMask = fmt->alphaMask;
276 templ->direct.red = fmt->red;
277 templ->direct.redMask = fmt->redMask;
278 templ->direct.green = fmt->green;
279 templ->direct.greenMask = fmt->greenMask;
280 templ->direct.blue = fmt->blue;
281 templ->direct.blueMask = fmt->blueMask;
282 templ->colormap = 0;
284 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
286 return TRUE;
289 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
291 if(fmt->depth != default_visual.depth) return FALSE;
292 if( (fmt->redMask << fmt->red) != default_visual.red_mask) return FALSE;
293 if( (fmt->greenMask << fmt->green) != default_visual.green_mask) return FALSE;
294 if( (fmt->blueMask << fmt->blue) != default_visual.blue_mask) return FALSE;
296 /* We never select a default ARGB visual */
297 if(fmt->alphaMask) return FALSE;
298 return TRUE;
301 static int load_xrender_formats(void)
303 int count = 0;
304 unsigned int i;
306 for (i = 0; i < WXR_NB_FORMATS; i++)
308 XRenderPictFormat templ;
310 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
312 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, default_visual.visual);
313 if (!pict_formats[i])
315 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
316 if (default_visual.class == DirectColor)
318 XVisualInfo info;
319 if (XMatchVisualInfo( gdi_display, default_visual.screen,
320 default_visual.depth, TrueColor, &info ))
322 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
323 if (pict_formats[i]) default_visual = info;
327 if (pict_formats[i]) default_format = i;
329 else
331 unsigned long mask = 0;
332 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
333 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
335 if (pict_formats[i])
337 count++;
338 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
341 return count;
344 /***********************************************************************
345 * X11DRV_XRender_Init
347 * Let's see if our XServer has the extension available
350 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
352 int event_base, i;
354 if (!client_side_with_render) return NULL;
355 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
357 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
358 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
359 LOAD_FUNCPTR(XRenderAddGlyphs);
360 LOAD_FUNCPTR(XRenderChangePicture);
361 LOAD_FUNCPTR(XRenderComposite);
362 LOAD_FUNCPTR(XRenderCompositeText16);
363 LOAD_FUNCPTR(XRenderCreateGlyphSet);
364 LOAD_FUNCPTR(XRenderCreatePicture);
365 LOAD_FUNCPTR(XRenderFillRectangle);
366 LOAD_FUNCPTR(XRenderFindFormat);
367 LOAD_FUNCPTR(XRenderFindVisualFormat);
368 LOAD_FUNCPTR(XRenderFreeGlyphSet);
369 LOAD_FUNCPTR(XRenderFreePicture);
370 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
371 LOAD_FUNCPTR(XRenderQueryExtension);
372 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
373 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
374 #endif
375 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
376 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
377 #endif
378 #undef LOAD_OPTIONAL_FUNCPTR
379 #undef LOAD_FUNCPTR
381 if (!pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) return NULL;
383 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
384 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
386 ERR_(winediag)("Wine has detected that you probably have a buggy version "
387 "of libXrender. Because of this client side font rendering "
388 "will be disabled. Please upgrade this library.\n");
389 return NULL;
392 if (!default_visual.red_mask || !default_visual.green_mask || !default_visual.blue_mask)
394 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
395 return NULL;
398 #ifdef SONAME_LIBFONTCONFIG
399 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
401 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fontconfig_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
402 LOAD_FUNCPTR(FcConfigSubstitute);
403 LOAD_FUNCPTR(FcDefaultSubstitute);
404 LOAD_FUNCPTR(FcFontMatch);
405 LOAD_FUNCPTR(FcInit);
406 LOAD_FUNCPTR(FcPatternCreate);
407 LOAD_FUNCPTR(FcPatternDestroy);
408 LOAD_FUNCPTR(FcPatternAddInteger);
409 LOAD_FUNCPTR(FcPatternAddString);
410 LOAD_FUNCPTR(FcPatternGetBool);
411 LOAD_FUNCPTR(FcPatternGetInteger);
412 LOAD_FUNCPTR(FcPatternGetString);
413 #undef LOAD_FUNCPTR
414 fontconfig_installed = pFcInit();
416 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
418 sym_not_found:
419 #endif
421 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
422 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
424 glyphsetCacheSize = INIT_CACHE_SIZE;
425 lastfree = 0;
426 for(i = 0; i < INIT_CACHE_SIZE; i++) {
427 glyphsetCache[i].next = i + 1;
428 glyphsetCache[i].count = -1;
430 glyphsetCache[i-1].next = -1;
432 if(default_visual.depth <= 8 || !client_side_antialias_with_render) antialias = 0;
434 return &xrender_funcs;
437 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
438 static void get_xrender_color( struct xrender_physdev *physdev, COLORREF src_color, XRenderColor *dst_color )
440 if (src_color & (1 << 24)) /* PALETTEINDEX */
442 HPALETTE pal = GetCurrentObject( physdev->dev.hdc, OBJ_PAL );
443 PALETTEENTRY pal_ent;
445 if (!GetPaletteEntries( pal, LOWORD(src_color), 1, &pal_ent ))
446 GetPaletteEntries( pal, 0, 1, &pal_ent );
447 dst_color->red = pal_ent.peRed * 257;
448 dst_color->green = pal_ent.peGreen * 257;
449 dst_color->blue = pal_ent.peBlue * 257;
451 else
453 if (src_color >> 16 == 0x10ff) src_color = 0; /* DIBINDEX */
455 dst_color->red = GetRValue( src_color ) * 257;
456 dst_color->green = GetGValue( src_color ) * 257;
457 dst_color->blue = GetBValue( src_color ) * 257;
460 if (physdev->format == WXR_FORMAT_MONO && !dst_color->red && !dst_color->green && !dst_color->blue)
461 dst_color->alpha = 0;
462 else
463 dst_color->alpha = 0xffff;
466 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
468 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
470 switch (info->bmiHeader.biBitCount)
472 case 1:
473 return WXR_FORMAT_MONO;
474 case 4:
475 case 8:
476 break;
477 case 24:
478 if (info->bmiHeader.biCompression != BI_RGB) break;
479 return WXR_FORMAT_R8G8B8;
480 case 16:
481 case 32:
482 if (info->bmiHeader.biCompression == BI_BITFIELDS)
484 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
485 unsigned int i;
487 for (i = 0; i < WXR_NB_FORMATS; i++)
489 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
490 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
491 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
492 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
493 return i;
495 break;
497 if (info->bmiHeader.biCompression != BI_RGB) break;
498 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
500 return WXR_INVALID_FORMAT;
503 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
504 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
506 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
507 XTransform xform = {{
508 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
509 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
510 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
513 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
514 #endif
517 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
519 XRenderPictureAttributes pa;
520 RGNDATA *data;
522 if (!rgn)
524 pa.clip_mask = None;
525 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
527 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
529 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
530 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
531 (XRectangle *)data->Buffer, data->rdh.nCount );
532 HeapFree( GetProcessHeap(), 0, data );
537 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
539 if (!dev->pict && dev->pict_format)
541 XRenderPictureAttributes pa;
543 pa.subwindow_mode = IncludeInferiors;
544 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
545 dev->pict_format, CPSubwindowMode, &pa );
546 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
547 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
548 dev->update_clip = (dev->region != 0);
551 if (clip_rect)
553 HRGN rgn = CreateRectRgnIndirect( clip_rect );
554 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
555 if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
556 update_xrender_clipping( dev, rgn );
557 DeleteObject( rgn );
559 else if (clip_rgn)
561 if (dev->region)
563 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
564 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
565 update_xrender_clipping( dev, rgn );
566 DeleteObject( rgn );
568 else update_xrender_clipping( dev, clip_rgn );
570 else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
572 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
573 return dev->pict;
576 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
578 if (!dev->pict_src && dev->pict_format)
580 XRenderPictureAttributes pa;
582 pa.subwindow_mode = IncludeInferiors;
583 pa.repeat = repeat ? RepeatNormal : RepeatNone;
584 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
585 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
587 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
588 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
591 return dev->pict_src;
594 static void free_xrender_picture( struct xrender_physdev *dev )
596 if (dev->pict || dev->pict_src)
598 XFlush( gdi_display );
599 if (dev->pict)
601 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
602 pXRenderFreePicture(gdi_display, dev->pict);
603 dev->pict = 0;
605 if(dev->pict_src)
607 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
608 pXRenderFreePicture(gdi_display, dev->pict_src);
609 dev->pict_src = 0;
614 /* return a mask picture used to force alpha to 0 */
615 static Picture get_no_alpha_mask(void)
617 static Pixmap pixmap;
618 static Picture pict;
620 EnterCriticalSection( &xrender_cs );
621 if (!pict)
623 XRenderPictureAttributes pa;
624 XRenderColor col;
626 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
627 pa.repeat = RepeatNormal;
628 pa.component_alpha = True;
629 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
630 CPRepeat|CPComponentAlpha, &pa );
631 col.red = col.green = col.blue = 0xffff;
632 col.alpha = 0;
633 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
635 LeaveCriticalSection( &xrender_cs );
636 return pict;
639 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
641 if(p1->hash != p2->hash) return TRUE;
642 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
643 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
644 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
645 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
648 #if 0
649 static void walk_cache(void)
651 int i;
653 EnterCriticalSection(&xrender_cs);
654 for(i=mru; i >= 0; i = glyphsetCache[i].next)
655 TRACE("item %d\n", i);
656 LeaveCriticalSection(&xrender_cs);
658 #endif
660 static int LookupEntry(LFANDSIZE *plfsz)
662 int i, prev_i = -1;
664 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
665 TRACE("%d\n", i);
666 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
668 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
669 glyphsetCache[i].count++;
670 if(prev_i >= 0) {
671 glyphsetCache[prev_i].next = glyphsetCache[i].next;
672 glyphsetCache[i].next = mru;
673 mru = i;
675 TRACE("found font in cache %d\n", i);
676 return i;
678 prev_i = i;
680 TRACE("font not in cache\n");
681 return -1;
684 static void FreeEntry(int entry)
686 int format;
688 for(format = 0; format < AA_MAXVALUE; format++) {
689 gsCacheEntryFormat * formatEntry;
691 if( !glyphsetCache[entry].format[format] )
692 continue;
694 formatEntry = glyphsetCache[entry].format[format];
696 if(formatEntry->glyphset) {
697 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
698 formatEntry->glyphset = 0;
700 if(formatEntry->nrealized) {
701 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
702 formatEntry->realized = NULL;
703 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
704 formatEntry->gis = NULL;
705 formatEntry->nrealized = 0;
708 HeapFree(GetProcessHeap(), 0, formatEntry);
709 glyphsetCache[entry].format[format] = NULL;
713 static int AllocEntry(void)
715 int best = -1, prev_best = -1, i, prev_i = -1;
717 if(lastfree >= 0) {
718 assert(glyphsetCache[lastfree].count == -1);
719 glyphsetCache[lastfree].count = 1;
720 best = lastfree;
721 lastfree = glyphsetCache[lastfree].next;
722 assert(best != mru);
723 glyphsetCache[best].next = mru;
724 mru = best;
726 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
727 return mru;
730 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
731 if(glyphsetCache[i].count == 0) {
732 best = i;
733 prev_best = prev_i;
735 prev_i = i;
738 if(best >= 0) {
739 TRACE("freeing unused glyphset at cache %d\n", best);
740 FreeEntry(best);
741 glyphsetCache[best].count = 1;
742 if(prev_best >= 0) {
743 glyphsetCache[prev_best].next = glyphsetCache[best].next;
744 glyphsetCache[best].next = mru;
745 mru = best;
746 } else {
747 assert(mru == best);
749 return mru;
752 TRACE("Growing cache\n");
754 if (glyphsetCache)
755 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
756 glyphsetCache,
757 (glyphsetCacheSize + INIT_CACHE_SIZE)
758 * sizeof(*glyphsetCache));
759 else
760 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
761 (glyphsetCacheSize + INIT_CACHE_SIZE)
762 * sizeof(*glyphsetCache));
764 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
765 i++) {
766 glyphsetCache[i].next = i + 1;
767 glyphsetCache[i].count = -1;
769 glyphsetCache[i-1].next = -1;
770 glyphsetCacheSize += INIT_CACHE_SIZE;
772 lastfree = glyphsetCache[best].next;
773 glyphsetCache[best].count = 1;
774 glyphsetCache[best].next = mru;
775 mru = best;
776 TRACE("new free cache slot at %d\n", mru);
777 return mru;
780 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
782 DWORD size;
783 WORD *gasp, *buffer;
784 WORD num_recs;
785 DWORD ppem;
786 TEXTMETRICW tm;
788 *flags = 0;
790 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
791 if(size == GDI_ERROR)
792 return FALSE;
794 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
795 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
797 GetTextMetricsW(hdc, &tm);
798 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
800 gasp++;
801 num_recs = get_be_word(*gasp);
802 gasp++;
803 while(num_recs--)
805 *flags = get_be_word(*(gasp + 1));
806 if(ppem <= get_be_word(*gasp))
807 break;
808 gasp += 2;
810 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
812 HeapFree(GetProcessHeap(), 0, buffer);
813 return TRUE;
816 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
818 AA_Type ret;
819 WORD flags;
820 UINT font_smoothing_type, font_smoothing_orientation;
822 if (subpixel &&
823 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
824 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
826 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
827 &font_smoothing_orientation, 0) &&
828 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
830 ret = AA_BGR;
832 else
833 ret = AA_RGB;
834 /*FIXME
835 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
836 But, Wine's subpixel rendering can support the portrait mode.
839 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
840 ret = AA_Grey;
841 else
842 ret = AA_None;
844 return ret;
847 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
849 int ret;
850 int format;
851 gsCacheEntry *entry;
852 static int hinter = -1;
853 static int subpixel = -1;
854 BOOL font_smoothing;
856 if((ret = LookupEntry(plfsz)) != -1) return ret;
858 ret = AllocEntry();
859 entry = glyphsetCache + ret;
860 entry->lfsz = *plfsz;
861 for( format = 0; format < AA_MAXVALUE; format++ ) {
862 assert( !entry->format[format] );
865 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
867 if(hinter == -1 || subpixel == -1)
869 RASTERIZER_STATUS status;
870 GetRasterizerCaps(&status, sizeof(status));
871 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
872 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
875 switch (plfsz->lf.lfQuality)
877 case ANTIALIASED_QUALITY:
878 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
879 return ret; /* ignore further configuration */
880 case CLEARTYPE_QUALITY:
881 case CLEARTYPE_NATURAL_QUALITY:
882 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
883 break;
884 case DEFAULT_QUALITY:
885 case DRAFT_QUALITY:
886 case PROOF_QUALITY:
887 default:
888 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
889 font_smoothing)
891 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
893 else
894 entry->aa_default = AA_None;
895 break;
898 font_smoothing = TRUE; /* default to enabled */
899 #ifdef SONAME_LIBFONTCONFIG
900 if (fontconfig_installed)
902 FcPattern *match, *pattern;
903 FcResult result;
904 char family[LF_FACESIZE * 4];
906 #if defined(__i386__) && defined(__GNUC__)
907 /* fontconfig generates floating point exceptions, mask them */
908 WORD cw, default_cw = 0x37f;
909 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
910 #endif
912 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
913 pattern = pFcPatternCreate();
914 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
915 if (plfsz->lf.lfWeight != FW_DONTCARE)
917 int weight;
918 switch (plfsz->lf.lfWeight)
920 case FW_THIN: weight = FC_WEIGHT_THIN; break;
921 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
922 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
923 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
924 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
925 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
926 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
927 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
928 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
929 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
931 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
933 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
934 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
935 pFcDefaultSubstitute( pattern );
936 if ((match = pFcFontMatch( NULL, pattern, &result )))
938 int rgba;
939 FcBool antialias;
941 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
942 antialias = TRUE;
943 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
945 FcChar8 *file;
946 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
948 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
949 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
951 switch (rgba)
953 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
954 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
955 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
956 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
957 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
960 if (!antialias) font_smoothing = FALSE;
961 pFcPatternDestroy( match );
963 pFcPatternDestroy( pattern );
965 #if defined(__i386__) && defined(__GNUC__)
966 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
967 #endif
969 #endif /* SONAME_LIBFONTCONFIG */
971 /* now check Xft resources */
973 char *value;
974 BOOL antialias = TRUE;
976 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
978 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
979 value[0] == '0' || !strcasecmp( value, "off" ))
980 antialias = FALSE;
982 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
984 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
985 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
986 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
987 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
988 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
989 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
991 if (!antialias) font_smoothing = FALSE;
994 if (!font_smoothing) entry->aa_default = AA_None;
996 else
997 entry->aa_default = AA_None;
999 return ret;
1002 static void dec_ref_cache(int index)
1004 assert(index >= 0);
1005 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1006 assert(glyphsetCache[index].count > 0);
1007 glyphsetCache[index].count--;
1010 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1012 DWORD hash = 0, *ptr, two_chars;
1013 WORD *pwc;
1014 int i;
1016 hash ^= plfsz->devsize.cx;
1017 hash ^= plfsz->devsize.cy;
1018 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1019 hash ^= *ptr;
1020 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1021 hash ^= *ptr;
1022 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1023 two_chars = *ptr;
1024 pwc = (WCHAR *)&two_chars;
1025 if(!*pwc) break;
1026 *pwc = toupperW(*pwc);
1027 pwc++;
1028 *pwc = toupperW(*pwc);
1029 hash ^= two_chars;
1030 if(!*pwc) break;
1032 plfsz->hash = hash;
1033 return;
1036 /**********************************************************************
1037 * xrenderdrv_SelectFont
1039 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1041 LFANDSIZE lfsz;
1042 struct xrender_physdev *physdev = get_xrender_dev( dev );
1043 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1044 HFONT ret = next->funcs->pSelectFont( next, hfont );
1046 if (!ret) return 0;
1048 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1050 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1051 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1052 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1053 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1054 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1055 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1057 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1058 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1059 lfsz.xform.eM21, lfsz.xform.eM22);
1061 if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE && lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
1062 lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
1064 /* Not used fields, would break hashing */
1065 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1067 lfsz_calc_hash(&lfsz);
1069 EnterCriticalSection(&xrender_cs);
1070 if (physdev->cache_index != -1)
1071 dec_ref_cache( physdev->cache_index );
1072 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1073 LeaveCriticalSection(&xrender_cs);
1074 return ret;
1077 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1079 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1080 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1082 if (!physdev) return FALSE;
1083 physdev->x11dev = x11dev;
1084 physdev->cache_index = -1;
1085 physdev->format = format;
1086 physdev->pict_format = pict_formats[format];
1087 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1088 return TRUE;
1091 /* store the color mask data in the bitmap info structure */
1092 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1094 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1096 info->bmiHeader.biPlanes = 1;
1097 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1098 info->bmiHeader.biCompression = BI_RGB;
1099 info->bmiHeader.biClrUsed = 0;
1101 switch (info->bmiHeader.biBitCount)
1103 case 16:
1104 colors[0] = format->direct.redMask << format->direct.red;
1105 colors[1] = format->direct.greenMask << format->direct.green;
1106 colors[2] = format->direct.blueMask << format->direct.blue;
1107 info->bmiHeader.biCompression = BI_BITFIELDS;
1108 break;
1109 case 32:
1110 colors[0] = format->direct.redMask << format->direct.red;
1111 colors[1] = format->direct.greenMask << format->direct.green;
1112 colors[2] = format->direct.blueMask << format->direct.blue;
1113 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1114 info->bmiHeader.biCompression = BI_BITFIELDS;
1115 break;
1120 /**********************************************************************
1121 * xrenderdrv_CreateDC
1123 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1124 LPCWSTR output, const DEVMODEW* initData )
1126 return create_xrender_dc( pdev, default_format );
1129 /**********************************************************************
1130 * xrenderdrv_CreateCompatibleDC
1132 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1134 if (orig) /* chain to x11drv first */
1136 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1137 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1139 /* otherwise we have been called by x11drv */
1141 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1144 /**********************************************************************
1145 * xrenderdrv_DeleteDC
1147 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1149 struct xrender_physdev *physdev = get_xrender_dev( dev );
1151 free_xrender_picture( physdev );
1153 EnterCriticalSection( &xrender_cs );
1154 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1155 LeaveCriticalSection( &xrender_cs );
1157 HeapFree( GetProcessHeap(), 0, physdev );
1158 return TRUE;
1161 /**********************************************************************
1162 * xrenderdrv_ExtEscape
1164 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1165 INT out_count, LPVOID out_data )
1167 struct xrender_physdev *physdev = get_xrender_dev( dev );
1169 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1171 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1173 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1175 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1176 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1177 return ret;
1180 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1183 /***********************************************************************
1184 * xrenderdrv_SetDeviceClipping
1186 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1188 struct xrender_physdev *physdev = get_xrender_dev( dev );
1190 physdev->region = rgn;
1191 physdev->update_clip = TRUE;
1193 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1194 dev->funcs->pSetDeviceClipping( dev, rgn );
1198 /************************************************************************
1199 * UploadGlyph
1201 * Helper to ExtTextOut. Must be called inside xrender_cs
1203 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1205 unsigned int buflen;
1206 char *buf;
1207 Glyph gid;
1208 GLYPHMETRICS gm;
1209 XGlyphInfo gi;
1210 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1211 gsCacheEntryFormat *formatEntry;
1212 UINT ggo_format = GGO_GLYPH_INDEX;
1213 enum wxr_format wxr_format;
1214 static const char zero[4];
1215 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1217 switch(format) {
1218 case AA_Grey:
1219 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1220 break;
1221 case AA_RGB:
1222 ggo_format |= WINE_GGO_HRGB_BITMAP;
1223 break;
1224 case AA_BGR:
1225 ggo_format |= WINE_GGO_HBGR_BITMAP;
1226 break;
1227 case AA_VRGB:
1228 ggo_format |= WINE_GGO_VRGB_BITMAP;
1229 break;
1230 case AA_VBGR:
1231 ggo_format |= WINE_GGO_VBGR_BITMAP;
1232 break;
1234 default:
1235 ERR("aa = %d - not implemented\n", format);
1236 case AA_None:
1237 ggo_format |= GGO_BITMAP;
1238 break;
1241 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1242 if(buflen == GDI_ERROR) {
1243 if(format != AA_None) {
1244 format = AA_None;
1245 entry->aa_default = AA_None;
1246 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1247 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1249 if(buflen == GDI_ERROR) {
1250 WARN("GetGlyphOutlineW failed using default glyph\n");
1251 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1252 if(buflen == GDI_ERROR) {
1253 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1254 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1255 if(buflen == GDI_ERROR) {
1256 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1257 return;
1261 TRACE("Turning off antialiasing for this monochrome font\n");
1264 /* If there is nothing for the current type, we create the entry. */
1265 if( !entry->format[format] ) {
1266 entry->format[format] = HeapAlloc(GetProcessHeap(),
1267 HEAP_ZERO_MEMORY,
1268 sizeof(gsCacheEntryFormat));
1270 formatEntry = entry->format[format];
1272 if(formatEntry->nrealized <= glyph) {
1273 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1275 if (formatEntry->realized)
1276 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1277 HEAP_ZERO_MEMORY,
1278 formatEntry->realized,
1279 formatEntry->nrealized * sizeof(BOOL));
1280 else
1281 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1282 HEAP_ZERO_MEMORY,
1283 formatEntry->nrealized * sizeof(BOOL));
1285 if (formatEntry->gis)
1286 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1287 HEAP_ZERO_MEMORY,
1288 formatEntry->gis,
1289 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1290 else
1291 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1292 HEAP_ZERO_MEMORY,
1293 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1297 if(formatEntry->glyphset == 0) {
1298 switch(format) {
1299 case AA_Grey:
1300 wxr_format = WXR_FORMAT_GRAY;
1301 break;
1303 case AA_RGB:
1304 case AA_BGR:
1305 case AA_VRGB:
1306 case AA_VBGR:
1307 wxr_format = WXR_FORMAT_A8R8G8B8;
1308 break;
1310 default:
1311 ERR("aa = %d - not implemented\n", format);
1312 case AA_None:
1313 wxr_format = WXR_FORMAT_MONO;
1314 break;
1317 formatEntry->font_format = pict_formats[wxr_format];
1318 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1322 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1323 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1324 formatEntry->realized[glyph] = TRUE;
1326 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1327 buflen,
1328 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1329 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1331 gi.width = gm.gmBlackBoxX;
1332 gi.height = gm.gmBlackBoxY;
1333 gi.x = -gm.gmptGlyphOrigin.x;
1334 gi.y = gm.gmptGlyphOrigin.y;
1335 gi.xOff = gm.gmCellIncX;
1336 gi.yOff = gm.gmCellIncY;
1338 if(TRACE_ON(xrender)) {
1339 int pitch, i, j;
1340 char output[300];
1341 unsigned char *line;
1343 if(format == AA_None) {
1344 pitch = ((gi.width + 31) / 32) * 4;
1345 for(i = 0; i < gi.height; i++) {
1346 line = (unsigned char*) buf + i * pitch;
1347 output[0] = '\0';
1348 for(j = 0; j < pitch * 8; j++) {
1349 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1351 TRACE("%s\n", output);
1353 } else {
1354 static const char blks[] = " .:;!o*#";
1355 char str[2];
1357 str[1] = '\0';
1358 pitch = ((gi.width + 3) / 4) * 4;
1359 for(i = 0; i < gi.height; i++) {
1360 line = (unsigned char*) buf + i * pitch;
1361 output[0] = '\0';
1362 for(j = 0; j < pitch; j++) {
1363 str[0] = blks[line[j] >> 5];
1364 strcat(output, str);
1366 TRACE("%s\n", output);
1372 if(formatEntry->glyphset) {
1373 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1374 unsigned char *byte = (unsigned char*) buf, c;
1375 int i = buflen;
1377 while(i--) {
1378 c = *byte;
1380 /* magic to flip bit order */
1381 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1382 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1383 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1385 *byte++ = c;
1388 else if ( format != AA_Grey &&
1389 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1391 unsigned int i, *data = (unsigned int *)buf;
1392 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1394 gid = glyph;
1397 XRenderCompositeText seems to ignore 0x0 glyphs when
1398 AA_None, which means we lose the advance width of glyphs
1399 like the space. We'll pretend that such glyphs are 1x1
1400 bitmaps.
1403 if(buflen == 0)
1404 gi.width = gi.height = 1;
1406 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1407 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1408 HeapFree(GetProcessHeap(), 0, buf);
1411 formatEntry->gis[glyph] = gi;
1414 /*************************************************************
1415 * get_tile_pict
1417 * Returns an appropriate Picture for tiling the text colour.
1418 * Call and use result within the xrender_cs
1420 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1422 static struct
1424 Pixmap xpm;
1425 Picture pict;
1426 XRenderColor current_color;
1427 } tiles[WXR_NB_FORMATS], *tile;
1429 tile = &tiles[wxr_format];
1431 if(!tile->xpm)
1433 XRenderPictureAttributes pa;
1434 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1436 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1438 pa.repeat = RepeatNormal;
1439 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1441 /* init current_color to something different from text_pixel */
1442 tile->current_color = *color;
1443 tile->current_color.red ^= 0xffff;
1445 if (wxr_format == WXR_FORMAT_MONO)
1447 /* for a 1bpp bitmap we always need a 1 in the tile */
1448 XRenderColor col;
1449 col.red = col.green = col.blue = 0;
1450 col.alpha = 0xffff;
1451 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1455 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1457 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1458 tile->current_color = *color;
1460 return tile->pict;
1463 /*************************************************************
1464 * get_mask_pict
1466 * Returns an appropriate Picture for masking with the specified alpha.
1467 * Call and use result within the xrender_cs
1469 static Picture get_mask_pict( int alpha )
1471 static Pixmap pixmap;
1472 static Picture pict;
1473 static int current_alpha;
1475 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1477 if (!pixmap)
1479 XRenderPictureAttributes pa;
1481 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1482 pa.repeat = RepeatNormal;
1483 pict = pXRenderCreatePicture( gdi_display, pixmap,
1484 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1485 current_alpha = -1;
1488 if (alpha != current_alpha)
1490 XRenderColor col;
1491 col.red = col.green = col.blue = 0;
1492 col.alpha = current_alpha = alpha;
1493 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1495 return pict;
1498 /***********************************************************************
1499 * xrenderdrv_ExtTextOut
1501 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1502 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1504 struct xrender_physdev *physdev = get_xrender_dev( dev );
1505 gsCacheEntry *entry;
1506 gsCacheEntryFormat *formatEntry;
1507 AA_Type aa_type = AA_None;
1508 unsigned int idx;
1509 Picture pict, tile_pict = 0;
1510 XGlyphElt16 *elts;
1511 POINT offset, desired, current;
1512 int render_op = PictOpOver;
1513 XRenderColor col;
1514 RECT rect, bounds;
1516 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1517 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1519 if(flags & ETO_OPAQUE)
1521 XRenderColor bg;
1523 if (physdev->format == WXR_FORMAT_MONO)
1524 /* use the inverse of the text color */
1525 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1526 else
1527 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1529 set_xrender_transformation( pict, 1, 1, 0, 0 );
1530 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1531 physdev->x11dev->dc_rect.left + lprect->left,
1532 physdev->x11dev->dc_rect.top + lprect->top,
1533 lprect->right - lprect->left,
1534 lprect->bottom - lprect->top );
1535 add_device_bounds( physdev->x11dev, lprect );
1538 if(count == 0) return TRUE;
1540 EnterCriticalSection(&xrender_cs);
1542 entry = glyphsetCache + physdev->cache_index;
1543 aa_type = entry->aa_default;
1544 formatEntry = entry->format[aa_type];
1546 for(idx = 0; idx < count; idx++) {
1547 if( !formatEntry ) {
1548 UploadGlyph(physdev, wstr[idx], aa_type);
1549 /* re-evaluate antialias since aa_default may have changed */
1550 aa_type = entry->aa_default;
1551 formatEntry = entry->format[aa_type];
1552 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1553 UploadGlyph(physdev, wstr[idx], aa_type);
1556 if (!formatEntry)
1558 WARN("could not upload requested glyphs\n");
1559 LeaveCriticalSection(&xrender_cs);
1560 return FALSE;
1563 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1564 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1566 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1568 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1569 So we pass zeros to the function and move to our starting position using the first
1570 element of the elts array. */
1572 desired.x = physdev->x11dev->dc_rect.left + x;
1573 desired.y = physdev->x11dev->dc_rect.top + y;
1574 offset.x = offset.y = 0;
1575 current.x = current.y = 0;
1577 tile_pict = get_tile_pict(physdev->format, &col);
1579 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1581 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1582 render_op = PictOpOutReverse; /* This gives us 'black' text */
1584 reset_bounds( &bounds );
1585 for(idx = 0; idx < count; idx++)
1587 elts[idx].glyphset = formatEntry->glyphset;
1588 elts[idx].chars = wstr + idx;
1589 elts[idx].nchars = 1;
1590 elts[idx].xOff = desired.x - current.x;
1591 elts[idx].yOff = desired.y - current.y;
1593 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1594 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1596 rect.left = desired.x - physdev->x11dev->dc_rect.left - formatEntry->gis[wstr[idx]].x;
1597 rect.top = desired.y - physdev->x11dev->dc_rect.top - formatEntry->gis[wstr[idx]].y;
1598 rect.right = rect.left + formatEntry->gis[wstr[idx]].width;
1599 rect.bottom = rect.top + formatEntry->gis[wstr[idx]].height;
1600 add_bounds_rect( &bounds, &rect );
1602 if(!lpDx)
1604 desired.x += formatEntry->gis[wstr[idx]].xOff;
1605 desired.y += formatEntry->gis[wstr[idx]].yOff;
1607 else
1609 if(flags & ETO_PDY)
1611 offset.x += lpDx[idx * 2];
1612 offset.y += lpDx[idx * 2 + 1];
1614 else
1615 offset.x += lpDx[idx];
1616 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1617 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1621 /* Make sure we don't have any transforms set from a previous call */
1622 set_xrender_transformation(pict, 1, 1, 0, 0);
1623 pXRenderCompositeText16(gdi_display, render_op,
1624 tile_pict,
1625 pict,
1626 formatEntry->font_format,
1627 0, 0, 0, 0, elts, count);
1628 HeapFree(GetProcessHeap(), 0, elts);
1630 LeaveCriticalSection(&xrender_cs);
1631 add_device_bounds( physdev->x11dev, &bounds );
1632 return TRUE;
1635 /* multiply the alpha channel of a picture */
1636 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1637 int x, int y, int width, int height )
1639 XRenderPictureAttributes pa;
1640 Pixmap src_pixmap, mask_pixmap;
1641 Picture src_pict, mask_pict;
1642 XRenderColor color;
1644 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1645 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1646 pa.repeat = RepeatNormal;
1647 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1648 pa.component_alpha = True;
1649 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1650 color.red = color.green = color.blue = color.alpha = 0xffff;
1651 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1652 color.alpha = alpha;
1653 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1654 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1655 0, 0, 0, 0, x, y, width, height );
1656 pXRenderFreePicture( gdi_display, src_pict );
1657 pXRenderFreePicture( gdi_display, mask_pict );
1658 XFreePixmap( gdi_display, src_pixmap );
1659 XFreePixmap( gdi_display, mask_pixmap );
1662 /* Helper function for (stretched) blitting using xrender */
1663 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1664 int x_src, int y_src, int width_src, int height_src,
1665 int x_dst, int y_dst, int width_dst, int height_dst,
1666 double xscale, double yscale )
1668 int x_offset, y_offset;
1670 if (width_src < 0)
1672 x_src += width_src + 1;
1673 width_src = -width_src;
1675 if (height_src < 0)
1677 y_src += height_src + 1;
1678 height_src = -height_src;
1680 if (width_dst < 0)
1682 x_dst += width_dst + 1;
1683 width_dst = -width_dst;
1685 if (height_dst < 0)
1687 y_dst += height_dst + 1;
1688 height_dst = -height_dst;
1691 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1692 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1693 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1694 if(xscale != 1.0 || yscale != 1.0)
1696 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1697 * in the wrong quadrant of the x-y plane.
1699 x_offset = (xscale < 0) ? -width_dst : 0;
1700 y_offset = (yscale < 0) ? -height_dst : 0;
1701 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1703 else
1705 x_offset = x_src;
1706 y_offset = y_src;
1707 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1709 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1710 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1713 /* Helper function for (stretched) mono->color blitting using xrender */
1714 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1715 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1716 int x_src, int y_src, int width_src, int height_src,
1717 int x_dst, int y_dst, int width_dst, int height_dst,
1718 double xscale, double yscale )
1720 Picture tile_pict;
1721 int x_offset, y_offset;
1722 XRenderColor color;
1724 if (width_src < 0)
1726 x_src += width_src + 1;
1727 width_src = -width_src;
1729 if (height_src < 0)
1731 y_src += height_src + 1;
1732 height_src = -height_src;
1734 if (width_dst < 0)
1736 x_dst += width_dst + 1;
1737 width_dst = -width_dst;
1739 if (height_dst < 0)
1741 y_dst += height_dst + 1;
1742 height_dst = -height_dst;
1745 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1746 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1747 * the tile data.
1749 EnterCriticalSection( &xrender_cs );
1750 color = *bg;
1751 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1752 tile_pict = get_tile_pict( dst_format, &color );
1754 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1756 if (xscale != 1.0 || yscale != 1.0)
1758 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1759 * in the wrong quadrant of the x-y plane.
1761 x_offset = (xscale < 0) ? -width_dst : 0;
1762 y_offset = (yscale < 0) ? -height_dst : 0;
1763 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1765 else
1767 x_offset = x_src;
1768 y_offset = y_src;
1769 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1771 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1772 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1773 LeaveCriticalSection( &xrender_cs );
1775 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1776 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1777 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1778 x_dst, y_dst, width_dst, height_dst );
1781 /* create a pixmap and render picture for an image */
1782 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1783 struct bitblt_coords *src, enum wxr_format format,
1784 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1786 DWORD ret;
1787 int width = src->visrect.right - src->visrect.left;
1788 int height = src->visrect.bottom - src->visrect.top;
1789 int depth = pict_formats[format]->depth;
1790 struct gdi_image_bits dst_bits;
1791 XRenderPictureAttributes pa;
1792 GC gc;
1793 XImage *image;
1795 image = XCreateImage( gdi_display, default_visual.visual, depth, ZPixmap, 0, NULL,
1796 info->bmiHeader.biWidth, height, 32, 0 );
1797 if (!image) return ERROR_OUTOFMEMORY;
1799 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1800 if (ret) return ret;
1802 image->data = dst_bits.ptr;
1804 *use_repeat = (width == 1 && height == 1);
1805 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1807 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1808 gc = XCreateGC( gdi_display, *pixmap, 0, NULL );
1809 XPutImage( gdi_display, *pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1810 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1811 XFreeGC( gdi_display, gc );
1813 /* make coordinates relative to the pixmap */
1814 src->x -= src->visrect.left;
1815 src->y -= src->visrect.top;
1816 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1818 image->data = NULL;
1819 XDestroyImage( image );
1820 if (dst_bits.free) dst_bits.free( &dst_bits );
1821 return ret;
1824 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1825 Drawable drawable, const struct bitblt_coords *src,
1826 const struct bitblt_coords *dst )
1828 int x_dst, y_dst;
1829 Picture src_pict = 0, dst_pict, mask_pict = 0;
1830 double xscale = src->width / (double)dst->width;
1831 double yscale = src->height / (double)dst->height;
1833 if (drawable) /* using an intermediate pixmap */
1835 x_dst = dst->x;
1836 y_dst = dst->y;
1837 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, 0, NULL );
1839 else
1841 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
1842 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
1843 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1846 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1848 /* mono -> color */
1849 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1851 XRenderColor fg, bg;
1853 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
1854 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
1855 fg.alpha = bg.alpha = 0;
1857 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
1858 physdev_src->x11dev->dc_rect.left + src->x,
1859 physdev_src->x11dev->dc_rect.top + src->y,
1860 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1862 else /* color -> color (can be at different depths) or mono -> mono */
1864 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
1865 mask_pict = get_no_alpha_mask();
1867 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
1868 physdev_src->x11dev->dc_rect.left + src->x,
1869 physdev_src->x11dev->dc_rect.top + src->y,
1870 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1873 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1877 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
1878 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
1879 Drawable drawable, struct bitblt_coords *src,
1880 struct bitblt_coords *dst, BOOL use_repeat )
1882 int x_dst, y_dst;
1883 Picture dst_pict;
1884 double xscale, yscale;
1886 if (drawable) /* using an intermediate pixmap */
1888 RGNDATA *clip_data = NULL;
1890 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1891 x_dst = dst->x;
1892 y_dst = dst->y;
1893 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL );
1894 if (clip_data)
1895 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
1896 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
1897 HeapFree( GetProcessHeap(), 0, clip_data );
1899 else
1901 x_dst = physdev->x11dev->dc_rect.left + dst->x;
1902 y_dst = physdev->x11dev->dc_rect.top + dst->y;
1903 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
1906 if (!use_repeat)
1908 xscale = src->width / (double)dst->width;
1909 yscale = src->height / (double)dst->height;
1911 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1913 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
1914 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1916 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1920 /***********************************************************************
1921 * xrenderdrv_StretchBlt
1923 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1924 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1926 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1927 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1928 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
1930 if (src_dev->funcs != dst_dev->funcs)
1932 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
1933 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
1936 /* XRender is of no use for color -> mono */
1937 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
1938 goto x11drv_fallback;
1940 /* if not stretching, we only need to handle format conversion */
1941 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
1943 if (rop != SRCCOPY)
1945 GC tmpGC;
1946 Pixmap tmp_pixmap;
1947 struct bitblt_coords tmp;
1949 /* make coordinates relative to tmp pixmap */
1950 tmp = *dst;
1951 tmp.x -= tmp.visrect.left;
1952 tmp.y -= tmp.visrect.top;
1953 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1955 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
1956 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1957 XSetGraphicsExposures( gdi_display, tmpGC, False );
1958 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
1959 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
1961 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
1962 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
1964 XFreePixmap( gdi_display, tmp_pixmap );
1965 XFreeGC( gdi_display, tmpGC );
1967 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
1969 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
1970 return TRUE;
1972 x11drv_fallback:
1973 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
1977 /***********************************************************************
1978 * xrenderdrv_PutImage
1980 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1981 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1982 struct bitblt_coords *dst, DWORD rop )
1984 struct xrender_physdev *physdev = get_xrender_dev( dev );
1985 DWORD ret;
1986 Pixmap tmp_pixmap;
1987 GC gc;
1988 enum wxr_format src_format, dst_format;
1989 XRenderPictFormat *pict_format;
1990 Pixmap src_pixmap;
1991 Picture src_pict, mask_pict = 0;
1992 BOOL use_repeat;
1994 dst_format = physdev->format;
1995 src_format = get_xrender_format_from_bitmapinfo( info );
1996 if (!(pict_format = pict_formats[src_format])) goto update_format;
1998 /* make sure we can create an image with the same bpp */
1999 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2000 goto update_format;
2002 /* mono <-> color conversions not supported */
2003 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2004 goto x11drv_fallback;
2006 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2008 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2010 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2011 if (!ret)
2013 struct bitblt_coords tmp;
2015 if (rop != SRCCOPY)
2017 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2019 /* make coordinates relative to tmp pixmap */
2020 tmp = *dst;
2021 tmp.x -= tmp.visrect.left;
2022 tmp.y -= tmp.visrect.top;
2023 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2025 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2026 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2027 XSetGraphicsExposures( gdi_display, gc, False );
2028 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2029 tmp.visrect.right - tmp.visrect.left,
2030 tmp.visrect.bottom - tmp.visrect.top,
2031 physdev->pict_format->depth );
2033 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2034 NULL, tmp_pixmap, src, &tmp, use_repeat );
2035 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2037 XFreePixmap( gdi_display, tmp_pixmap );
2038 XFreeGC( gdi_display, gc );
2039 if (restore_region) restore_clipping_region( physdev->x11dev );
2041 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2042 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2044 add_device_bounds( physdev->x11dev, &dst->visrect );
2046 pXRenderFreePicture( gdi_display, src_pict );
2047 XFreePixmap( gdi_display, src_pixmap );
2049 return ret;
2051 update_format:
2052 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2053 set_color_info( pict_formats[dst_format], info );
2054 return ERROR_BAD_FORMAT;
2056 x11drv_fallback:
2057 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2058 return dev->funcs->pPutImage( dev, clip, info, bits, src, dst, rop );
2062 /***********************************************************************
2063 * xrenderdrv_BlendImage
2065 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2066 struct bitblt_coords *src, struct bitblt_coords *dst,
2067 BLENDFUNCTION func )
2069 struct xrender_physdev *physdev = get_xrender_dev( dev );
2070 DWORD ret;
2071 enum wxr_format format;
2072 XRenderPictFormat *pict_format;
2073 Picture dst_pict, src_pict, mask_pict;
2074 Pixmap src_pixmap;
2075 BOOL use_repeat;
2077 format = get_xrender_format_from_bitmapinfo( info );
2078 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2079 format = get_format_without_alpha( format );
2080 else if (format != WXR_FORMAT_A8R8G8B8 || info->bmiHeader.biCompression != BI_RGB)
2081 return ERROR_INVALID_PARAMETER;
2083 if (!(pict_format = pict_formats[format])) goto update_format;
2085 /* make sure we can create an image with the same bpp */
2086 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2087 goto update_format;
2089 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2090 goto update_format;
2092 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2094 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2095 if (!ret)
2097 double xscale, yscale;
2099 if (!use_repeat)
2101 xscale = src->width / (double)dst->width;
2102 yscale = src->height / (double)dst->height;
2104 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2106 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2108 EnterCriticalSection( &xrender_cs );
2109 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2111 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2112 src->x, src->y, src->width, src->height,
2113 physdev->x11dev->dc_rect.left + dst->x,
2114 physdev->x11dev->dc_rect.top + dst->y,
2115 dst->width, dst->height, xscale, yscale );
2117 pXRenderFreePicture( gdi_display, src_pict );
2118 XFreePixmap( gdi_display, src_pixmap );
2120 LeaveCriticalSection( &xrender_cs );
2121 add_device_bounds( physdev->x11dev, &dst->visrect );
2123 return ret;
2125 update_format:
2126 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2127 set_color_info( physdev->pict_format, info );
2128 return ERROR_BAD_FORMAT;
2132 /***********************************************************************
2133 * xrenderdrv_AlphaBlend
2135 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2136 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2138 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2139 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2140 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2141 XRenderPictureAttributes pa;
2142 Pixmap tmp_pixmap = 0;
2143 double xscale, yscale;
2145 if (src_dev->funcs != dst_dev->funcs)
2147 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2148 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2151 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2153 SetLastError( ERROR_INVALID_PARAMETER );
2154 return FALSE;
2157 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2159 xscale = src->width / (double)dst->width;
2160 yscale = src->height / (double)dst->height;
2162 src_pict = get_xrender_picture_source( physdev_src, FALSE );
2164 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2166 /* mono -> color blending needs an intermediate color pixmap */
2167 XRenderColor fg, bg;
2168 int width = src->visrect.right - src->visrect.left;
2169 int height = src->visrect.bottom - src->visrect.top;
2171 /* blending doesn't use the destination DC colors */
2172 fg.red = fg.green = fg.blue = 0;
2173 bg.red = bg.green = bg.blue = 0xffff;
2174 fg.alpha = bg.alpha = 0xffff;
2176 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2177 physdev_dst->pict_format->depth );
2178 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format, 0, NULL );
2180 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2181 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
2183 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2185 /* we need a source picture with no alpha */
2186 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2187 if (format != physdev_src->format)
2189 pa.subwindow_mode = IncludeInferiors;
2190 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2191 pict_formats[format], CPSubwindowMode, &pa );
2195 if (tmp_pict) src_pict = tmp_pict;
2197 EnterCriticalSection( &xrender_cs );
2198 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2200 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2201 physdev_src->x11dev->dc_rect.left + src->x,
2202 physdev_src->x11dev->dc_rect.top + src->y,
2203 src->width, src->height,
2204 physdev_dst->x11dev->dc_rect.left + dst->x,
2205 physdev_dst->x11dev->dc_rect.top + dst->y,
2206 dst->width, dst->height, xscale, yscale );
2208 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2209 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2211 LeaveCriticalSection( &xrender_cs );
2212 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2213 return TRUE;
2216 /***********************************************************************
2217 * xrenderdrv_GradientFill
2219 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2220 void * grad_array, ULONG ngrad, ULONG mode )
2222 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2223 static const XFixed stops[2] = { 0, 1 << 16 };
2224 struct xrender_physdev *physdev = get_xrender_dev( dev );
2225 XLinearGradient gradient;
2226 XRenderColor colors[2];
2227 Picture src_pict, dst_pict;
2228 unsigned int i;
2229 const GRADIENT_RECT *rect = grad_array;
2230 RECT rc;
2231 POINT pt[2];
2233 if (!pXRenderCreateLinearGradient) goto fallback;
2235 /* <= 16-bpp uses dithering */
2236 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2238 switch (mode)
2240 case GRADIENT_FILL_RECT_H:
2241 case GRADIENT_FILL_RECT_V:
2242 for (i = 0; i < ngrad; i++, rect++)
2244 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2245 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2247 colors[0].red = v1->Red * 257 / 256;
2248 colors[0].green = v1->Green * 257 / 256;
2249 colors[0].blue = v1->Blue * 257 / 256;
2250 colors[1].red = v2->Red * 257 / 256;
2251 colors[1].green = v2->Green * 257 / 256;
2252 colors[1].blue = v2->Blue * 257 / 256;
2253 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2254 colors[0].alpha = colors[1].alpha = 65535;
2256 pt[0].x = v1->x;
2257 pt[0].y = v1->y;
2258 pt[1].x = v2->x;
2259 pt[1].y = v2->y;
2260 LPtoDP( dev->hdc, pt, 2 );
2261 if (mode == GRADIENT_FILL_RECT_H)
2263 gradient.p1.y = gradient.p2.y = 0;
2264 if (pt[1].x > pt[0].x)
2266 gradient.p1.x = 0;
2267 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2269 else
2271 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2272 gradient.p2.x = 0;
2275 else
2277 gradient.p1.x = gradient.p2.x = 0;
2278 if (pt[1].y > pt[0].y)
2280 gradient.p1.y = 0;
2281 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2283 else
2285 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2286 gradient.p2.y = 0;
2290 rc.left = min( pt[0].x, pt[1].x );
2291 rc.top = min( pt[0].y, pt[1].y );
2292 rc.right = max( pt[0].x, pt[1].x );
2293 rc.bottom = max( pt[0].y, pt[1].y );
2295 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2296 mode, wine_dbgstr_rect( &rc ),
2297 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2298 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2300 dst_pict = get_xrender_picture( physdev, 0, NULL );
2302 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2303 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2304 0, 0, rc.right - rc.left, rc.bottom - rc.top,
2305 physdev->x11dev->dc_rect.left + rc.left,
2306 physdev->x11dev->dc_rect.top + rc.top,
2307 rc.right - rc.left, rc.bottom - rc.top, 1, 1 );
2308 pXRenderFreePicture( gdi_display, src_pict );
2309 add_device_bounds( physdev->x11dev, &rc );
2311 return TRUE;
2314 fallback:
2315 #endif
2316 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2317 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2320 /***********************************************************************
2321 * xrenderdrv_SelectBrush
2323 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2325 struct xrender_physdev *physdev = get_xrender_dev( dev );
2326 Pixmap pixmap;
2327 XVisualInfo vis = default_visual;
2328 XRenderPictFormat *format = physdev->pict_format;
2330 if (!pattern) goto x11drv_fallback;
2331 if (pattern->info->bmiHeader.biBitCount == 1) goto x11drv_fallback;
2332 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2334 vis.depth = format->depth;
2335 vis.red_mask = format->direct.redMask << format->direct.red;
2336 vis.green_mask = format->direct.greenMask << format->direct.green;
2337 vis.blue_mask = format->direct.blueMask << format->direct.blue;
2339 pixmap = create_pixmap_from_image( physdev->dev.hdc, &vis, pattern->info,
2340 &pattern->bits, pattern->usage );
2341 if (!pixmap) return 0;
2343 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2344 physdev->x11dev->brush.pixmap = pixmap;
2345 physdev->x11dev->brush.fillStyle = FillTiled;
2346 physdev->x11dev->brush.pixel = 0; /* ignored */
2347 physdev->x11dev->brush.style = BS_PATTERN;
2348 return hbrush;
2350 x11drv_fallback:
2351 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2352 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2356 static const struct gdi_dc_funcs xrender_funcs =
2358 NULL, /* pAbortDoc */
2359 NULL, /* pAbortPath */
2360 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2361 NULL, /* pAngleArc */
2362 NULL, /* pArc */
2363 NULL, /* pArcTo */
2364 NULL, /* pBeginPath */
2365 xrenderdrv_BlendImage, /* pBlendImage */
2366 NULL, /* pChord */
2367 NULL, /* pCloseFigure */
2368 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2369 xrenderdrv_CreateDC, /* pCreateDC */
2370 xrenderdrv_DeleteDC, /* pDeleteDC */
2371 NULL, /* pDeleteObject */
2372 NULL, /* pDeviceCapabilities */
2373 NULL, /* pEllipse */
2374 NULL, /* pEndDoc */
2375 NULL, /* pEndPage */
2376 NULL, /* pEndPath */
2377 NULL, /* pEnumFonts */
2378 NULL, /* pEnumICMProfiles */
2379 NULL, /* pExcludeClipRect */
2380 NULL, /* pExtDeviceMode */
2381 xrenderdrv_ExtEscape, /* pExtEscape */
2382 NULL, /* pExtFloodFill */
2383 NULL, /* pExtSelectClipRgn */
2384 xrenderdrv_ExtTextOut, /* pExtTextOut */
2385 NULL, /* pFillPath */
2386 NULL, /* pFillRgn */
2387 NULL, /* pFlattenPath */
2388 NULL, /* pFontIsLinked */
2389 NULL, /* pFrameRgn */
2390 NULL, /* pGdiComment */
2391 NULL, /* pGdiRealizationInfo */
2392 NULL, /* pGetBoundsRect */
2393 NULL, /* pGetCharABCWidths */
2394 NULL, /* pGetCharABCWidthsI */
2395 NULL, /* pGetCharWidth */
2396 NULL, /* pGetDeviceCaps */
2397 NULL, /* pGetDeviceGammaRamp */
2398 NULL, /* pGetFontData */
2399 NULL, /* pGetFontUnicodeRanges */
2400 NULL, /* pGetGlyphIndices */
2401 NULL, /* pGetGlyphOutline */
2402 NULL, /* pGetICMProfile */
2403 NULL, /* pGetImage */
2404 NULL, /* pGetKerningPairs */
2405 NULL, /* pGetNearestColor */
2406 NULL, /* pGetOutlineTextMetrics */
2407 NULL, /* pGetPixel */
2408 NULL, /* pGetSystemPaletteEntries */
2409 NULL, /* pGetTextCharsetInfo */
2410 NULL, /* pGetTextExtentExPoint */
2411 NULL, /* pGetTextExtentExPointI */
2412 NULL, /* pGetTextFace */
2413 NULL, /* pGetTextMetrics */
2414 xrenderdrv_GradientFill, /* pGradientFill */
2415 NULL, /* pIntersectClipRect */
2416 NULL, /* pInvertRgn */
2417 NULL, /* pLineTo */
2418 NULL, /* pModifyWorldTransform */
2419 NULL, /* pMoveTo */
2420 NULL, /* pOffsetClipRgn */
2421 NULL, /* pOffsetViewportOrg */
2422 NULL, /* pOffsetWindowOrg */
2423 NULL, /* pPaintRgn */
2424 NULL, /* pPatBlt */
2425 NULL, /* pPie */
2426 NULL, /* pPolyBezier */
2427 NULL, /* pPolyBezierTo */
2428 NULL, /* pPolyDraw */
2429 NULL, /* pPolyPolygon */
2430 NULL, /* pPolyPolyline */
2431 NULL, /* pPolygon */
2432 NULL, /* pPolyline */
2433 NULL, /* pPolylineTo */
2434 xrenderdrv_PutImage, /* pPutImage */
2435 NULL, /* pRealizeDefaultPalette */
2436 NULL, /* pRealizePalette */
2437 NULL, /* pRectangle */
2438 NULL, /* pResetDC */
2439 NULL, /* pRestoreDC */
2440 NULL, /* pRoundRect */
2441 NULL, /* pSaveDC */
2442 NULL, /* pScaleViewportExt */
2443 NULL, /* pScaleWindowExt */
2444 NULL, /* pSelectBitmap */
2445 xrenderdrv_SelectBrush, /* pSelectBrush */
2446 NULL, /* pSelectClipPath */
2447 xrenderdrv_SelectFont, /* pSelectFont */
2448 NULL, /* pSelectPalette */
2449 NULL, /* pSelectPen */
2450 NULL, /* pSetArcDirection */
2451 NULL, /* pSetBkColor */
2452 NULL, /* pSetBkMode */
2453 NULL, /* pSetBoundsRect */
2454 NULL, /* pSetDCBrushColor */
2455 NULL, /* pSetDCPenColor */
2456 NULL, /* pSetDIBitsToDevice */
2457 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2458 NULL, /* pSetDeviceGammaRamp */
2459 NULL, /* pSetLayout */
2460 NULL, /* pSetMapMode */
2461 NULL, /* pSetMapperFlags */
2462 NULL, /* pSetPixel */
2463 NULL, /* pSetPolyFillMode */
2464 NULL, /* pSetROP2 */
2465 NULL, /* pSetRelAbs */
2466 NULL, /* pSetStretchBltMode */
2467 NULL, /* pSetTextAlign */
2468 NULL, /* pSetTextCharacterExtra */
2469 NULL, /* pSetTextColor */
2470 NULL, /* pSetTextJustification */
2471 NULL, /* pSetViewportExt */
2472 NULL, /* pSetViewportOrg */
2473 NULL, /* pSetWindowExt */
2474 NULL, /* pSetWindowOrg */
2475 NULL, /* pSetWorldTransform */
2476 NULL, /* pStartDoc */
2477 NULL, /* pStartPage */
2478 xrenderdrv_StretchBlt, /* pStretchBlt */
2479 NULL, /* pStretchDIBits */
2480 NULL, /* pStrokeAndFillPath */
2481 NULL, /* pStrokePath */
2482 NULL, /* pUnrealizePalette */
2483 NULL, /* pWidenPath */
2484 NULL, /* wine_get_wgl_driver */
2485 GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
2488 #else /* SONAME_LIBXRENDER */
2490 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2492 TRACE("XRender support not compiled in.\n");
2493 return NULL;
2496 #endif /* SONAME_LIBXRENDER */