winex11: Implement a SelectBrush entry point in the XRender driver.
[wine.git] / dlls / winex11.drv / xrender.c
bloba61568eed97069416deeaf3a117455f4204862b0
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 int using_client_side_fonts = FALSE;
43 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
45 #ifdef SONAME_LIBXRENDER
47 static BOOL X11DRV_XRender_Installed = FALSE;
49 #include <X11/Xlib.h>
50 #include <X11/extensions/Xrender.h>
52 #ifndef RepeatNone /* added in 0.10 */
53 #define RepeatNone 0
54 #define RepeatNormal 1
55 #define RepeatPad 2
56 #define RepeatReflect 3
57 #endif
59 enum wxr_format
61 WXR_FORMAT_MONO,
62 WXR_FORMAT_GRAY,
63 WXR_FORMAT_X1R5G5B5,
64 WXR_FORMAT_X1B5G5R5,
65 WXR_FORMAT_R5G6B5,
66 WXR_FORMAT_B5G6R5,
67 WXR_FORMAT_R8G8B8,
68 WXR_FORMAT_B8G8R8,
69 WXR_FORMAT_A8R8G8B8,
70 WXR_FORMAT_B8G8R8A8,
71 WXR_FORMAT_X8R8G8B8,
72 WXR_FORMAT_B8G8R8X8,
73 WXR_NB_FORMATS,
74 WXR_INVALID_FORMAT = WXR_NB_FORMATS
77 typedef struct wine_xrender_format_template
79 unsigned int depth;
80 unsigned int alpha;
81 unsigned int alphaMask;
82 unsigned int red;
83 unsigned int redMask;
84 unsigned int green;
85 unsigned int greenMask;
86 unsigned int blue;
87 unsigned int blueMask;
88 } WineXRenderFormatTemplate;
90 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
92 /* Format depth alpha mask red mask green mask blue mask*/
93 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
94 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
95 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
96 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
97 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
98 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
99 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
101 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
103 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
107 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
109 /* format phys red phys green phys blue log red log green log blue */
110 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
111 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
112 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
113 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
114 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
115 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
116 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
118 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
120 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
124 static enum wxr_format default_format = WXR_INVALID_FORMAT;
125 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
127 typedef struct
129 LOGFONTW lf;
130 XFORM xform;
131 SIZE devsize; /* size in device coords */
132 DWORD hash;
133 } LFANDSIZE;
135 #define INITIAL_REALIZED_BUF_SIZE 128
137 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
139 typedef struct
141 GlyphSet glyphset;
142 XRenderPictFormat *font_format;
143 int nrealized;
144 BOOL *realized;
145 void **bitmaps;
146 XGlyphInfo *gis;
147 } gsCacheEntryFormat;
149 typedef struct
151 LFANDSIZE lfsz;
152 AA_Type aa_default;
153 gsCacheEntryFormat * format[AA_MAXVALUE];
154 INT count;
155 INT next;
156 } gsCacheEntry;
158 struct xrender_physdev
160 struct gdi_physdev dev;
161 X11DRV_PDEVICE *x11dev;
162 enum wxr_format format;
163 int cache_index;
164 BOOL update_clip;
165 Picture pict;
166 Picture pict_src;
167 XRenderPictFormat *pict_format;
170 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
172 return (struct xrender_physdev *)dev;
175 static const struct gdi_dc_funcs xrender_funcs;
177 static gsCacheEntry *glyphsetCache = NULL;
178 static DWORD glyphsetCacheSize = 0;
179 static INT lastfree = -1;
180 static INT mru = -1;
182 #define INIT_CACHE_SIZE 10
184 static int antialias = 1;
186 static void *xrender_handle;
188 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
189 MAKE_FUNCPTR(XRenderAddGlyphs)
190 MAKE_FUNCPTR(XRenderComposite)
191 MAKE_FUNCPTR(XRenderCompositeText16)
192 MAKE_FUNCPTR(XRenderCreateGlyphSet)
193 MAKE_FUNCPTR(XRenderCreatePicture)
194 MAKE_FUNCPTR(XRenderFillRectangle)
195 MAKE_FUNCPTR(XRenderFindFormat)
196 MAKE_FUNCPTR(XRenderFindVisualFormat)
197 MAKE_FUNCPTR(XRenderFreeGlyphSet)
198 MAKE_FUNCPTR(XRenderFreePicture)
199 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
200 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
201 MAKE_FUNCPTR(XRenderSetPictureTransform)
202 #endif
203 MAKE_FUNCPTR(XRenderQueryExtension)
205 #ifdef SONAME_LIBFONTCONFIG
206 #include <fontconfig/fontconfig.h>
207 MAKE_FUNCPTR(FcConfigSubstitute)
208 MAKE_FUNCPTR(FcDefaultSubstitute)
209 MAKE_FUNCPTR(FcFontMatch)
210 MAKE_FUNCPTR(FcInit)
211 MAKE_FUNCPTR(FcPatternCreate)
212 MAKE_FUNCPTR(FcPatternDestroy)
213 MAKE_FUNCPTR(FcPatternAddInteger)
214 MAKE_FUNCPTR(FcPatternAddString)
215 MAKE_FUNCPTR(FcPatternGetBool)
216 MAKE_FUNCPTR(FcPatternGetInteger)
217 MAKE_FUNCPTR(FcPatternGetString)
218 static void *fontconfig_handle;
219 static BOOL fontconfig_installed;
220 #endif
222 #undef MAKE_FUNCPTR
224 static CRITICAL_SECTION xrender_cs;
225 static CRITICAL_SECTION_DEBUG critsect_debug =
227 0, 0, &xrender_cs,
228 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
229 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
231 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
233 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
234 ( ( (ULONG)_x4 << 24 ) | \
235 ( (ULONG)_x3 << 16 ) | \
236 ( (ULONG)_x2 << 8 ) | \
237 (ULONG)_x1 )
239 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
241 #define GASP_GRIDFIT 0x01
242 #define GASP_DOGRAY 0x02
244 #ifdef WORDS_BIGENDIAN
245 #define get_be_word(x) (x)
246 #define NATIVE_BYTE_ORDER MSBFirst
247 #else
248 #define get_be_word(x) RtlUshortByteSwap(x)
249 #define NATIVE_BYTE_ORDER LSBFirst
250 #endif
252 static BOOL has_alpha( enum wxr_format format )
254 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
257 static enum wxr_format get_format_without_alpha( enum wxr_format format )
259 switch (format)
261 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
262 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
263 default: return format;
267 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
269 templ->id = 0;
270 templ->type = PictTypeDirect;
271 templ->depth = fmt->depth;
272 templ->direct.alpha = fmt->alpha;
273 templ->direct.alphaMask = fmt->alphaMask;
274 templ->direct.red = fmt->red;
275 templ->direct.redMask = fmt->redMask;
276 templ->direct.green = fmt->green;
277 templ->direct.greenMask = fmt->greenMask;
278 templ->direct.blue = fmt->blue;
279 templ->direct.blueMask = fmt->blueMask;
280 templ->colormap = 0;
282 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
284 return TRUE;
287 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
289 if(fmt->depth != screen_depth)
290 return FALSE;
291 if( (fmt->redMask << fmt->red) != visual->red_mask)
292 return FALSE;
293 if( (fmt->greenMask << fmt->green) != visual->green_mask)
294 return FALSE;
295 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
296 return FALSE;
298 /* We never select a default ARGB visual */
299 if(fmt->alphaMask)
300 return FALSE;
302 return TRUE;
305 static int load_xrender_formats(void)
307 int count = 0;
308 unsigned int i;
310 for (i = 0; i < WXR_NB_FORMATS; i++)
312 XRenderPictFormat templ;
314 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
316 wine_tsx11_lock();
317 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
318 if (!pict_formats[i])
320 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
321 if (visual->class == DirectColor)
323 XVisualInfo info;
324 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
325 screen_depth, TrueColor, &info ))
327 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
328 if (pict_formats[i]) visual = info.visual;
332 wine_tsx11_unlock();
333 if (pict_formats[i]) default_format = i;
335 else
337 unsigned long mask = 0;
338 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
340 wine_tsx11_lock();
341 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
342 wine_tsx11_unlock();
344 if (pict_formats[i])
346 count++;
347 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
350 return count;
353 /***********************************************************************
354 * X11DRV_XRender_Init
356 * Let's see if our XServer has the extension available
359 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
361 int event_base, i;
363 if (client_side_with_render &&
364 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
367 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
368 LOAD_FUNCPTR(XRenderAddGlyphs)
369 LOAD_FUNCPTR(XRenderComposite)
370 LOAD_FUNCPTR(XRenderCompositeText16)
371 LOAD_FUNCPTR(XRenderCreateGlyphSet)
372 LOAD_FUNCPTR(XRenderCreatePicture)
373 LOAD_FUNCPTR(XRenderFillRectangle)
374 LOAD_FUNCPTR(XRenderFindFormat)
375 LOAD_FUNCPTR(XRenderFindVisualFormat)
376 LOAD_FUNCPTR(XRenderFreeGlyphSet)
377 LOAD_FUNCPTR(XRenderFreePicture)
378 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
379 LOAD_FUNCPTR(XRenderQueryExtension)
380 #undef LOAD_FUNCPTR
381 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
382 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
383 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
384 #undef LOAD_OPTIONAL_FUNCPTR
385 #endif
387 wine_tsx11_lock();
388 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
389 wine_tsx11_unlock();
390 if(X11DRV_XRender_Installed) {
391 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
392 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
394 wine_tsx11_unlock();
395 WINE_MESSAGE(
396 "Wine has detected that you probably have a buggy version\n"
397 "of libXrender.so . Because of this client side font rendering\n"
398 "will be disabled. Please upgrade this library.\n");
399 X11DRV_XRender_Installed = FALSE;
400 return NULL;
403 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
404 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
405 X11DRV_XRender_Installed = FALSE;
410 #ifdef SONAME_LIBFONTCONFIG
411 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
413 #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;}
414 LOAD_FUNCPTR(FcConfigSubstitute);
415 LOAD_FUNCPTR(FcDefaultSubstitute);
416 LOAD_FUNCPTR(FcFontMatch);
417 LOAD_FUNCPTR(FcInit);
418 LOAD_FUNCPTR(FcPatternCreate);
419 LOAD_FUNCPTR(FcPatternDestroy);
420 LOAD_FUNCPTR(FcPatternAddInteger);
421 LOAD_FUNCPTR(FcPatternAddString);
422 LOAD_FUNCPTR(FcPatternGetBool);
423 LOAD_FUNCPTR(FcPatternGetInteger);
424 LOAD_FUNCPTR(FcPatternGetString);
425 #undef LOAD_FUNCPTR
426 fontconfig_installed = pFcInit();
428 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
429 #endif
431 sym_not_found:
432 if(X11DRV_XRender_Installed || client_side_with_core)
434 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
435 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
437 glyphsetCacheSize = INIT_CACHE_SIZE;
438 lastfree = 0;
439 for(i = 0; i < INIT_CACHE_SIZE; i++) {
440 glyphsetCache[i].next = i + 1;
441 glyphsetCache[i].count = -1;
443 glyphsetCache[i-1].next = -1;
444 using_client_side_fonts = 1;
446 if(!X11DRV_XRender_Installed) {
447 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
448 if(screen_depth <= 8 || !client_side_antialias_with_core)
449 antialias = 0;
450 } else {
451 if(screen_depth <= 8 || !client_side_antialias_with_render)
452 antialias = 0;
454 return &xrender_funcs;
456 TRACE("Using X11 core fonts\n");
457 return NULL;
460 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
461 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
463 if(pf->direct.redMask)
464 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
465 else
466 dst_color->red = 0;
468 if(pf->direct.greenMask)
469 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
470 else
471 dst_color->green = 0;
473 if(pf->direct.blueMask)
474 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
475 else
476 dst_color->blue = 0;
478 dst_color->alpha = 0xffff;
481 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
483 int redMask, greenMask, blueMask;
484 unsigned int i;
486 if (depth == 1) return WXR_FORMAT_MONO;
488 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
489 if (!shifts) return default_format;
491 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
492 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
493 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
495 /* Try to locate a format which matches the specification of the dibsection. */
496 for(i = 0; i < WXR_NB_FORMATS; i++)
498 if( depth == wxr_formats_template[i].depth &&
499 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
500 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
501 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
502 return i;
505 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
506 ERR("No XRender format found for %u %08x/%08x/%08x\n", depth, redMask, greenMask, blueMask);
507 return WXR_INVALID_FORMAT;
510 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
512 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
514 switch (info->bmiHeader.biBitCount)
516 case 1:
517 return WXR_FORMAT_MONO;
518 case 4:
519 case 8:
520 break;
521 case 24:
522 if (info->bmiHeader.biCompression != BI_RGB) break;
523 return WXR_FORMAT_R8G8B8;
524 case 16:
525 case 32:
526 if (info->bmiHeader.biCompression == BI_BITFIELDS)
528 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
529 unsigned int i;
531 for (i = 0; i < WXR_NB_FORMATS; i++)
533 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
534 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
535 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
536 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
537 return i;
539 break;
541 if (info->bmiHeader.biCompression != BI_RGB) break;
542 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
544 return WXR_INVALID_FORMAT;
547 static enum wxr_format get_bitmap_format( int bpp )
549 enum wxr_format format = WXR_INVALID_FORMAT;
551 if (bpp == screen_bpp)
553 switch (bpp)
555 case 16: format = WXR_FORMAT_R5G6B5; break;
556 case 24: format = WXR_FORMAT_R8G8B8; break;
557 case 32: format = WXR_FORMAT_A8R8G8B8; break;
560 return format;
563 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
564 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
566 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
567 XTransform xform = {{
568 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
569 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
570 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
573 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
574 #endif
577 /* check if we can use repeating instead of scaling for the specified source DC */
578 static BOOL use_source_repeat( struct xrender_physdev *dev )
580 return (dev->x11dev->bitmap &&
581 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
582 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
585 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
587 if (!dev->pict && dev->pict_format)
589 XRenderPictureAttributes pa;
591 wine_tsx11_lock();
592 pa.subwindow_mode = IncludeInferiors;
593 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
594 dev->pict_format, CPSubwindowMode, &pa );
595 wine_tsx11_unlock();
596 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
597 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
598 dev->update_clip = TRUE;
601 if (dev->update_clip)
603 RGNDATA *clip_data;
604 HRGN rgn = 0;
606 if (clip_rect)
608 rgn = CreateRectRgnIndirect( clip_rect );
609 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
610 CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
612 else if (clip_rgn)
614 rgn = CreateRectRgn( 0, 0, 0, 0 );
615 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
618 if ((clip_data = X11DRV_GetRegionData( rgn ? rgn : dev->x11dev->region, 0 )))
620 wine_tsx11_lock();
621 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
622 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
623 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
624 wine_tsx11_unlock();
625 HeapFree( GetProcessHeap(), 0, clip_data );
627 dev->update_clip = (rgn != 0); /* have to update again if we are using a custom region */
628 if (rgn) DeleteObject( rgn );
630 return dev->pict;
633 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
635 if (!dev->pict_src && dev->pict_format)
637 XRenderPictureAttributes pa;
639 wine_tsx11_lock();
640 pa.subwindow_mode = IncludeInferiors;
641 pa.repeat = repeat ? RepeatNormal : RepeatNone;
642 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
643 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
644 wine_tsx11_unlock();
646 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
647 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
650 return dev->pict_src;
653 static void free_xrender_picture( struct xrender_physdev *dev )
655 if (dev->pict || dev->pict_src)
657 wine_tsx11_lock();
658 XFlush( gdi_display );
659 if (dev->pict)
661 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
662 pXRenderFreePicture(gdi_display, dev->pict);
663 dev->pict = 0;
665 if(dev->pict_src)
667 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
668 pXRenderFreePicture(gdi_display, dev->pict_src);
669 dev->pict_src = 0;
671 wine_tsx11_unlock();
675 /* return a mask picture used to force alpha to 0 */
676 static Picture get_no_alpha_mask(void)
678 static Pixmap pixmap;
679 static Picture pict;
681 wine_tsx11_lock();
682 if (!pict)
684 XRenderPictureAttributes pa;
685 XRenderColor col;
687 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
688 pa.repeat = RepeatNormal;
689 pa.component_alpha = True;
690 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
691 CPRepeat|CPComponentAlpha, &pa );
692 col.red = col.green = col.blue = 0xffff;
693 col.alpha = 0;
694 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
696 wine_tsx11_unlock();
697 return pict;
700 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
702 if(p1->hash != p2->hash) return TRUE;
703 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
704 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
705 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
706 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
709 #if 0
710 static void walk_cache(void)
712 int i;
714 EnterCriticalSection(&xrender_cs);
715 for(i=mru; i >= 0; i = glyphsetCache[i].next)
716 TRACE("item %d\n", i);
717 LeaveCriticalSection(&xrender_cs);
719 #endif
721 static int LookupEntry(LFANDSIZE *plfsz)
723 int i, prev_i = -1;
725 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
726 TRACE("%d\n", i);
727 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
729 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
730 glyphsetCache[i].count++;
731 if(prev_i >= 0) {
732 glyphsetCache[prev_i].next = glyphsetCache[i].next;
733 glyphsetCache[i].next = mru;
734 mru = i;
736 TRACE("found font in cache %d\n", i);
737 return i;
739 prev_i = i;
741 TRACE("font not in cache\n");
742 return -1;
745 static void FreeEntry(int entry)
747 int i, format;
749 for(format = 0; format < AA_MAXVALUE; format++) {
750 gsCacheEntryFormat * formatEntry;
752 if( !glyphsetCache[entry].format[format] )
753 continue;
755 formatEntry = glyphsetCache[entry].format[format];
757 if(formatEntry->glyphset) {
758 wine_tsx11_lock();
759 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
760 wine_tsx11_unlock();
761 formatEntry->glyphset = 0;
763 if(formatEntry->nrealized) {
764 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
765 formatEntry->realized = NULL;
766 if(formatEntry->bitmaps) {
767 for(i = 0; i < formatEntry->nrealized; i++)
768 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
769 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
770 formatEntry->bitmaps = NULL;
772 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
773 formatEntry->gis = NULL;
774 formatEntry->nrealized = 0;
777 HeapFree(GetProcessHeap(), 0, formatEntry);
778 glyphsetCache[entry].format[format] = NULL;
782 static int AllocEntry(void)
784 int best = -1, prev_best = -1, i, prev_i = -1;
786 if(lastfree >= 0) {
787 assert(glyphsetCache[lastfree].count == -1);
788 glyphsetCache[lastfree].count = 1;
789 best = lastfree;
790 lastfree = glyphsetCache[lastfree].next;
791 assert(best != mru);
792 glyphsetCache[best].next = mru;
793 mru = best;
795 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
796 return mru;
799 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
800 if(glyphsetCache[i].count == 0) {
801 best = i;
802 prev_best = prev_i;
804 prev_i = i;
807 if(best >= 0) {
808 TRACE("freeing unused glyphset at cache %d\n", best);
809 FreeEntry(best);
810 glyphsetCache[best].count = 1;
811 if(prev_best >= 0) {
812 glyphsetCache[prev_best].next = glyphsetCache[best].next;
813 glyphsetCache[best].next = mru;
814 mru = best;
815 } else {
816 assert(mru == best);
818 return mru;
821 TRACE("Growing cache\n");
823 if (glyphsetCache)
824 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
825 glyphsetCache,
826 (glyphsetCacheSize + INIT_CACHE_SIZE)
827 * sizeof(*glyphsetCache));
828 else
829 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
830 (glyphsetCacheSize + INIT_CACHE_SIZE)
831 * sizeof(*glyphsetCache));
833 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
834 i++) {
835 glyphsetCache[i].next = i + 1;
836 glyphsetCache[i].count = -1;
838 glyphsetCache[i-1].next = -1;
839 glyphsetCacheSize += INIT_CACHE_SIZE;
841 lastfree = glyphsetCache[best].next;
842 glyphsetCache[best].count = 1;
843 glyphsetCache[best].next = mru;
844 mru = best;
845 TRACE("new free cache slot at %d\n", mru);
846 return mru;
849 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
851 DWORD size;
852 WORD *gasp, *buffer;
853 WORD num_recs;
854 DWORD ppem;
855 TEXTMETRICW tm;
857 *flags = 0;
859 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
860 if(size == GDI_ERROR)
861 return FALSE;
863 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
864 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
866 GetTextMetricsW(hdc, &tm);
867 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
869 gasp++;
870 num_recs = get_be_word(*gasp);
871 gasp++;
872 while(num_recs--)
874 *flags = get_be_word(*(gasp + 1));
875 if(ppem <= get_be_word(*gasp))
876 break;
877 gasp += 2;
879 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
881 HeapFree(GetProcessHeap(), 0, buffer);
882 return TRUE;
885 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
887 AA_Type ret;
888 WORD flags;
889 UINT font_smoothing_type, font_smoothing_orientation;
891 if (X11DRV_XRender_Installed && subpixel &&
892 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
893 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
895 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
896 &font_smoothing_orientation, 0) &&
897 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
899 ret = AA_BGR;
901 else
902 ret = AA_RGB;
903 /*FIXME
904 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
905 But, Wine's subpixel rendering can support the portrait mode.
908 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
909 ret = AA_Grey;
910 else
911 ret = AA_None;
913 return ret;
916 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
918 int ret;
919 int format;
920 gsCacheEntry *entry;
921 static int hinter = -1;
922 static int subpixel = -1;
923 BOOL font_smoothing;
925 if((ret = LookupEntry(plfsz)) != -1) return ret;
927 ret = AllocEntry();
928 entry = glyphsetCache + ret;
929 entry->lfsz = *plfsz;
930 for( format = 0; format < AA_MAXVALUE; format++ ) {
931 assert( !entry->format[format] );
934 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
936 if(hinter == -1 || subpixel == -1)
938 RASTERIZER_STATUS status;
939 GetRasterizerCaps(&status, sizeof(status));
940 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
941 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
944 switch (plfsz->lf.lfQuality)
946 case ANTIALIASED_QUALITY:
947 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
948 return ret; /* ignore further configuration */
949 case CLEARTYPE_QUALITY:
950 case CLEARTYPE_NATURAL_QUALITY:
951 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
952 break;
953 case DEFAULT_QUALITY:
954 case DRAFT_QUALITY:
955 case PROOF_QUALITY:
956 default:
957 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
958 font_smoothing)
960 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
962 else
963 entry->aa_default = AA_None;
964 break;
967 font_smoothing = TRUE; /* default to enabled */
968 #ifdef SONAME_LIBFONTCONFIG
969 if (fontconfig_installed)
971 FcPattern *match, *pattern;
972 FcResult result;
973 char family[LF_FACESIZE * 4];
975 #if defined(__i386__) && defined(__GNUC__)
976 /* fontconfig generates floating point exceptions, mask them */
977 WORD cw, default_cw = 0x37f;
978 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
979 #endif
981 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
982 pattern = pFcPatternCreate();
983 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
984 if (plfsz->lf.lfWeight != FW_DONTCARE)
986 int weight;
987 switch (plfsz->lf.lfWeight)
989 case FW_THIN: weight = FC_WEIGHT_THIN; break;
990 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
991 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
992 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
993 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
994 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
995 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
996 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
997 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
998 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
1000 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
1002 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
1003 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1004 pFcDefaultSubstitute( pattern );
1005 if ((match = pFcFontMatch( NULL, pattern, &result )))
1007 int rgba;
1008 FcBool antialias;
1010 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
1011 antialias = TRUE;
1012 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
1014 FcChar8 *file;
1015 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
1017 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
1018 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
1020 switch (rgba)
1022 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1023 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1024 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1025 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1026 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1029 if (!antialias) font_smoothing = FALSE;
1030 pFcPatternDestroy( match );
1032 pFcPatternDestroy( pattern );
1034 #if defined(__i386__) && defined(__GNUC__)
1035 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
1036 #endif
1038 #endif /* SONAME_LIBFONTCONFIG */
1040 /* now check Xft resources */
1042 char *value;
1043 BOOL antialias = TRUE;
1045 wine_tsx11_lock();
1046 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1048 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1049 value[0] == '0' || !strcasecmp( value, "off" ))
1050 antialias = FALSE;
1052 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1054 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1055 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1056 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1057 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1058 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1059 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1061 wine_tsx11_unlock();
1062 if (!antialias) font_smoothing = FALSE;
1065 if (!font_smoothing) entry->aa_default = AA_None;
1067 /* we can't support subpixel without xrender */
1068 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1070 else
1071 entry->aa_default = AA_None;
1073 return ret;
1076 static void dec_ref_cache(int index)
1078 assert(index >= 0);
1079 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1080 assert(glyphsetCache[index].count > 0);
1081 glyphsetCache[index].count--;
1084 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1086 DWORD hash = 0, *ptr, two_chars;
1087 WORD *pwc;
1088 int i;
1090 hash ^= plfsz->devsize.cx;
1091 hash ^= plfsz->devsize.cy;
1092 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1093 hash ^= *ptr;
1094 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1095 hash ^= *ptr;
1096 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1097 two_chars = *ptr;
1098 pwc = (WCHAR *)&two_chars;
1099 if(!*pwc) break;
1100 *pwc = toupperW(*pwc);
1101 pwc++;
1102 *pwc = toupperW(*pwc);
1103 hash ^= two_chars;
1104 if(!*pwc) break;
1106 plfsz->hash = hash;
1107 return;
1110 /***********************************************************************
1111 * X11DRV_XRender_Finalize
1113 void X11DRV_XRender_Finalize(void)
1115 int i;
1117 EnterCriticalSection(&xrender_cs);
1118 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1119 FreeEntry(i);
1120 LeaveCriticalSection(&xrender_cs);
1123 /**********************************************************************
1124 * xrenderdrv_SelectFont
1126 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1128 struct xrender_physdev *physdev = get_xrender_dev( dev );
1129 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1130 HFONT ret = next->funcs->pSelectFont( next, hfont );
1132 if (!ret) return 0;
1134 if (physdev->x11dev->has_gdi_font)
1136 LFANDSIZE lfsz;
1138 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1140 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1141 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1142 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1143 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1144 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1145 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1147 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1148 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1149 lfsz.xform.eM21, lfsz.xform.eM22);
1151 /* Not used fields, would break hashing */
1152 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1154 lfsz_calc_hash(&lfsz);
1156 EnterCriticalSection(&xrender_cs);
1157 if (physdev->cache_index != -1)
1158 dec_ref_cache( physdev->cache_index );
1159 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1160 LeaveCriticalSection(&xrender_cs);
1162 else
1164 EnterCriticalSection( &xrender_cs );
1165 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1166 physdev->cache_index = -1;
1167 LeaveCriticalSection( &xrender_cs );
1169 return ret;
1172 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1174 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1175 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1177 if (!physdev) return FALSE;
1178 physdev->x11dev = x11dev;
1179 physdev->cache_index = -1;
1180 physdev->format = format;
1181 physdev->pict_format = pict_formats[format];
1182 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1183 return TRUE;
1186 /* store the color mask data in the bitmap info structure */
1187 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1189 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1191 info->bmiHeader.biPlanes = 1;
1192 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1193 info->bmiHeader.biCompression = BI_RGB;
1194 info->bmiHeader.biClrUsed = 0;
1196 switch (info->bmiHeader.biBitCount)
1198 case 16:
1199 colors[0] = format->direct.redMask << format->direct.red;
1200 colors[1] = format->direct.greenMask << format->direct.green;
1201 colors[2] = format->direct.blueMask << format->direct.blue;
1202 info->bmiHeader.biCompression = BI_BITFIELDS;
1203 break;
1204 case 32:
1205 colors[0] = format->direct.redMask << format->direct.red;
1206 colors[1] = format->direct.greenMask << format->direct.green;
1207 colors[2] = format->direct.blueMask << format->direct.blue;
1208 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1209 info->bmiHeader.biCompression = BI_BITFIELDS;
1210 break;
1215 /**********************************************************************
1216 * xrenderdrv_CreateDC
1218 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1219 LPCWSTR output, const DEVMODEW* initData )
1221 return create_xrender_dc( pdev, default_format );
1224 /**********************************************************************
1225 * xrenderdrv_CreateCompatibleDC
1227 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1229 if (orig) /* chain to x11drv first */
1231 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1232 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1234 /* otherwise we have been called by x11drv */
1236 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1239 /**********************************************************************
1240 * xrenderdrv_DeleteDC
1242 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1244 struct xrender_physdev *physdev = get_xrender_dev( dev );
1246 free_xrender_picture( physdev );
1248 EnterCriticalSection( &xrender_cs );
1249 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1250 LeaveCriticalSection( &xrender_cs );
1252 HeapFree( GetProcessHeap(), 0, physdev );
1253 return TRUE;
1256 /**********************************************************************
1257 * xrenderdrv_ExtEscape
1259 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1260 INT out_count, LPVOID out_data )
1262 struct xrender_physdev *physdev = get_xrender_dev( dev );
1264 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1266 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1268 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1270 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1271 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1272 return ret;
1275 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1278 /****************************************************************************
1279 * xrenderdrv_CreateBitmap
1281 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1283 enum wxr_format format;
1284 BITMAP bitmap;
1286 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1288 if (bitmap.bmPlanes != 1) return FALSE;
1289 format = get_bitmap_format( bitmap.bmBitsPixel );
1291 if (pict_formats[format])
1292 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1293 TRUE, &wxr_color_shifts[format] );
1295 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1296 return dev->funcs->pCreateBitmap( dev, hbitmap );
1299 /****************************************************************************
1300 * xrenderdrv_DeleteBitmap
1302 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1304 return X11DRV_DeleteBitmap( hbitmap );
1307 /***********************************************************************
1308 * xrenderdrv_SelectBitmap
1310 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1312 HBITMAP ret;
1313 struct xrender_physdev *physdev = get_xrender_dev( dev );
1315 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1316 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1317 if (ret)
1319 free_xrender_picture( physdev );
1320 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1321 physdev->x11dev->color_shifts );
1322 physdev->pict_format = pict_formats[physdev->format];
1324 return ret;
1327 /***********************************************************************
1328 * xrenderdrv_GetImage
1330 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1331 struct gdi_image_bits *bits, struct bitblt_coords *src )
1333 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1334 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1335 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1338 /***********************************************************************
1339 * xrenderdrv_SetDeviceClipping
1341 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1343 struct xrender_physdev *physdev = get_xrender_dev( dev );
1345 physdev->update_clip = TRUE;
1347 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1348 dev->funcs->pSetDeviceClipping( dev, vis_rgn, clip_rgn );
1352 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1354 XRenderPictFormat *pict_format;
1355 ColorShifts shifts;
1356 const DWORD *bitfields;
1357 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1358 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1361 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1362 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1363 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1364 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1365 return FALSE;
1367 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1368 bitfields = dib->dsBitfields;
1369 else if(bits_pixel == 24 || bits_pixel == 32)
1370 bitfields = bitfields_32;
1371 else
1372 bitfields = bitfields_16;
1374 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1375 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1377 /* Common formats should be in our picture format table. */
1378 if (!pict_format)
1380 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1381 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1382 return FALSE;
1385 physBitmap->depth = pict_format->depth;
1386 physBitmap->trueColor = TRUE;
1387 physBitmap->color_shifts = shifts;
1388 return TRUE;
1391 /************************************************************************
1392 * UploadGlyph
1394 * Helper to ExtTextOut. Must be called inside xrender_cs
1396 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1398 unsigned int buflen;
1399 char *buf;
1400 Glyph gid;
1401 GLYPHMETRICS gm;
1402 XGlyphInfo gi;
1403 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1404 gsCacheEntryFormat *formatEntry;
1405 UINT ggo_format = GGO_GLYPH_INDEX;
1406 enum wxr_format wxr_format;
1407 static const char zero[4];
1408 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1410 switch(format) {
1411 case AA_Grey:
1412 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1413 break;
1414 case AA_RGB:
1415 ggo_format |= WINE_GGO_HRGB_BITMAP;
1416 break;
1417 case AA_BGR:
1418 ggo_format |= WINE_GGO_HBGR_BITMAP;
1419 break;
1420 case AA_VRGB:
1421 ggo_format |= WINE_GGO_VRGB_BITMAP;
1422 break;
1423 case AA_VBGR:
1424 ggo_format |= WINE_GGO_VBGR_BITMAP;
1425 break;
1427 default:
1428 ERR("aa = %d - not implemented\n", format);
1429 case AA_None:
1430 ggo_format |= GGO_BITMAP;
1431 break;
1434 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1435 if(buflen == GDI_ERROR) {
1436 if(format != AA_None) {
1437 format = AA_None;
1438 entry->aa_default = AA_None;
1439 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1440 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1442 if(buflen == GDI_ERROR) {
1443 WARN("GetGlyphOutlineW failed using default glyph\n");
1444 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1445 if(buflen == GDI_ERROR) {
1446 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1447 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1448 if(buflen == GDI_ERROR) {
1449 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1450 return;
1454 TRACE("Turning off antialiasing for this monochrome font\n");
1457 /* If there is nothing for the current type, we create the entry. */
1458 if( !entry->format[format] ) {
1459 entry->format[format] = HeapAlloc(GetProcessHeap(),
1460 HEAP_ZERO_MEMORY,
1461 sizeof(gsCacheEntryFormat));
1463 formatEntry = entry->format[format];
1465 if(formatEntry->nrealized <= glyph) {
1466 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1468 if (formatEntry->realized)
1469 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1470 HEAP_ZERO_MEMORY,
1471 formatEntry->realized,
1472 formatEntry->nrealized * sizeof(BOOL));
1473 else
1474 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1475 HEAP_ZERO_MEMORY,
1476 formatEntry->nrealized * sizeof(BOOL));
1478 if(!X11DRV_XRender_Installed) {
1479 if (formatEntry->bitmaps)
1480 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1481 HEAP_ZERO_MEMORY,
1482 formatEntry->bitmaps,
1483 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1484 else
1485 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1486 HEAP_ZERO_MEMORY,
1487 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1489 if (formatEntry->gis)
1490 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1491 HEAP_ZERO_MEMORY,
1492 formatEntry->gis,
1493 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1494 else
1495 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1496 HEAP_ZERO_MEMORY,
1497 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1501 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1502 switch(format) {
1503 case AA_Grey:
1504 wxr_format = WXR_FORMAT_GRAY;
1505 break;
1507 case AA_RGB:
1508 case AA_BGR:
1509 case AA_VRGB:
1510 case AA_VBGR:
1511 wxr_format = WXR_FORMAT_A8R8G8B8;
1512 break;
1514 default:
1515 ERR("aa = %d - not implemented\n", format);
1516 case AA_None:
1517 wxr_format = WXR_FORMAT_MONO;
1518 break;
1521 wine_tsx11_lock();
1522 formatEntry->font_format = pict_formats[wxr_format];
1523 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1524 wine_tsx11_unlock();
1528 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1529 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1530 formatEntry->realized[glyph] = TRUE;
1532 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1533 buflen,
1534 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1535 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1537 gi.width = gm.gmBlackBoxX;
1538 gi.height = gm.gmBlackBoxY;
1539 gi.x = -gm.gmptGlyphOrigin.x;
1540 gi.y = gm.gmptGlyphOrigin.y;
1541 gi.xOff = gm.gmCellIncX;
1542 gi.yOff = gm.gmCellIncY;
1544 if(TRACE_ON(xrender)) {
1545 int pitch, i, j;
1546 char output[300];
1547 unsigned char *line;
1549 if(format == AA_None) {
1550 pitch = ((gi.width + 31) / 32) * 4;
1551 for(i = 0; i < gi.height; i++) {
1552 line = (unsigned char*) buf + i * pitch;
1553 output[0] = '\0';
1554 for(j = 0; j < pitch * 8; j++) {
1555 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1557 TRACE("%s\n", output);
1559 } else {
1560 static const char blks[] = " .:;!o*#";
1561 char str[2];
1563 str[1] = '\0';
1564 pitch = ((gi.width + 3) / 4) * 4;
1565 for(i = 0; i < gi.height; i++) {
1566 line = (unsigned char*) buf + i * pitch;
1567 output[0] = '\0';
1568 for(j = 0; j < pitch; j++) {
1569 str[0] = blks[line[j] >> 5];
1570 strcat(output, str);
1572 TRACE("%s\n", output);
1578 if(formatEntry->glyphset) {
1579 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1580 unsigned char *byte = (unsigned char*) buf, c;
1581 int i = buflen;
1583 while(i--) {
1584 c = *byte;
1586 /* magic to flip bit order */
1587 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1588 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1589 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1591 *byte++ = c;
1594 else if ( format != AA_Grey &&
1595 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1597 unsigned int i, *data = (unsigned int *)buf;
1598 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1600 gid = glyph;
1603 XRenderCompositeText seems to ignore 0x0 glyphs when
1604 AA_None, which means we lose the advance width of glyphs
1605 like the space. We'll pretend that such glyphs are 1x1
1606 bitmaps.
1609 if(buflen == 0)
1610 gi.width = gi.height = 1;
1612 wine_tsx11_lock();
1613 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1614 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1615 wine_tsx11_unlock();
1616 HeapFree(GetProcessHeap(), 0, buf);
1617 } else {
1618 formatEntry->bitmaps[glyph] = buf;
1621 formatEntry->gis[glyph] = gi;
1624 static void SharpGlyphMono(struct xrender_physdev *physDev, INT x, INT y,
1625 void *bitmap, XGlyphInfo *gi)
1627 unsigned char *srcLine = bitmap, *src;
1628 unsigned char bits, bitsMask;
1629 int width = gi->width;
1630 int stride = ((width + 31) & ~31) >> 3;
1631 int height = gi->height;
1632 int w;
1633 int xspan, lenspan;
1635 TRACE("%d, %d\n", x, y);
1636 x -= gi->x;
1637 y -= gi->y;
1638 while (height--)
1640 src = srcLine;
1641 srcLine += stride;
1642 w = width;
1644 bitsMask = 0x80; /* FreeType is always MSB first */
1645 bits = *src++;
1647 xspan = x;
1648 while (w)
1650 if (bits & bitsMask)
1652 lenspan = 0;
1655 lenspan++;
1656 if (lenspan == w)
1657 break;
1658 bitsMask = bitsMask >> 1;
1659 if (!bitsMask)
1661 bits = *src++;
1662 bitsMask = 0x80;
1664 } while (bits & bitsMask);
1665 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1666 physDev->x11dev->gc, xspan, y, lenspan, 1);
1667 xspan += lenspan;
1668 w -= lenspan;
1670 else
1674 w--;
1675 xspan++;
1676 if (!w)
1677 break;
1678 bitsMask = bitsMask >> 1;
1679 if (!bitsMask)
1681 bits = *src++;
1682 bitsMask = 0x80;
1684 } while (!(bits & bitsMask));
1687 y++;
1691 static void SharpGlyphGray(struct xrender_physdev *physDev, INT x, INT y,
1692 void *bitmap, XGlyphInfo *gi)
1694 unsigned char *srcLine = bitmap, *src, bits;
1695 int width = gi->width;
1696 int stride = ((width + 3) & ~3);
1697 int height = gi->height;
1698 int w;
1699 int xspan, lenspan;
1701 x -= gi->x;
1702 y -= gi->y;
1703 while (height--)
1705 src = srcLine;
1706 srcLine += stride;
1707 w = width;
1709 bits = *src++;
1710 xspan = x;
1711 while (w)
1713 if (bits >= 0x80)
1715 lenspan = 0;
1718 lenspan++;
1719 if (lenspan == w)
1720 break;
1721 bits = *src++;
1722 } while (bits >= 0x80);
1723 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1724 physDev->x11dev->gc, xspan, y, lenspan, 1);
1725 xspan += lenspan;
1726 w -= lenspan;
1728 else
1732 w--;
1733 xspan++;
1734 if (!w)
1735 break;
1736 bits = *src++;
1737 } while (bits < 0x80);
1740 y++;
1745 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1747 int s, l;
1749 s = 0;
1750 while ((mask & 1) == 0)
1752 mask >>= 1;
1753 s++;
1755 l = 0;
1756 while ((mask & 1) == 1)
1758 mask >>= 1;
1759 l++;
1761 *shift = s;
1762 *len = l;
1765 static DWORD GetField (DWORD pixel, int shift, int len)
1767 pixel = pixel & (((1 << (len)) - 1) << shift);
1768 pixel = pixel << (32 - (shift + len)) >> 24;
1769 while (len < 8)
1771 pixel |= (pixel >> len);
1772 len <<= 1;
1774 return pixel;
1778 static DWORD PutField (DWORD pixel, int shift, int len)
1780 shift = shift - (8 - len);
1781 if (len <= 8)
1782 pixel &= (((1 << len) - 1) << (8 - len));
1783 if (shift < 0)
1784 pixel >>= -shift;
1785 else
1786 pixel <<= shift;
1787 return pixel;
1790 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1791 int color)
1793 int r_shift, r_len;
1794 int g_shift, g_len;
1795 int b_shift, b_len;
1796 BYTE *maskLine, *mask, m;
1797 int maskStride;
1798 DWORD pixel;
1799 int width, height;
1800 int w, tx;
1801 BYTE src_r, src_g, src_b;
1803 x -= gi->x;
1804 y -= gi->y;
1805 width = gi->width;
1806 height = gi->height;
1808 maskLine = bitmap;
1809 maskStride = (width + 3) & ~3;
1811 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1812 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1813 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1815 src_r = GetField(color, r_shift, r_len);
1816 src_g = GetField(color, g_shift, g_len);
1817 src_b = GetField(color, b_shift, b_len);
1819 for(; height--; y++)
1821 mask = maskLine;
1822 maskLine += maskStride;
1823 w = width;
1824 tx = x;
1826 if(y < 0) continue;
1827 if(y >= image->height) break;
1829 for(; w--; tx++)
1831 if(tx >= image->width) break;
1833 m = *mask++;
1834 if(tx < 0) continue;
1836 if (m == 0xff)
1837 XPutPixel (image, tx, y, color);
1838 else if (m)
1840 BYTE r, g, b;
1842 pixel = XGetPixel (image, tx, y);
1844 r = GetField(pixel, r_shift, r_len);
1845 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1846 g = GetField(pixel, g_shift, g_len);
1847 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1848 b = GetField(pixel, b_shift, b_len);
1849 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1851 pixel = (PutField (r, r_shift, r_len) |
1852 PutField (g, g_shift, g_len) |
1853 PutField (b, b_shift, b_len));
1854 XPutPixel (image, tx, y, pixel);
1860 /*************************************************************
1861 * get_tile_pict
1863 * Returns an appropriate Picture for tiling the text colour.
1864 * Call and use result within the xrender_cs
1866 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1868 static struct
1870 Pixmap xpm;
1871 Picture pict;
1872 XRenderColor current_color;
1873 } tiles[WXR_NB_FORMATS], *tile;
1875 tile = &tiles[wxr_format];
1877 if(!tile->xpm)
1879 XRenderPictureAttributes pa;
1880 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1882 wine_tsx11_lock();
1883 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1885 pa.repeat = RepeatNormal;
1886 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1887 wine_tsx11_unlock();
1889 /* init current_color to something different from text_pixel */
1890 tile->current_color = *color;
1891 tile->current_color.red ^= 0xffff;
1893 if (wxr_format == WXR_FORMAT_MONO)
1895 /* for a 1bpp bitmap we always need a 1 in the tile */
1896 XRenderColor col;
1897 col.red = col.green = col.blue = 0;
1898 col.alpha = 0xffff;
1899 wine_tsx11_lock();
1900 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1901 wine_tsx11_unlock();
1905 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1907 wine_tsx11_lock();
1908 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1909 wine_tsx11_unlock();
1910 tile->current_color = *color;
1912 return tile->pict;
1915 /*************************************************************
1916 * get_mask_pict
1918 * Returns an appropriate Picture for masking with the specified alpha.
1919 * Call and use result within the xrender_cs
1921 static Picture get_mask_pict( int alpha )
1923 static Pixmap pixmap;
1924 static Picture pict;
1925 static int current_alpha;
1927 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1929 if (!pixmap)
1931 XRenderPictureAttributes pa;
1933 wine_tsx11_lock();
1934 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1935 pa.repeat = RepeatNormal;
1936 pict = pXRenderCreatePicture( gdi_display, pixmap,
1937 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1938 wine_tsx11_unlock();
1939 current_alpha = -1;
1942 if (alpha != current_alpha)
1944 XRenderColor col;
1945 col.red = col.green = col.blue = 0;
1946 col.alpha = current_alpha = alpha;
1947 wine_tsx11_lock();
1948 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1949 wine_tsx11_unlock();
1951 return pict;
1954 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1956 return 1;
1959 /********************************************************************
1960 * is_dib_with_colortable
1962 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1964 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1966 DIBSECTION dib;
1968 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1969 dib.dsBmih.biBitCount <= 8 )
1970 return TRUE;
1972 return FALSE;
1975 /***********************************************************************
1976 * xrenderdrv_ExtTextOut
1978 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1979 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1981 struct xrender_physdev *physdev = get_xrender_dev( dev );
1982 XGCValues xgcval;
1983 gsCacheEntry *entry;
1984 gsCacheEntryFormat *formatEntry;
1985 BOOL retv = FALSE;
1986 int textPixel, backgroundPixel;
1987 RGNDATA *saved_region = NULL;
1988 BOOL disable_antialias = FALSE;
1989 AA_Type aa_type = AA_None;
1990 unsigned int idx;
1991 Picture tile_pict = 0;
1993 if (!physdev->x11dev->has_gdi_font)
1995 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1996 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1999 if(is_dib_with_colortable( physdev->x11dev ))
2001 TRACE("Disabling antialiasing\n");
2002 disable_antialias = TRUE;
2005 xgcval.function = GXcopy;
2006 xgcval.background = physdev->x11dev->backgroundPixel;
2007 xgcval.fill_style = FillSolid;
2008 wine_tsx11_lock();
2009 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
2010 wine_tsx11_unlock();
2012 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2014 if(physdev->x11dev->depth == 1) {
2015 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
2016 textPixel = 0;
2017 backgroundPixel = 1;
2018 } else {
2019 textPixel = 1;
2020 backgroundPixel = 0;
2022 } else {
2023 textPixel = physdev->x11dev->textPixel;
2024 backgroundPixel = physdev->x11dev->backgroundPixel;
2027 if(flags & ETO_OPAQUE)
2029 wine_tsx11_lock();
2030 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
2031 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
2032 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
2033 lprect->right - lprect->left, lprect->bottom - lprect->top );
2034 wine_tsx11_unlock();
2037 if(count == 0)
2039 retv = TRUE;
2040 goto done_unlock;
2043 EnterCriticalSection(&xrender_cs);
2045 entry = glyphsetCache + physdev->cache_index;
2046 if( disable_antialias == FALSE )
2047 aa_type = entry->aa_default;
2048 formatEntry = entry->format[aa_type];
2050 for(idx = 0; idx < count; idx++) {
2051 if( !formatEntry ) {
2052 UploadGlyph(physdev, wstr[idx], aa_type);
2053 /* re-evaluate antialias since aa_default may have changed */
2054 if( disable_antialias == FALSE )
2055 aa_type = entry->aa_default;
2056 formatEntry = entry->format[aa_type];
2057 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
2058 UploadGlyph(physdev, wstr[idx], aa_type);
2061 if (!formatEntry)
2063 WARN("could not upload requested glyphs\n");
2064 LeaveCriticalSection(&xrender_cs);
2065 goto done_unlock;
2068 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
2069 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2071 if(X11DRV_XRender_Installed)
2073 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
2074 POINT offset = {0, 0};
2075 POINT desired, current;
2076 int render_op = PictOpOver;
2077 Picture pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
2078 XRenderColor col;
2080 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2081 So we pass zeros to the function and move to our starting position using the first
2082 element of the elts array. */
2084 desired.x = physdev->x11dev->dc_rect.left + x;
2085 desired.y = physdev->x11dev->dc_rect.top + y;
2086 current.x = current.y = 0;
2088 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
2089 tile_pict = get_tile_pict(physdev->format, &col);
2091 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2093 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
2094 render_op = PictOpOutReverse; /* This gives us 'black' text */
2096 for(idx = 0; idx < count; idx++)
2098 elts[idx].glyphset = formatEntry->glyphset;
2099 elts[idx].chars = wstr + idx;
2100 elts[idx].nchars = 1;
2101 elts[idx].xOff = desired.x - current.x;
2102 elts[idx].yOff = desired.y - current.y;
2104 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
2105 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
2107 if(!lpDx)
2109 desired.x += formatEntry->gis[wstr[idx]].xOff;
2110 desired.y += formatEntry->gis[wstr[idx]].yOff;
2112 else
2114 if(flags & ETO_PDY)
2116 offset.x += lpDx[idx * 2];
2117 offset.y += lpDx[idx * 2 + 1];
2119 else
2120 offset.x += lpDx[idx];
2121 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
2122 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
2126 wine_tsx11_lock();
2127 /* Make sure we don't have any transforms set from a previous call */
2128 set_xrender_transformation(pict, 1, 1, 0, 0);
2129 pXRenderCompositeText16(gdi_display, render_op,
2130 tile_pict,
2131 pict,
2132 formatEntry->font_format,
2133 0, 0, 0, 0, elts, count);
2134 wine_tsx11_unlock();
2135 HeapFree(GetProcessHeap(), 0, elts);
2136 } else {
2137 POINT offset = {0, 0};
2139 if (flags & ETO_CLIPPED)
2141 HRGN clip_region = CreateRectRgnIndirect( lprect );
2142 saved_region = add_extra_clipping_region( physdev->x11dev, clip_region );
2143 DeleteObject( clip_region );
2146 wine_tsx11_lock();
2147 XSetForeground( gdi_display, physdev->x11dev->gc, textPixel );
2149 if(aa_type == AA_None || physdev->x11dev->depth == 1)
2151 void (* sharp_glyph_fn)(struct xrender_physdev *, INT, INT, void *, XGlyphInfo *);
2153 if(aa_type == AA_None)
2154 sharp_glyph_fn = SharpGlyphMono;
2155 else
2156 sharp_glyph_fn = SharpGlyphGray;
2158 for(idx = 0; idx < count; idx++) {
2159 sharp_glyph_fn(physdev,
2160 physdev->x11dev->dc_rect.left + x + offset.x,
2161 physdev->x11dev->dc_rect.top + y + offset.y,
2162 formatEntry->bitmaps[wstr[idx]],
2163 &formatEntry->gis[wstr[idx]]);
2164 if(lpDx)
2166 if(flags & ETO_PDY)
2168 offset.x += lpDx[idx * 2];
2169 offset.y += lpDx[idx * 2 + 1];
2171 else
2172 offset.x += lpDx[idx];
2174 else
2176 offset.x += formatEntry->gis[wstr[idx]].xOff;
2177 offset.y += formatEntry->gis[wstr[idx]].yOff;
2180 } else {
2181 XImage *image;
2182 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2183 RECT extents = {0, 0, 0, 0};
2184 POINT cur = {0, 0};
2185 int w = physdev->x11dev->drawable_rect.right - physdev->x11dev->drawable_rect.left;
2186 int h = physdev->x11dev->drawable_rect.bottom - physdev->x11dev->drawable_rect.top;
2188 TRACE("drawable %dx%d\n", w, h);
2190 for(idx = 0; idx < count; idx++) {
2191 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2192 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2193 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2194 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2195 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2196 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2197 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2198 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2200 if(lpDx)
2202 if(flags & ETO_PDY)
2204 cur.x += lpDx[idx * 2];
2205 cur.y += lpDx[idx * 2 + 1];
2207 else
2208 cur.x += lpDx[idx];
2210 else
2212 cur.x += formatEntry->gis[wstr[idx]].xOff;
2213 cur.y += formatEntry->gis[wstr[idx]].yOff;
2216 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2217 extents.right, extents.bottom, physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2219 if(physdev->x11dev->dc_rect.left + x + extents.left >= 0) {
2220 image_x = physdev->x11dev->dc_rect.left + x + extents.left;
2221 image_off_x = 0;
2222 } else {
2223 image_x = 0;
2224 image_off_x = physdev->x11dev->dc_rect.left + x + extents.left;
2226 if(physdev->x11dev->dc_rect.top + y + extents.top >= 0) {
2227 image_y = physdev->x11dev->dc_rect.top + y + extents.top;
2228 image_off_y = 0;
2229 } else {
2230 image_y = 0;
2231 image_off_y = physdev->x11dev->dc_rect.top + y + extents.top;
2233 if(physdev->x11dev->dc_rect.left + x + extents.right < w)
2234 image_w = physdev->x11dev->dc_rect.left + x + extents.right - image_x;
2235 else
2236 image_w = w - image_x;
2237 if(physdev->x11dev->dc_rect.top + y + extents.bottom < h)
2238 image_h = physdev->x11dev->dc_rect.top + y + extents.bottom - image_y;
2239 else
2240 image_h = h - image_y;
2242 if(image_w <= 0 || image_h <= 0) goto no_image;
2244 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2245 image = XGetImage(gdi_display, physdev->x11dev->drawable,
2246 image_x, image_y, image_w, image_h,
2247 AllPlanes, ZPixmap);
2248 X11DRV_check_error();
2250 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2251 gdi_display, (int)physdev->x11dev->drawable, image_x, image_y,
2252 image_w, image_h, AllPlanes, ZPixmap,
2253 physdev->x11dev->depth, image);
2254 if(!image) {
2255 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2256 physdev->x11dev->depth);
2257 GC gc;
2258 XGCValues gcv;
2260 gcv.graphics_exposures = False;
2261 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2262 XCopyArea(gdi_display, physdev->x11dev->drawable, xpm, gc, image_x, image_y,
2263 image_w, image_h, 0, 0);
2264 XFreeGC(gdi_display, gc);
2265 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2266 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2267 ZPixmap);
2268 X11DRV_check_error();
2269 XFreePixmap(gdi_display, xpm);
2271 if(!image) goto no_image;
2273 image->red_mask = visual->red_mask;
2274 image->green_mask = visual->green_mask;
2275 image->blue_mask = visual->blue_mask;
2277 for(idx = 0; idx < count; idx++) {
2278 SmoothGlyphGray(image,
2279 offset.x + image_off_x - extents.left,
2280 offset.y + image_off_y - extents.top,
2281 formatEntry->bitmaps[wstr[idx]],
2282 &formatEntry->gis[wstr[idx]],
2283 physdev->x11dev->textPixel);
2284 if(lpDx)
2286 if(flags & ETO_PDY)
2288 offset.x += lpDx[idx * 2];
2289 offset.y += lpDx[idx * 2 + 1];
2291 else
2292 offset.x += lpDx[idx];
2294 else
2296 offset.x += formatEntry->gis[wstr[idx]].xOff;
2297 offset.y += formatEntry->gis[wstr[idx]].yOff;
2300 XPutImage(gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc, image, 0, 0,
2301 image_x, image_y, image_w, image_h);
2302 XDestroyImage(image);
2304 no_image:
2305 wine_tsx11_unlock();
2306 restore_clipping_region( physdev->x11dev, saved_region );
2308 LeaveCriticalSection(&xrender_cs);
2309 retv = TRUE;
2311 done_unlock:
2312 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2313 return retv;
2316 /* multiply the alpha channel of a picture */
2317 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
2318 int x, int y, int width, int height )
2320 XRenderPictureAttributes pa;
2321 Pixmap src_pixmap, mask_pixmap;
2322 Picture src_pict, mask_pict;
2323 XRenderColor color;
2325 wine_tsx11_lock();
2326 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2327 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2328 pa.repeat = RepeatNormal;
2329 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
2330 pa.component_alpha = True;
2331 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
2332 color.red = color.green = color.blue = color.alpha = 0xffff;
2333 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
2334 color.alpha = alpha;
2335 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
2336 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
2337 0, 0, 0, 0, x, y, width, height );
2338 pXRenderFreePicture( gdi_display, src_pict );
2339 pXRenderFreePicture( gdi_display, mask_pict );
2340 XFreePixmap( gdi_display, src_pixmap );
2341 XFreePixmap( gdi_display, mask_pixmap );
2342 wine_tsx11_unlock();
2345 /* Helper function for (stretched) blitting using xrender */
2346 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2347 int x_src, int y_src, int x_dst, int y_dst,
2348 double xscale, double yscale, int width, int height )
2350 int x_offset, y_offset;
2352 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2353 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2354 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2355 wine_tsx11_lock();
2356 if(xscale != 1.0 || yscale != 1.0)
2358 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2359 * in the wrong quadrant of the x-y plane.
2361 x_offset = (xscale < 0) ? -width : 0;
2362 y_offset = (yscale < 0) ? -height : 0;
2363 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2365 else
2367 x_offset = x_src;
2368 y_offset = y_src;
2369 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2371 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2372 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2373 wine_tsx11_unlock();
2376 /* Helper function for (stretched) mono->color blitting using xrender */
2377 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
2378 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
2379 int x_src, int y_src, int x_dst, int y_dst,
2380 double xscale, double yscale, int width, int height )
2382 Picture tile_pict;
2383 int x_offset, y_offset;
2384 XRenderColor color;
2386 /* When doing a mono->color blit, the source data is used as mask, and the source picture
2387 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
2388 * the tile data.
2390 EnterCriticalSection( &xrender_cs );
2391 color = *bg;
2392 color.alpha = 0xffff; /* tile pict needs 100% alpha */
2393 tile_pict = get_tile_pict( dst_format, &color );
2395 wine_tsx11_lock();
2396 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
2398 if (xscale != 1.0 || yscale != 1.0)
2400 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2401 * in the wrong quadrant of the x-y plane.
2403 x_offset = (xscale < 0) ? -width : 0;
2404 y_offset = (yscale < 0) ? -height : 0;
2405 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2407 else
2409 x_offset = x_src;
2410 y_offset = y_src;
2411 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2413 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
2414 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
2415 wine_tsx11_unlock();
2416 LeaveCriticalSection( &xrender_cs );
2418 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
2419 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
2420 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
2423 /* create a pixmap and render picture for an image */
2424 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
2425 struct bitblt_coords *src, enum wxr_format format,
2426 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
2428 DWORD ret;
2429 int width = src->visrect.right - src->visrect.left;
2430 int height = src->visrect.bottom - src->visrect.top;
2431 int depth = pict_formats[format]->depth;
2432 struct gdi_image_bits dst_bits;
2433 XRenderPictureAttributes pa;
2434 XImage *image;
2436 wine_tsx11_lock();
2437 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2438 info->bmiHeader.biWidth, height, 32, 0 );
2439 wine_tsx11_unlock();
2440 if (!image) return ERROR_OUTOFMEMORY;
2442 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2443 if (ret) return ret;
2445 image->data = dst_bits.ptr;
2446 /* hack: make sure the bits are readable if we are reading from a DIB section */
2447 /* to be removed once we get rid of DIB access protections */
2448 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2450 *use_repeat = (width == 1 && height == 1);
2451 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2453 wine_tsx11_lock();
2454 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2455 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2456 src->visrect.left, 0, 0, 0, width, height );
2457 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2458 wine_tsx11_unlock();
2460 /* make coordinates relative to the pixmap */
2461 src->x -= src->visrect.left;
2462 src->y -= src->visrect.top;
2463 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2465 image->data = NULL;
2466 wine_tsx11_lock();
2467 XDestroyImage( image );
2468 wine_tsx11_unlock();
2469 if (dst_bits.free) dst_bits.free( &dst_bits );
2470 return ret;
2473 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2474 Drawable drawable, const struct bitblt_coords *src,
2475 const struct bitblt_coords *dst )
2477 int width = abs( dst->width );
2478 int height = abs( dst->height );
2479 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2480 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2481 int x_dst, y_dst;
2482 Picture src_pict = 0, dst_pict, mask_pict = 0;
2483 BOOL use_repeat;
2484 double xscale, yscale;
2486 use_repeat = use_source_repeat( physdev_src );
2487 if (!use_repeat)
2489 xscale = src->width / (double)dst->width;
2490 yscale = src->height / (double)dst->height;
2492 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2494 if (drawable) /* using an intermediate pixmap */
2496 XRenderPictureAttributes pa;
2498 x_dst = dst->x;
2499 y_dst = dst->y;
2500 pa.repeat = RepeatNone;
2501 wine_tsx11_lock();
2502 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2503 wine_tsx11_unlock();
2505 else
2507 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2508 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2509 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2512 if (src->width < 0) x_src += src->width + 1;
2513 if (src->height < 0) y_src += src->height + 1;
2514 if (dst->width < 0) x_dst += dst->width + 1;
2515 if (dst->height < 0) y_dst += dst->height + 1;
2517 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2519 /* mono -> color */
2520 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2522 XRenderColor fg, bg;
2524 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, &fg );
2525 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, &bg );
2526 fg.alpha = bg.alpha = 0;
2528 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2529 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2531 else /* color -> color (can be at different depths) or mono -> mono */
2533 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2534 mask_pict = get_no_alpha_mask();
2536 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2537 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2540 if (drawable)
2542 wine_tsx11_lock();
2543 pXRenderFreePicture( gdi_display, dst_pict );
2544 wine_tsx11_unlock();
2549 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2550 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2551 Drawable drawable, struct bitblt_coords *src,
2552 struct bitblt_coords *dst, BOOL use_repeat )
2554 int x_src, y_src, x_dst, y_dst;
2555 Picture dst_pict;
2556 XRenderPictureAttributes pa;
2557 double xscale, yscale;
2559 if (drawable) /* using an intermediate pixmap */
2561 RGNDATA *clip_data = NULL;
2563 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2564 x_dst = dst->x;
2565 y_dst = dst->y;
2566 pa.repeat = RepeatNone;
2567 wine_tsx11_lock();
2568 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2569 if (clip_data)
2570 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2571 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2572 wine_tsx11_unlock();
2573 HeapFree( GetProcessHeap(), 0, clip_data );
2575 else
2577 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2578 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2579 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2582 if (!use_repeat)
2584 xscale = src->width / (double)dst->width;
2585 yscale = src->height / (double)dst->height;
2587 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2589 x_src = src->x;
2590 y_src = src->y;
2591 if (src->width < 0) x_src += src->width + 1;
2592 if (src->height < 0) y_src += src->height + 1;
2593 if (dst->width < 0) x_dst += dst->width + 1;
2594 if (dst->height < 0) y_dst += dst->height + 1;
2596 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2597 xscale, yscale, abs( dst->width ), abs( dst->height ));
2599 if (drawable)
2601 wine_tsx11_lock();
2602 pXRenderFreePicture( gdi_display, dst_pict );
2603 wine_tsx11_unlock();
2608 /***********************************************************************
2609 * xrenderdrv_StretchBlt
2611 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2612 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2614 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2615 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2616 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2618 if (src_dev->funcs != dst_dev->funcs)
2620 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2621 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2624 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2626 /* XRender is of no use for color -> mono */
2627 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2628 goto x11drv_fallback;
2630 /* if not stretching, we only need to handle format conversion */
2631 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2633 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2634 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2636 if (rop != SRCCOPY)
2638 GC tmpGC;
2639 Pixmap tmp_pixmap;
2640 struct bitblt_coords tmp;
2642 /* make coordinates relative to tmp pixmap */
2643 tmp = *dst;
2644 tmp.x -= tmp.visrect.left;
2645 tmp.y -= tmp.visrect.top;
2646 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2648 wine_tsx11_lock();
2649 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2650 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2651 XSetGraphicsExposures( gdi_display, tmpGC, False );
2652 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2653 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2654 wine_tsx11_unlock();
2656 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2657 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2659 wine_tsx11_lock();
2660 XFreePixmap( gdi_display, tmp_pixmap );
2661 XFreeGC( gdi_display, tmpGC );
2662 wine_tsx11_unlock();
2664 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2666 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2667 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2668 return TRUE;
2670 x11drv_fallback:
2671 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2675 /***********************************************************************
2676 * xrenderdrv_PutImage
2678 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2679 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2680 struct bitblt_coords *dst, DWORD rop )
2682 struct xrender_physdev *physdev;
2683 X_PHYSBITMAP *bitmap;
2684 DWORD ret;
2685 Pixmap tmp_pixmap;
2686 GC gc;
2687 enum wxr_format src_format, dst_format;
2688 XRenderPictFormat *pict_format;
2689 Pixmap src_pixmap;
2690 Picture src_pict, mask_pict = 0;
2691 BOOL use_repeat;
2693 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2695 if (hbitmap)
2697 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2698 physdev = NULL;
2699 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2701 else
2703 physdev = get_xrender_dev( dev );
2704 bitmap = NULL;
2705 dst_format = physdev->format;
2708 src_format = get_xrender_format_from_bitmapinfo( info );
2709 if (!(pict_format = pict_formats[src_format])) goto update_format;
2711 /* make sure we can create an image with the same bpp */
2712 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2713 goto update_format;
2715 /* mono <-> color conversions not supported */
2716 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2717 goto x11drv_fallback;
2719 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2721 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2723 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2724 if (!ret)
2726 struct bitblt_coords tmp;
2728 if (bitmap)
2730 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2731 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2733 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2735 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2736 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2738 X11DRV_DIB_Unlock( bitmap, TRUE );
2739 DeleteObject( rgn );
2741 else
2743 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2745 if (rop != SRCCOPY)
2747 RGNDATA *clip_data = NULL;
2749 /* make coordinates relative to tmp pixmap */
2750 tmp = *dst;
2751 tmp.x -= tmp.visrect.left;
2752 tmp.y -= tmp.visrect.top;
2753 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2755 if (clip) clip_data = add_extra_clipping_region( physdev->x11dev, clip );
2757 wine_tsx11_lock();
2758 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2759 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2760 XSetGraphicsExposures( gdi_display, gc, False );
2761 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2762 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2763 wine_tsx11_unlock();
2765 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2766 NULL, tmp_pixmap, src, &tmp, use_repeat );
2767 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2769 wine_tsx11_lock();
2770 XFreePixmap( gdi_display, tmp_pixmap );
2771 XFreeGC( gdi_display, gc );
2772 wine_tsx11_unlock();
2774 restore_clipping_region( physdev->x11dev, clip_data );
2776 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2777 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2779 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2782 wine_tsx11_lock();
2783 pXRenderFreePicture( gdi_display, src_pict );
2784 XFreePixmap( gdi_display, src_pixmap );
2785 wine_tsx11_unlock();
2787 return ret;
2789 update_format:
2790 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2791 set_color_info( pict_formats[dst_format], info );
2792 return ERROR_BAD_FORMAT;
2794 x11drv_fallback:
2795 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2796 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2797 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2801 /***********************************************************************
2802 * xrenderdrv_BlendImage
2804 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2805 struct bitblt_coords *src, struct bitblt_coords *dst,
2806 BLENDFUNCTION func )
2808 struct xrender_physdev *physdev = get_xrender_dev( dev );
2809 DWORD ret;
2810 enum wxr_format format;
2811 XRenderPictFormat *pict_format;
2812 Picture dst_pict, src_pict, mask_pict;
2813 Pixmap src_pixmap;
2814 BOOL use_repeat;
2816 if (!X11DRV_XRender_Installed)
2818 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2819 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2822 format = get_xrender_format_from_bitmapinfo( info );
2823 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2824 format = get_format_without_alpha( format );
2825 else if (format != WXR_FORMAT_A8R8G8B8)
2826 return ERROR_INVALID_PARAMETER;
2828 if (!(pict_format = pict_formats[format])) goto update_format;
2830 /* make sure we can create an image with the same bpp */
2831 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2832 goto update_format;
2834 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2835 goto update_format;
2837 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2839 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2840 if (!ret)
2842 double xscale, yscale;
2844 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2846 if (!use_repeat)
2848 xscale = src->width / (double)dst->width;
2849 yscale = src->height / (double)dst->height;
2851 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2853 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2855 EnterCriticalSection( &xrender_cs );
2856 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2858 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2859 physdev->x11dev->dc_rect.left + dst->x,
2860 physdev->x11dev->dc_rect.top + dst->y,
2861 xscale, yscale, dst->width, dst->height );
2863 wine_tsx11_lock();
2864 pXRenderFreePicture( gdi_display, src_pict );
2865 XFreePixmap( gdi_display, src_pixmap );
2866 wine_tsx11_unlock();
2868 LeaveCriticalSection( &xrender_cs );
2870 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2872 return ret;
2874 update_format:
2875 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2876 set_color_info( physdev->pict_format, info );
2877 return ERROR_BAD_FORMAT;
2881 /***********************************************************************
2882 * xrenderdrv_AlphaBlend
2884 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2885 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2887 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2888 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2889 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2890 XRenderPictureAttributes pa;
2891 Pixmap tmp_pixmap = 0;
2892 double xscale, yscale;
2893 BOOL use_repeat;
2895 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2897 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2898 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2901 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2903 SetLastError( ERROR_INVALID_PARAMETER );
2904 return FALSE;
2907 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2908 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2910 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2912 use_repeat = use_source_repeat( physdev_src );
2913 if (!use_repeat)
2915 xscale = src->width / (double)dst->width;
2916 yscale = src->height / (double)dst->height;
2918 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2920 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2922 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2924 /* mono -> color blending needs an intermediate color pixmap */
2925 XRenderColor fg, bg;
2926 int width = src->visrect.right - src->visrect.left;
2927 int height = src->visrect.bottom - src->visrect.top;
2929 /* blending doesn't use the destination DC colors */
2930 fg.red = fg.green = fg.blue = 0;
2931 bg.red = bg.green = bg.blue = 0xffff;
2932 fg.alpha = bg.alpha = 0xffff;
2934 wine_tsx11_lock();
2935 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2936 physdev_dst->pict_format->depth );
2937 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2938 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2939 CPRepeat, &pa );
2940 wine_tsx11_unlock();
2942 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2943 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2945 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2947 /* we need a source picture with no alpha */
2948 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2949 if (format != physdev_src->format)
2951 wine_tsx11_lock();
2952 pa.subwindow_mode = IncludeInferiors;
2953 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2954 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2955 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2956 wine_tsx11_unlock();
2960 if (tmp_pict) src_pict = tmp_pict;
2962 EnterCriticalSection( &xrender_cs );
2963 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2965 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2966 physdev_src->x11dev->dc_rect.left + src->x,
2967 physdev_src->x11dev->dc_rect.top + src->y,
2968 physdev_dst->x11dev->dc_rect.left + dst->x,
2969 physdev_dst->x11dev->dc_rect.top + dst->y,
2970 xscale, yscale, dst->width, dst->height );
2972 wine_tsx11_lock();
2973 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2974 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2975 wine_tsx11_unlock();
2977 LeaveCriticalSection( &xrender_cs );
2978 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2979 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2980 return TRUE;
2983 /***********************************************************************
2984 * xrenderdrv_SelectBrush
2986 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, HBITMAP bitmap,
2987 const BITMAPINFO *info, void *bits, UINT usage )
2989 struct xrender_physdev *physdev = get_xrender_dev( dev );
2990 X_PHYSBITMAP *physbitmap;
2991 enum wxr_format format;
2992 BOOL delete_bitmap = FALSE;
2993 BITMAP bm;
2994 Pixmap pixmap;
2995 Picture src_pict, dst_pict;
2996 XRenderPictureAttributes pa;
2998 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2999 if (!bitmap && !info) goto x11drv_fallback;
3000 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
3002 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
3004 format = get_bitmap_format( info->bmiHeader.biBitCount );
3005 if (format == physdev->format || !pict_formats[format]) goto x11drv_fallback;
3006 if (!(bitmap = create_brush_bitmap( physdev->x11dev, info, bits, usage ))) return 0;
3007 physbitmap = X11DRV_get_phys_bitmap( bitmap );
3008 delete_bitmap = TRUE;
3010 else
3012 format = get_xrender_format_from_color_shifts( physbitmap->depth, &physbitmap->color_shifts );
3013 if (format == WXR_FORMAT_MONO || format == physdev->format || !pict_formats[format])
3014 goto x11drv_fallback;
3017 GetObjectW( bitmap, sizeof(bm), &bm );
3019 X11DRV_DIB_Lock( physbitmap, DIB_Status_GdiMod );
3021 wine_tsx11_lock();
3022 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
3023 physdev->pict_format->depth );
3025 pa.repeat = RepeatNone;
3026 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_formats[format], CPRepeat, &pa);
3027 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
3029 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, bm.bmWidth, bm.bmHeight );
3030 pXRenderFreePicture( gdi_display, src_pict );
3031 pXRenderFreePicture( gdi_display, dst_pict );
3033 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
3034 physdev->x11dev->brush.pixmap = pixmap;
3035 physdev->x11dev->brush.fillStyle = FillTiled;
3036 physdev->x11dev->brush.pixel = 0; /* ignored */
3037 wine_tsx11_unlock();
3039 X11DRV_DIB_Unlock( physbitmap, TRUE );
3040 if (delete_bitmap) DeleteObject( bitmap );
3041 return hbrush;
3043 x11drv_fallback:
3044 if (delete_bitmap) DeleteObject( bitmap );
3045 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
3046 return dev->funcs->pSelectBrush( dev, hbrush, bitmap, info, bits, usage );
3050 static const struct gdi_dc_funcs xrender_funcs =
3052 NULL, /* pAbortDoc */
3053 NULL, /* pAbortPath */
3054 xrenderdrv_AlphaBlend, /* pAlphaBlend */
3055 NULL, /* pAngleArc */
3056 NULL, /* pArc */
3057 NULL, /* pArcTo */
3058 NULL, /* pBeginPath */
3059 xrenderdrv_BlendImage, /* pBlendImage */
3060 NULL, /* pChoosePixelFormat */
3061 NULL, /* pChord */
3062 NULL, /* pCloseFigure */
3063 xrenderdrv_CreateBitmap, /* pCreateBitmap */
3064 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
3065 xrenderdrv_CreateDC, /* pCreateDC */
3066 NULL, /* pCreateDIBSection */
3067 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
3068 xrenderdrv_DeleteDC, /* pDeleteDC */
3069 NULL, /* pDeleteObject */
3070 NULL, /* pDescribePixelFormat */
3071 NULL, /* pDeviceCapabilities */
3072 NULL, /* pEllipse */
3073 NULL, /* pEndDoc */
3074 NULL, /* pEndPage */
3075 NULL, /* pEndPath */
3076 NULL, /* pEnumFonts */
3077 NULL, /* pEnumICMProfiles */
3078 NULL, /* pExcludeClipRect */
3079 NULL, /* pExtDeviceMode */
3080 xrenderdrv_ExtEscape, /* pExtEscape */
3081 NULL, /* pExtFloodFill */
3082 NULL, /* pExtSelectClipRgn */
3083 xrenderdrv_ExtTextOut, /* pExtTextOut */
3084 NULL, /* pFillPath */
3085 NULL, /* pFillRgn */
3086 NULL, /* pFlattenPath */
3087 NULL, /* pFontIsLinked */
3088 NULL, /* pFrameRgn */
3089 NULL, /* pGdiComment */
3090 NULL, /* pGdiRealizationInfo */
3091 NULL, /* pGetCharABCWidths */
3092 NULL, /* pGetCharABCWidthsI */
3093 NULL, /* pGetCharWidth */
3094 NULL, /* pGetDeviceCaps */
3095 NULL, /* pGetDeviceGammaRamp */
3096 NULL, /* pGetFontData */
3097 NULL, /* pGetFontUnicodeRanges */
3098 NULL, /* pGetGlyphIndices */
3099 NULL, /* pGetGlyphOutline */
3100 NULL, /* pGetICMProfile */
3101 xrenderdrv_GetImage, /* pGetImage */
3102 NULL, /* pGetKerningPairs */
3103 NULL, /* pGetNearestColor */
3104 NULL, /* pGetOutlineTextMetrics */
3105 NULL, /* pGetPixel */
3106 NULL, /* pGetPixelFormat */
3107 NULL, /* pGetSystemPaletteEntries */
3108 NULL, /* pGetTextCharsetInfo */
3109 NULL, /* pGetTextExtentExPoint */
3110 NULL, /* pGetTextExtentExPointI */
3111 NULL, /* pGetTextFace */
3112 NULL, /* pGetTextMetrics */
3113 NULL, /* pGradientFill */
3114 NULL, /* pIntersectClipRect */
3115 NULL, /* pInvertRgn */
3116 NULL, /* pLineTo */
3117 NULL, /* pModifyWorldTransform */
3118 NULL, /* pMoveTo */
3119 NULL, /* pOffsetClipRgn */
3120 NULL, /* pOffsetViewportOrg */
3121 NULL, /* pOffsetWindowOrg */
3122 NULL, /* pPaintRgn */
3123 NULL, /* pPatBlt */
3124 NULL, /* pPie */
3125 NULL, /* pPolyBezier */
3126 NULL, /* pPolyBezierTo */
3127 NULL, /* pPolyDraw */
3128 NULL, /* pPolyPolygon */
3129 NULL, /* pPolyPolyline */
3130 NULL, /* pPolygon */
3131 NULL, /* pPolyline */
3132 NULL, /* pPolylineTo */
3133 xrenderdrv_PutImage, /* pPutImage */
3134 NULL, /* pRealizeDefaultPalette */
3135 NULL, /* pRealizePalette */
3136 NULL, /* pRectangle */
3137 NULL, /* pResetDC */
3138 NULL, /* pRestoreDC */
3139 NULL, /* pRoundRect */
3140 NULL, /* pSaveDC */
3141 NULL, /* pScaleViewportExt */
3142 NULL, /* pScaleWindowExt */
3143 xrenderdrv_SelectBitmap, /* pSelectBitmap */
3144 xrenderdrv_SelectBrush, /* pSelectBrush */
3145 NULL, /* pSelectClipPath */
3146 xrenderdrv_SelectFont, /* pSelectFont */
3147 NULL, /* pSelectPalette */
3148 NULL, /* pSelectPen */
3149 NULL, /* pSetArcDirection */
3150 NULL, /* pSetBkColor */
3151 NULL, /* pSetBkMode */
3152 NULL, /* pSetDCBrushColor */
3153 NULL, /* pSetDCPenColor */
3154 NULL, /* pSetDIBColorTable */
3155 NULL, /* pSetDIBitsToDevice */
3156 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
3157 NULL, /* pSetDeviceGammaRamp */
3158 NULL, /* pSetLayout */
3159 NULL, /* pSetMapMode */
3160 NULL, /* pSetMapperFlags */
3161 NULL, /* pSetPixel */
3162 NULL, /* pSetPixelFormat */
3163 NULL, /* pSetPolyFillMode */
3164 NULL, /* pSetROP2 */
3165 NULL, /* pSetRelAbs */
3166 NULL, /* pSetStretchBltMode */
3167 NULL, /* pSetTextAlign */
3168 NULL, /* pSetTextCharacterExtra */
3169 NULL, /* pSetTextColor */
3170 NULL, /* pSetTextJustification */
3171 NULL, /* pSetViewportExt */
3172 NULL, /* pSetViewportOrg */
3173 NULL, /* pSetWindowExt */
3174 NULL, /* pSetWindowOrg */
3175 NULL, /* pSetWorldTransform */
3176 NULL, /* pStartDoc */
3177 NULL, /* pStartPage */
3178 xrenderdrv_StretchBlt, /* pStretchBlt */
3179 NULL, /* pStretchDIBits */
3180 NULL, /* pStrokeAndFillPath */
3181 NULL, /* pStrokePath */
3182 NULL, /* pSwapBuffers */
3183 NULL, /* pUnrealizePalette */
3184 NULL, /* pWidenPath */
3185 /* OpenGL not supported */
3188 #else /* SONAME_LIBXRENDER */
3190 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
3192 TRACE("XRender support not compiled in.\n");
3193 return NULL;
3196 void X11DRV_XRender_Finalize(void)
3200 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
3202 return FALSE;
3205 #endif /* SONAME_LIBXRENDER */