winex11: Fix selecting a pattern brush into a DIB section device.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blob036ab94f975be2002cb23736a9dc0c9712d8038f
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);
1121 DeleteCriticalSection(&xrender_cs);
1124 /**********************************************************************
1125 * xrenderdrv_SelectFont
1127 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1129 struct xrender_physdev *physdev = get_xrender_dev( dev );
1130 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1131 HFONT ret = next->funcs->pSelectFont( next, hfont );
1133 if (!ret) return 0;
1135 if (physdev->x11dev->has_gdi_font)
1137 LFANDSIZE lfsz;
1139 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1141 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1142 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1143 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1144 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1145 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1146 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1148 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1149 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1150 lfsz.xform.eM21, lfsz.xform.eM22);
1152 /* Not used fields, would break hashing */
1153 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1155 lfsz_calc_hash(&lfsz);
1157 EnterCriticalSection(&xrender_cs);
1158 if (physdev->cache_index != -1)
1159 dec_ref_cache( physdev->cache_index );
1160 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1161 LeaveCriticalSection(&xrender_cs);
1163 else
1165 EnterCriticalSection( &xrender_cs );
1166 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1167 physdev->cache_index = -1;
1168 LeaveCriticalSection( &xrender_cs );
1170 return ret;
1173 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1175 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1176 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1178 if (!physdev) return FALSE;
1179 physdev->x11dev = x11dev;
1180 physdev->cache_index = -1;
1181 physdev->format = format;
1182 physdev->pict_format = pict_formats[format];
1183 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1184 return TRUE;
1187 /* store the color mask data in the bitmap info structure */
1188 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1190 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1192 info->bmiHeader.biPlanes = 1;
1193 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1194 info->bmiHeader.biCompression = BI_RGB;
1195 info->bmiHeader.biClrUsed = 0;
1197 switch (info->bmiHeader.biBitCount)
1199 case 16:
1200 colors[0] = format->direct.redMask << format->direct.red;
1201 colors[1] = format->direct.greenMask << format->direct.green;
1202 colors[2] = format->direct.blueMask << format->direct.blue;
1203 info->bmiHeader.biCompression = BI_BITFIELDS;
1204 break;
1205 case 32:
1206 colors[0] = format->direct.redMask << format->direct.red;
1207 colors[1] = format->direct.greenMask << format->direct.green;
1208 colors[2] = format->direct.blueMask << format->direct.blue;
1209 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1210 info->bmiHeader.biCompression = BI_BITFIELDS;
1211 break;
1216 /**********************************************************************
1217 * xrenderdrv_CreateDC
1219 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1220 LPCWSTR output, const DEVMODEW* initData )
1222 return create_xrender_dc( pdev, default_format );
1225 /**********************************************************************
1226 * xrenderdrv_CreateCompatibleDC
1228 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1230 if (orig) /* chain to x11drv first */
1232 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1233 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1235 /* otherwise we have been called by x11drv */
1237 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1240 /**********************************************************************
1241 * xrenderdrv_DeleteDC
1243 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1245 struct xrender_physdev *physdev = get_xrender_dev( dev );
1247 free_xrender_picture( physdev );
1249 EnterCriticalSection( &xrender_cs );
1250 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1251 LeaveCriticalSection( &xrender_cs );
1253 HeapFree( GetProcessHeap(), 0, physdev );
1254 return TRUE;
1257 /**********************************************************************
1258 * xrenderdrv_ExtEscape
1260 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1261 INT out_count, LPVOID out_data )
1263 struct xrender_physdev *physdev = get_xrender_dev( dev );
1265 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1267 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1269 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1271 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1272 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1273 return ret;
1276 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1279 /****************************************************************************
1280 * xrenderdrv_CopyBitmap
1282 static BOOL xrenderdrv_CopyBitmap( HBITMAP src, HBITMAP dst )
1284 return X11DRV_CopyBitmap( src, dst );
1287 /****************************************************************************
1288 * xrenderdrv_CreateBitmap
1290 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1292 enum wxr_format format;
1293 BITMAP bitmap;
1295 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1297 if (bitmap.bmPlanes != 1) return FALSE;
1298 format = get_bitmap_format( bitmap.bmBitsPixel );
1300 if (pict_formats[format])
1301 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1302 TRUE, &wxr_color_shifts[format] );
1304 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1305 return dev->funcs->pCreateBitmap( dev, hbitmap );
1308 /****************************************************************************
1309 * xrenderdrv_DeleteBitmap
1311 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1313 return X11DRV_DeleteBitmap( hbitmap );
1316 /***********************************************************************
1317 * xrenderdrv_SelectBitmap
1319 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1321 HBITMAP ret;
1322 struct xrender_physdev *physdev = get_xrender_dev( dev );
1324 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1325 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1326 if (ret)
1328 free_xrender_picture( physdev );
1329 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1330 physdev->x11dev->color_shifts );
1331 physdev->pict_format = pict_formats[physdev->format];
1333 return ret;
1336 /***********************************************************************
1337 * xrenderdrv_GetImage
1339 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1340 struct gdi_image_bits *bits, struct bitblt_coords *src )
1342 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1343 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1344 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1347 /***********************************************************************
1348 * xrenderdrv_SetDeviceClipping
1350 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1352 struct xrender_physdev *physdev = get_xrender_dev( dev );
1354 physdev->update_clip = TRUE;
1356 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1357 dev->funcs->pSetDeviceClipping( dev, vis_rgn, clip_rgn );
1361 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1363 XRenderPictFormat *pict_format;
1364 ColorShifts shifts;
1365 const DWORD *bitfields;
1366 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1367 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1370 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1371 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1372 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1373 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1374 return FALSE;
1376 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1377 bitfields = dib->dsBitfields;
1378 else if(bits_pixel == 24 || bits_pixel == 32)
1379 bitfields = bitfields_32;
1380 else
1381 bitfields = bitfields_16;
1383 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1384 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1386 /* Common formats should be in our picture format table. */
1387 if (!pict_format)
1389 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1390 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1391 return FALSE;
1394 physBitmap->depth = pict_format->depth;
1395 physBitmap->trueColor = TRUE;
1396 physBitmap->color_shifts = shifts;
1397 return TRUE;
1400 /************************************************************************
1401 * UploadGlyph
1403 * Helper to ExtTextOut. Must be called inside xrender_cs
1405 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1407 unsigned int buflen;
1408 char *buf;
1409 Glyph gid;
1410 GLYPHMETRICS gm;
1411 XGlyphInfo gi;
1412 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1413 gsCacheEntryFormat *formatEntry;
1414 UINT ggo_format = GGO_GLYPH_INDEX;
1415 enum wxr_format wxr_format;
1416 static const char zero[4];
1417 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1419 switch(format) {
1420 case AA_Grey:
1421 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1422 break;
1423 case AA_RGB:
1424 ggo_format |= WINE_GGO_HRGB_BITMAP;
1425 break;
1426 case AA_BGR:
1427 ggo_format |= WINE_GGO_HBGR_BITMAP;
1428 break;
1429 case AA_VRGB:
1430 ggo_format |= WINE_GGO_VRGB_BITMAP;
1431 break;
1432 case AA_VBGR:
1433 ggo_format |= WINE_GGO_VBGR_BITMAP;
1434 break;
1436 default:
1437 ERR("aa = %d - not implemented\n", format);
1438 case AA_None:
1439 ggo_format |= GGO_BITMAP;
1440 break;
1443 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1444 if(buflen == GDI_ERROR) {
1445 if(format != AA_None) {
1446 format = AA_None;
1447 entry->aa_default = AA_None;
1448 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1449 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1451 if(buflen == GDI_ERROR) {
1452 WARN("GetGlyphOutlineW failed using default glyph\n");
1453 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1454 if(buflen == GDI_ERROR) {
1455 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1456 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1457 if(buflen == GDI_ERROR) {
1458 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1459 return;
1463 TRACE("Turning off antialiasing for this monochrome font\n");
1466 /* If there is nothing for the current type, we create the entry. */
1467 if( !entry->format[format] ) {
1468 entry->format[format] = HeapAlloc(GetProcessHeap(),
1469 HEAP_ZERO_MEMORY,
1470 sizeof(gsCacheEntryFormat));
1472 formatEntry = entry->format[format];
1474 if(formatEntry->nrealized <= glyph) {
1475 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1477 if (formatEntry->realized)
1478 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1479 HEAP_ZERO_MEMORY,
1480 formatEntry->realized,
1481 formatEntry->nrealized * sizeof(BOOL));
1482 else
1483 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1484 HEAP_ZERO_MEMORY,
1485 formatEntry->nrealized * sizeof(BOOL));
1487 if(!X11DRV_XRender_Installed) {
1488 if (formatEntry->bitmaps)
1489 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1490 HEAP_ZERO_MEMORY,
1491 formatEntry->bitmaps,
1492 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1493 else
1494 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1495 HEAP_ZERO_MEMORY,
1496 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1498 if (formatEntry->gis)
1499 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1500 HEAP_ZERO_MEMORY,
1501 formatEntry->gis,
1502 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1503 else
1504 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1505 HEAP_ZERO_MEMORY,
1506 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1510 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1511 switch(format) {
1512 case AA_Grey:
1513 wxr_format = WXR_FORMAT_GRAY;
1514 break;
1516 case AA_RGB:
1517 case AA_BGR:
1518 case AA_VRGB:
1519 case AA_VBGR:
1520 wxr_format = WXR_FORMAT_A8R8G8B8;
1521 break;
1523 default:
1524 ERR("aa = %d - not implemented\n", format);
1525 case AA_None:
1526 wxr_format = WXR_FORMAT_MONO;
1527 break;
1530 wine_tsx11_lock();
1531 formatEntry->font_format = pict_formats[wxr_format];
1532 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1533 wine_tsx11_unlock();
1537 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1538 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1539 formatEntry->realized[glyph] = TRUE;
1541 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1542 buflen,
1543 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1544 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1546 gi.width = gm.gmBlackBoxX;
1547 gi.height = gm.gmBlackBoxY;
1548 gi.x = -gm.gmptGlyphOrigin.x;
1549 gi.y = gm.gmptGlyphOrigin.y;
1550 gi.xOff = gm.gmCellIncX;
1551 gi.yOff = gm.gmCellIncY;
1553 if(TRACE_ON(xrender)) {
1554 int pitch, i, j;
1555 char output[300];
1556 unsigned char *line;
1558 if(format == AA_None) {
1559 pitch = ((gi.width + 31) / 32) * 4;
1560 for(i = 0; i < gi.height; i++) {
1561 line = (unsigned char*) buf + i * pitch;
1562 output[0] = '\0';
1563 for(j = 0; j < pitch * 8; j++) {
1564 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1566 TRACE("%s\n", output);
1568 } else {
1569 static const char blks[] = " .:;!o*#";
1570 char str[2];
1572 str[1] = '\0';
1573 pitch = ((gi.width + 3) / 4) * 4;
1574 for(i = 0; i < gi.height; i++) {
1575 line = (unsigned char*) buf + i * pitch;
1576 output[0] = '\0';
1577 for(j = 0; j < pitch; j++) {
1578 str[0] = blks[line[j] >> 5];
1579 strcat(output, str);
1581 TRACE("%s\n", output);
1587 if(formatEntry->glyphset) {
1588 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1589 unsigned char *byte = (unsigned char*) buf, c;
1590 int i = buflen;
1592 while(i--) {
1593 c = *byte;
1595 /* magic to flip bit order */
1596 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1597 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1598 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1600 *byte++ = c;
1603 else if ( format != AA_Grey &&
1604 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1606 unsigned int i, *data = (unsigned int *)buf;
1607 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1609 gid = glyph;
1612 XRenderCompositeText seems to ignore 0x0 glyphs when
1613 AA_None, which means we lose the advance width of glyphs
1614 like the space. We'll pretend that such glyphs are 1x1
1615 bitmaps.
1618 if(buflen == 0)
1619 gi.width = gi.height = 1;
1621 wine_tsx11_lock();
1622 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1623 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1624 wine_tsx11_unlock();
1625 HeapFree(GetProcessHeap(), 0, buf);
1626 } else {
1627 formatEntry->bitmaps[glyph] = buf;
1630 formatEntry->gis[glyph] = gi;
1633 static void SharpGlyphMono(struct xrender_physdev *physDev, INT x, INT y,
1634 void *bitmap, XGlyphInfo *gi)
1636 unsigned char *srcLine = bitmap, *src;
1637 unsigned char bits, bitsMask;
1638 int width = gi->width;
1639 int stride = ((width + 31) & ~31) >> 3;
1640 int height = gi->height;
1641 int w;
1642 int xspan, lenspan;
1644 TRACE("%d, %d\n", x, y);
1645 x -= gi->x;
1646 y -= gi->y;
1647 while (height--)
1649 src = srcLine;
1650 srcLine += stride;
1651 w = width;
1653 bitsMask = 0x80; /* FreeType is always MSB first */
1654 bits = *src++;
1656 xspan = x;
1657 while (w)
1659 if (bits & bitsMask)
1661 lenspan = 0;
1664 lenspan++;
1665 if (lenspan == w)
1666 break;
1667 bitsMask = bitsMask >> 1;
1668 if (!bitsMask)
1670 bits = *src++;
1671 bitsMask = 0x80;
1673 } while (bits & bitsMask);
1674 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1675 physDev->x11dev->gc, xspan, y, lenspan, 1);
1676 xspan += lenspan;
1677 w -= lenspan;
1679 else
1683 w--;
1684 xspan++;
1685 if (!w)
1686 break;
1687 bitsMask = bitsMask >> 1;
1688 if (!bitsMask)
1690 bits = *src++;
1691 bitsMask = 0x80;
1693 } while (!(bits & bitsMask));
1696 y++;
1700 static void SharpGlyphGray(struct xrender_physdev *physDev, INT x, INT y,
1701 void *bitmap, XGlyphInfo *gi)
1703 unsigned char *srcLine = bitmap, *src, bits;
1704 int width = gi->width;
1705 int stride = ((width + 3) & ~3);
1706 int height = gi->height;
1707 int w;
1708 int xspan, lenspan;
1710 x -= gi->x;
1711 y -= gi->y;
1712 while (height--)
1714 src = srcLine;
1715 srcLine += stride;
1716 w = width;
1718 bits = *src++;
1719 xspan = x;
1720 while (w)
1722 if (bits >= 0x80)
1724 lenspan = 0;
1727 lenspan++;
1728 if (lenspan == w)
1729 break;
1730 bits = *src++;
1731 } while (bits >= 0x80);
1732 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1733 physDev->x11dev->gc, xspan, y, lenspan, 1);
1734 xspan += lenspan;
1735 w -= lenspan;
1737 else
1741 w--;
1742 xspan++;
1743 if (!w)
1744 break;
1745 bits = *src++;
1746 } while (bits < 0x80);
1749 y++;
1754 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1756 int s, l;
1758 s = 0;
1759 while ((mask & 1) == 0)
1761 mask >>= 1;
1762 s++;
1764 l = 0;
1765 while ((mask & 1) == 1)
1767 mask >>= 1;
1768 l++;
1770 *shift = s;
1771 *len = l;
1774 static DWORD GetField (DWORD pixel, int shift, int len)
1776 pixel = pixel & (((1 << (len)) - 1) << shift);
1777 pixel = pixel << (32 - (shift + len)) >> 24;
1778 while (len < 8)
1780 pixel |= (pixel >> len);
1781 len <<= 1;
1783 return pixel;
1787 static DWORD PutField (DWORD pixel, int shift, int len)
1789 shift = shift - (8 - len);
1790 if (len <= 8)
1791 pixel &= (((1 << len) - 1) << (8 - len));
1792 if (shift < 0)
1793 pixel >>= -shift;
1794 else
1795 pixel <<= shift;
1796 return pixel;
1799 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1800 int color)
1802 int r_shift, r_len;
1803 int g_shift, g_len;
1804 int b_shift, b_len;
1805 BYTE *maskLine, *mask, m;
1806 int maskStride;
1807 DWORD pixel;
1808 int width, height;
1809 int w, tx;
1810 BYTE src_r, src_g, src_b;
1812 x -= gi->x;
1813 y -= gi->y;
1814 width = gi->width;
1815 height = gi->height;
1817 maskLine = bitmap;
1818 maskStride = (width + 3) & ~3;
1820 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1821 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1822 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1824 src_r = GetField(color, r_shift, r_len);
1825 src_g = GetField(color, g_shift, g_len);
1826 src_b = GetField(color, b_shift, b_len);
1828 for(; height--; y++)
1830 mask = maskLine;
1831 maskLine += maskStride;
1832 w = width;
1833 tx = x;
1835 if(y < 0) continue;
1836 if(y >= image->height) break;
1838 for(; w--; tx++)
1840 if(tx >= image->width) break;
1842 m = *mask++;
1843 if(tx < 0) continue;
1845 if (m == 0xff)
1846 XPutPixel (image, tx, y, color);
1847 else if (m)
1849 BYTE r, g, b;
1851 pixel = XGetPixel (image, tx, y);
1853 r = GetField(pixel, r_shift, r_len);
1854 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1855 g = GetField(pixel, g_shift, g_len);
1856 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1857 b = GetField(pixel, b_shift, b_len);
1858 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1860 pixel = (PutField (r, r_shift, r_len) |
1861 PutField (g, g_shift, g_len) |
1862 PutField (b, b_shift, b_len));
1863 XPutPixel (image, tx, y, pixel);
1869 /*************************************************************
1870 * get_tile_pict
1872 * Returns an appropriate Picture for tiling the text colour.
1873 * Call and use result within the xrender_cs
1875 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1877 static struct
1879 Pixmap xpm;
1880 Picture pict;
1881 XRenderColor current_color;
1882 } tiles[WXR_NB_FORMATS], *tile;
1884 tile = &tiles[wxr_format];
1886 if(!tile->xpm)
1888 XRenderPictureAttributes pa;
1889 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1891 wine_tsx11_lock();
1892 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1894 pa.repeat = RepeatNormal;
1895 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1896 wine_tsx11_unlock();
1898 /* init current_color to something different from text_pixel */
1899 tile->current_color = *color;
1900 tile->current_color.red ^= 0xffff;
1902 if (wxr_format == WXR_FORMAT_MONO)
1904 /* for a 1bpp bitmap we always need a 1 in the tile */
1905 XRenderColor col;
1906 col.red = col.green = col.blue = 0;
1907 col.alpha = 0xffff;
1908 wine_tsx11_lock();
1909 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1910 wine_tsx11_unlock();
1914 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1916 wine_tsx11_lock();
1917 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1918 wine_tsx11_unlock();
1919 tile->current_color = *color;
1921 return tile->pict;
1924 /*************************************************************
1925 * get_mask_pict
1927 * Returns an appropriate Picture for masking with the specified alpha.
1928 * Call and use result within the xrender_cs
1930 static Picture get_mask_pict( int alpha )
1932 static Pixmap pixmap;
1933 static Picture pict;
1934 static int current_alpha;
1936 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1938 if (!pixmap)
1940 XRenderPictureAttributes pa;
1942 wine_tsx11_lock();
1943 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1944 pa.repeat = RepeatNormal;
1945 pict = pXRenderCreatePicture( gdi_display, pixmap,
1946 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1947 wine_tsx11_unlock();
1948 current_alpha = -1;
1951 if (alpha != current_alpha)
1953 XRenderColor col;
1954 col.red = col.green = col.blue = 0;
1955 col.alpha = current_alpha = alpha;
1956 wine_tsx11_lock();
1957 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1958 wine_tsx11_unlock();
1960 return pict;
1963 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1965 return 1;
1968 /***********************************************************************
1969 * xrenderdrv_ExtTextOut
1971 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1972 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1974 struct xrender_physdev *physdev = get_xrender_dev( dev );
1975 XGCValues xgcval;
1976 gsCacheEntry *entry;
1977 gsCacheEntryFormat *formatEntry;
1978 BOOL retv = FALSE;
1979 int textPixel, backgroundPixel;
1980 RGNDATA *saved_region = NULL;
1981 AA_Type aa_type = AA_None;
1982 unsigned int idx;
1983 Picture tile_pict = 0;
1985 if (!physdev->x11dev->has_gdi_font)
1987 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1988 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1991 xgcval.function = GXcopy;
1992 xgcval.background = physdev->x11dev->backgroundPixel;
1993 xgcval.fill_style = FillSolid;
1994 wine_tsx11_lock();
1995 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1996 wine_tsx11_unlock();
1998 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2000 if(physdev->x11dev->depth == 1) {
2001 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
2002 textPixel = 0;
2003 backgroundPixel = 1;
2004 } else {
2005 textPixel = 1;
2006 backgroundPixel = 0;
2008 } else {
2009 textPixel = physdev->x11dev->textPixel;
2010 backgroundPixel = physdev->x11dev->backgroundPixel;
2013 if(flags & ETO_OPAQUE)
2015 wine_tsx11_lock();
2016 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
2017 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
2018 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
2019 lprect->right - lprect->left, lprect->bottom - lprect->top );
2020 wine_tsx11_unlock();
2023 if(count == 0)
2025 retv = TRUE;
2026 goto done_unlock;
2029 EnterCriticalSection(&xrender_cs);
2031 entry = glyphsetCache + physdev->cache_index;
2032 aa_type = entry->aa_default;
2033 formatEntry = entry->format[aa_type];
2035 for(idx = 0; idx < count; idx++) {
2036 if( !formatEntry ) {
2037 UploadGlyph(physdev, wstr[idx], aa_type);
2038 /* re-evaluate antialias since aa_default may have changed */
2039 aa_type = entry->aa_default;
2040 formatEntry = entry->format[aa_type];
2041 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
2042 UploadGlyph(physdev, wstr[idx], aa_type);
2045 if (!formatEntry)
2047 WARN("could not upload requested glyphs\n");
2048 LeaveCriticalSection(&xrender_cs);
2049 goto done_unlock;
2052 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
2053 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2055 if(X11DRV_XRender_Installed)
2057 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
2058 POINT offset = {0, 0};
2059 POINT desired, current;
2060 int render_op = PictOpOver;
2061 Picture pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
2062 XRenderColor col;
2064 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2065 So we pass zeros to the function and move to our starting position using the first
2066 element of the elts array. */
2068 desired.x = physdev->x11dev->dc_rect.left + x;
2069 desired.y = physdev->x11dev->dc_rect.top + y;
2070 current.x = current.y = 0;
2072 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
2073 tile_pict = get_tile_pict(physdev->format, &col);
2075 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2077 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
2078 render_op = PictOpOutReverse; /* This gives us 'black' text */
2080 for(idx = 0; idx < count; idx++)
2082 elts[idx].glyphset = formatEntry->glyphset;
2083 elts[idx].chars = wstr + idx;
2084 elts[idx].nchars = 1;
2085 elts[idx].xOff = desired.x - current.x;
2086 elts[idx].yOff = desired.y - current.y;
2088 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
2089 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
2091 if(!lpDx)
2093 desired.x += formatEntry->gis[wstr[idx]].xOff;
2094 desired.y += formatEntry->gis[wstr[idx]].yOff;
2096 else
2098 if(flags & ETO_PDY)
2100 offset.x += lpDx[idx * 2];
2101 offset.y += lpDx[idx * 2 + 1];
2103 else
2104 offset.x += lpDx[idx];
2105 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
2106 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
2110 wine_tsx11_lock();
2111 /* Make sure we don't have any transforms set from a previous call */
2112 set_xrender_transformation(pict, 1, 1, 0, 0);
2113 pXRenderCompositeText16(gdi_display, render_op,
2114 tile_pict,
2115 pict,
2116 formatEntry->font_format,
2117 0, 0, 0, 0, elts, count);
2118 wine_tsx11_unlock();
2119 HeapFree(GetProcessHeap(), 0, elts);
2120 } else {
2121 POINT offset = {0, 0};
2123 if (flags & ETO_CLIPPED)
2125 HRGN clip_region = CreateRectRgnIndirect( lprect );
2126 saved_region = add_extra_clipping_region( physdev->x11dev, clip_region );
2127 DeleteObject( clip_region );
2130 wine_tsx11_lock();
2131 XSetForeground( gdi_display, physdev->x11dev->gc, textPixel );
2133 if(aa_type == AA_None || physdev->x11dev->depth == 1)
2135 void (* sharp_glyph_fn)(struct xrender_physdev *, INT, INT, void *, XGlyphInfo *);
2137 if(aa_type == AA_None)
2138 sharp_glyph_fn = SharpGlyphMono;
2139 else
2140 sharp_glyph_fn = SharpGlyphGray;
2142 for(idx = 0; idx < count; idx++) {
2143 sharp_glyph_fn(physdev,
2144 physdev->x11dev->dc_rect.left + x + offset.x,
2145 physdev->x11dev->dc_rect.top + y + offset.y,
2146 formatEntry->bitmaps[wstr[idx]],
2147 &formatEntry->gis[wstr[idx]]);
2148 if(lpDx)
2150 if(flags & ETO_PDY)
2152 offset.x += lpDx[idx * 2];
2153 offset.y += lpDx[idx * 2 + 1];
2155 else
2156 offset.x += lpDx[idx];
2158 else
2160 offset.x += formatEntry->gis[wstr[idx]].xOff;
2161 offset.y += formatEntry->gis[wstr[idx]].yOff;
2164 } else {
2165 XImage *image;
2166 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2167 RECT extents = {0, 0, 0, 0};
2168 POINT cur = {0, 0};
2169 int w = physdev->x11dev->drawable_rect.right - physdev->x11dev->drawable_rect.left;
2170 int h = physdev->x11dev->drawable_rect.bottom - physdev->x11dev->drawable_rect.top;
2172 TRACE("drawable %dx%d\n", w, h);
2174 for(idx = 0; idx < count; idx++) {
2175 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2176 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2177 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2178 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2179 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2180 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2181 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2182 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2184 if(lpDx)
2186 if(flags & ETO_PDY)
2188 cur.x += lpDx[idx * 2];
2189 cur.y += lpDx[idx * 2 + 1];
2191 else
2192 cur.x += lpDx[idx];
2194 else
2196 cur.x += formatEntry->gis[wstr[idx]].xOff;
2197 cur.y += formatEntry->gis[wstr[idx]].yOff;
2200 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2201 extents.right, extents.bottom, physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2203 if(physdev->x11dev->dc_rect.left + x + extents.left >= 0) {
2204 image_x = physdev->x11dev->dc_rect.left + x + extents.left;
2205 image_off_x = 0;
2206 } else {
2207 image_x = 0;
2208 image_off_x = physdev->x11dev->dc_rect.left + x + extents.left;
2210 if(physdev->x11dev->dc_rect.top + y + extents.top >= 0) {
2211 image_y = physdev->x11dev->dc_rect.top + y + extents.top;
2212 image_off_y = 0;
2213 } else {
2214 image_y = 0;
2215 image_off_y = physdev->x11dev->dc_rect.top + y + extents.top;
2217 if(physdev->x11dev->dc_rect.left + x + extents.right < w)
2218 image_w = physdev->x11dev->dc_rect.left + x + extents.right - image_x;
2219 else
2220 image_w = w - image_x;
2221 if(physdev->x11dev->dc_rect.top + y + extents.bottom < h)
2222 image_h = physdev->x11dev->dc_rect.top + y + extents.bottom - image_y;
2223 else
2224 image_h = h - image_y;
2226 if(image_w <= 0 || image_h <= 0) goto no_image;
2228 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2229 image = XGetImage(gdi_display, physdev->x11dev->drawable,
2230 image_x, image_y, image_w, image_h,
2231 AllPlanes, ZPixmap);
2232 X11DRV_check_error();
2234 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2235 gdi_display, (int)physdev->x11dev->drawable, image_x, image_y,
2236 image_w, image_h, AllPlanes, ZPixmap,
2237 physdev->x11dev->depth, image);
2238 if(!image) {
2239 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2240 physdev->x11dev->depth);
2241 GC gc;
2242 XGCValues gcv;
2244 gcv.graphics_exposures = False;
2245 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2246 XCopyArea(gdi_display, physdev->x11dev->drawable, xpm, gc, image_x, image_y,
2247 image_w, image_h, 0, 0);
2248 XFreeGC(gdi_display, gc);
2249 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2250 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2251 ZPixmap);
2252 X11DRV_check_error();
2253 XFreePixmap(gdi_display, xpm);
2255 if(!image) goto no_image;
2257 image->red_mask = visual->red_mask;
2258 image->green_mask = visual->green_mask;
2259 image->blue_mask = visual->blue_mask;
2261 for(idx = 0; idx < count; idx++) {
2262 SmoothGlyphGray(image,
2263 offset.x + image_off_x - extents.left,
2264 offset.y + image_off_y - extents.top,
2265 formatEntry->bitmaps[wstr[idx]],
2266 &formatEntry->gis[wstr[idx]],
2267 physdev->x11dev->textPixel);
2268 if(lpDx)
2270 if(flags & ETO_PDY)
2272 offset.x += lpDx[idx * 2];
2273 offset.y += lpDx[idx * 2 + 1];
2275 else
2276 offset.x += lpDx[idx];
2278 else
2280 offset.x += formatEntry->gis[wstr[idx]].xOff;
2281 offset.y += formatEntry->gis[wstr[idx]].yOff;
2284 XPutImage(gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc, image, 0, 0,
2285 image_x, image_y, image_w, image_h);
2286 XDestroyImage(image);
2288 no_image:
2289 wine_tsx11_unlock();
2290 restore_clipping_region( physdev->x11dev, saved_region );
2292 LeaveCriticalSection(&xrender_cs);
2293 retv = TRUE;
2295 done_unlock:
2296 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2297 return retv;
2300 /* multiply the alpha channel of a picture */
2301 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
2302 int x, int y, int width, int height )
2304 XRenderPictureAttributes pa;
2305 Pixmap src_pixmap, mask_pixmap;
2306 Picture src_pict, mask_pict;
2307 XRenderColor color;
2309 wine_tsx11_lock();
2310 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2311 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2312 pa.repeat = RepeatNormal;
2313 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
2314 pa.component_alpha = True;
2315 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
2316 color.red = color.green = color.blue = color.alpha = 0xffff;
2317 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
2318 color.alpha = alpha;
2319 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
2320 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
2321 0, 0, 0, 0, x, y, width, height );
2322 pXRenderFreePicture( gdi_display, src_pict );
2323 pXRenderFreePicture( gdi_display, mask_pict );
2324 XFreePixmap( gdi_display, src_pixmap );
2325 XFreePixmap( gdi_display, mask_pixmap );
2326 wine_tsx11_unlock();
2329 /* Helper function for (stretched) blitting using xrender */
2330 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2331 int x_src, int y_src, int x_dst, int y_dst,
2332 double xscale, double yscale, int width, int height )
2334 int x_offset, y_offset;
2336 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2337 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2338 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2339 wine_tsx11_lock();
2340 if(xscale != 1.0 || yscale != 1.0)
2342 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2343 * in the wrong quadrant of the x-y plane.
2345 x_offset = (xscale < 0) ? -width : 0;
2346 y_offset = (yscale < 0) ? -height : 0;
2347 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2349 else
2351 x_offset = x_src;
2352 y_offset = y_src;
2353 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2355 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2356 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2357 wine_tsx11_unlock();
2360 /* Helper function for (stretched) mono->color blitting using xrender */
2361 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
2362 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
2363 int x_src, int y_src, int x_dst, int y_dst,
2364 double xscale, double yscale, int width, int height )
2366 Picture tile_pict;
2367 int x_offset, y_offset;
2368 XRenderColor color;
2370 /* When doing a mono->color blit, the source data is used as mask, and the source picture
2371 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
2372 * the tile data.
2374 EnterCriticalSection( &xrender_cs );
2375 color = *bg;
2376 color.alpha = 0xffff; /* tile pict needs 100% alpha */
2377 tile_pict = get_tile_pict( dst_format, &color );
2379 wine_tsx11_lock();
2380 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
2382 if (xscale != 1.0 || yscale != 1.0)
2384 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2385 * in the wrong quadrant of the x-y plane.
2387 x_offset = (xscale < 0) ? -width : 0;
2388 y_offset = (yscale < 0) ? -height : 0;
2389 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2391 else
2393 x_offset = x_src;
2394 y_offset = y_src;
2395 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2397 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
2398 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
2399 wine_tsx11_unlock();
2400 LeaveCriticalSection( &xrender_cs );
2402 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
2403 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
2404 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
2407 /* create a pixmap and render picture for an image */
2408 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
2409 struct bitblt_coords *src, enum wxr_format format,
2410 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
2412 DWORD ret;
2413 int width = src->visrect.right - src->visrect.left;
2414 int height = src->visrect.bottom - src->visrect.top;
2415 int depth = pict_formats[format]->depth;
2416 struct gdi_image_bits dst_bits;
2417 XRenderPictureAttributes pa;
2418 XImage *image;
2420 wine_tsx11_lock();
2421 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2422 info->bmiHeader.biWidth, height, 32, 0 );
2423 wine_tsx11_unlock();
2424 if (!image) return ERROR_OUTOFMEMORY;
2426 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2427 if (ret) return ret;
2429 image->data = dst_bits.ptr;
2430 /* hack: make sure the bits are readable if we are reading from a DIB section */
2431 /* to be removed once we get rid of DIB access protections */
2432 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2434 *use_repeat = (width == 1 && height == 1);
2435 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2437 wine_tsx11_lock();
2438 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2439 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2440 src->visrect.left, 0, 0, 0, width, height );
2441 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2442 wine_tsx11_unlock();
2444 /* make coordinates relative to the pixmap */
2445 src->x -= src->visrect.left;
2446 src->y -= src->visrect.top;
2447 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2449 image->data = NULL;
2450 wine_tsx11_lock();
2451 XDestroyImage( image );
2452 wine_tsx11_unlock();
2453 if (dst_bits.free) dst_bits.free( &dst_bits );
2454 return ret;
2457 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2458 Drawable drawable, const struct bitblt_coords *src,
2459 const struct bitblt_coords *dst )
2461 int width = abs( dst->width );
2462 int height = abs( dst->height );
2463 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2464 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2465 int x_dst, y_dst;
2466 Picture src_pict = 0, dst_pict, mask_pict = 0;
2467 BOOL use_repeat;
2468 double xscale, yscale;
2470 use_repeat = use_source_repeat( physdev_src );
2471 if (!use_repeat)
2473 xscale = src->width / (double)dst->width;
2474 yscale = src->height / (double)dst->height;
2476 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2478 if (drawable) /* using an intermediate pixmap */
2480 XRenderPictureAttributes pa;
2482 x_dst = dst->x;
2483 y_dst = dst->y;
2484 pa.repeat = RepeatNone;
2485 wine_tsx11_lock();
2486 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2487 wine_tsx11_unlock();
2489 else
2491 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2492 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2493 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2496 if (src->width < 0) x_src += src->width + 1;
2497 if (src->height < 0) y_src += src->height + 1;
2498 if (dst->width < 0) x_dst += dst->width + 1;
2499 if (dst->height < 0) y_dst += dst->height + 1;
2501 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2503 /* mono -> color */
2504 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2506 XRenderColor fg, bg;
2508 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, &fg );
2509 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, &bg );
2510 fg.alpha = bg.alpha = 0;
2512 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2513 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2515 else /* color -> color (can be at different depths) or mono -> mono */
2517 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2518 mask_pict = get_no_alpha_mask();
2520 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2521 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2524 if (drawable)
2526 wine_tsx11_lock();
2527 pXRenderFreePicture( gdi_display, dst_pict );
2528 wine_tsx11_unlock();
2533 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2534 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2535 Drawable drawable, struct bitblt_coords *src,
2536 struct bitblt_coords *dst, BOOL use_repeat )
2538 int x_src, y_src, x_dst, y_dst;
2539 Picture dst_pict;
2540 XRenderPictureAttributes pa;
2541 double xscale, yscale;
2543 if (drawable) /* using an intermediate pixmap */
2545 RGNDATA *clip_data = NULL;
2547 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2548 x_dst = dst->x;
2549 y_dst = dst->y;
2550 pa.repeat = RepeatNone;
2551 wine_tsx11_lock();
2552 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2553 if (clip_data)
2554 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2555 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2556 wine_tsx11_unlock();
2557 HeapFree( GetProcessHeap(), 0, clip_data );
2559 else
2561 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2562 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2563 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2566 if (!use_repeat)
2568 xscale = src->width / (double)dst->width;
2569 yscale = src->height / (double)dst->height;
2571 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2573 x_src = src->x;
2574 y_src = src->y;
2575 if (src->width < 0) x_src += src->width + 1;
2576 if (src->height < 0) y_src += src->height + 1;
2577 if (dst->width < 0) x_dst += dst->width + 1;
2578 if (dst->height < 0) y_dst += dst->height + 1;
2580 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2581 xscale, yscale, abs( dst->width ), abs( dst->height ));
2583 if (drawable)
2585 wine_tsx11_lock();
2586 pXRenderFreePicture( gdi_display, dst_pict );
2587 wine_tsx11_unlock();
2592 /***********************************************************************
2593 * xrenderdrv_StretchBlt
2595 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2596 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2598 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2599 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2600 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2602 if (src_dev->funcs != dst_dev->funcs)
2604 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2605 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2608 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2610 /* XRender is of no use for color -> mono */
2611 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2612 goto x11drv_fallback;
2614 /* if not stretching, we only need to handle format conversion */
2615 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2617 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2618 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2620 if (rop != SRCCOPY)
2622 GC tmpGC;
2623 Pixmap tmp_pixmap;
2624 struct bitblt_coords tmp;
2626 /* make coordinates relative to tmp pixmap */
2627 tmp = *dst;
2628 tmp.x -= tmp.visrect.left;
2629 tmp.y -= tmp.visrect.top;
2630 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2632 wine_tsx11_lock();
2633 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2634 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2635 XSetGraphicsExposures( gdi_display, tmpGC, False );
2636 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2637 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2638 wine_tsx11_unlock();
2640 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2641 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2643 wine_tsx11_lock();
2644 XFreePixmap( gdi_display, tmp_pixmap );
2645 XFreeGC( gdi_display, tmpGC );
2646 wine_tsx11_unlock();
2648 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2650 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2651 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2652 return TRUE;
2654 x11drv_fallback:
2655 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2659 /***********************************************************************
2660 * xrenderdrv_PutImage
2662 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2663 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2664 struct bitblt_coords *dst, DWORD rop )
2666 struct xrender_physdev *physdev;
2667 X_PHYSBITMAP *bitmap;
2668 DWORD ret;
2669 Pixmap tmp_pixmap;
2670 GC gc;
2671 enum wxr_format src_format, dst_format;
2672 XRenderPictFormat *pict_format;
2673 Pixmap src_pixmap;
2674 Picture src_pict, mask_pict = 0;
2675 BOOL use_repeat;
2677 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2679 if (hbitmap)
2681 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2682 physdev = NULL;
2683 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2685 else
2687 physdev = get_xrender_dev( dev );
2688 bitmap = NULL;
2689 dst_format = physdev->format;
2692 src_format = get_xrender_format_from_bitmapinfo( info );
2693 if (!(pict_format = pict_formats[src_format])) goto update_format;
2695 /* make sure we can create an image with the same bpp */
2696 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2697 goto update_format;
2699 /* mono <-> color conversions not supported */
2700 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2701 goto x11drv_fallback;
2703 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2705 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2707 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2708 if (!ret)
2710 struct bitblt_coords tmp;
2712 if (bitmap)
2714 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2715 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2717 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2719 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2720 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2722 X11DRV_DIB_Unlock( bitmap, TRUE );
2723 DeleteObject( rgn );
2725 else
2727 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2729 if (rop != SRCCOPY)
2731 RGNDATA *clip_data = NULL;
2733 /* make coordinates relative to tmp pixmap */
2734 tmp = *dst;
2735 tmp.x -= tmp.visrect.left;
2736 tmp.y -= tmp.visrect.top;
2737 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2739 if (clip) clip_data = add_extra_clipping_region( physdev->x11dev, clip );
2741 wine_tsx11_lock();
2742 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2743 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2744 XSetGraphicsExposures( gdi_display, gc, False );
2745 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2746 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2747 wine_tsx11_unlock();
2749 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2750 NULL, tmp_pixmap, src, &tmp, use_repeat );
2751 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2753 wine_tsx11_lock();
2754 XFreePixmap( gdi_display, tmp_pixmap );
2755 XFreeGC( gdi_display, gc );
2756 wine_tsx11_unlock();
2758 restore_clipping_region( physdev->x11dev, clip_data );
2760 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2761 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2763 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2766 wine_tsx11_lock();
2767 pXRenderFreePicture( gdi_display, src_pict );
2768 XFreePixmap( gdi_display, src_pixmap );
2769 wine_tsx11_unlock();
2771 return ret;
2773 update_format:
2774 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2775 set_color_info( pict_formats[dst_format], info );
2776 return ERROR_BAD_FORMAT;
2778 x11drv_fallback:
2779 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2780 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2781 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2785 /***********************************************************************
2786 * xrenderdrv_BlendImage
2788 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2789 struct bitblt_coords *src, struct bitblt_coords *dst,
2790 BLENDFUNCTION func )
2792 struct xrender_physdev *physdev = get_xrender_dev( dev );
2793 DWORD ret;
2794 enum wxr_format format;
2795 XRenderPictFormat *pict_format;
2796 Picture dst_pict, src_pict, mask_pict;
2797 Pixmap src_pixmap;
2798 BOOL use_repeat;
2800 if (!X11DRV_XRender_Installed)
2802 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2803 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2806 format = get_xrender_format_from_bitmapinfo( info );
2807 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2808 format = get_format_without_alpha( format );
2809 else if (format != WXR_FORMAT_A8R8G8B8)
2810 return ERROR_INVALID_PARAMETER;
2812 if (!(pict_format = pict_formats[format])) goto update_format;
2814 /* make sure we can create an image with the same bpp */
2815 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2816 goto update_format;
2818 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2819 goto update_format;
2821 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2823 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2824 if (!ret)
2826 double xscale, yscale;
2828 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2830 if (!use_repeat)
2832 xscale = src->width / (double)dst->width;
2833 yscale = src->height / (double)dst->height;
2835 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2837 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2839 EnterCriticalSection( &xrender_cs );
2840 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2842 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2843 physdev->x11dev->dc_rect.left + dst->x,
2844 physdev->x11dev->dc_rect.top + dst->y,
2845 xscale, yscale, dst->width, dst->height );
2847 wine_tsx11_lock();
2848 pXRenderFreePicture( gdi_display, src_pict );
2849 XFreePixmap( gdi_display, src_pixmap );
2850 wine_tsx11_unlock();
2852 LeaveCriticalSection( &xrender_cs );
2854 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2856 return ret;
2858 update_format:
2859 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2860 set_color_info( physdev->pict_format, info );
2861 return ERROR_BAD_FORMAT;
2865 /***********************************************************************
2866 * xrenderdrv_AlphaBlend
2868 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2869 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2871 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2872 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2873 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2874 XRenderPictureAttributes pa;
2875 Pixmap tmp_pixmap = 0;
2876 double xscale, yscale;
2877 BOOL use_repeat;
2879 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2881 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2882 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2885 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2887 SetLastError( ERROR_INVALID_PARAMETER );
2888 return FALSE;
2891 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2892 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2894 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2896 use_repeat = use_source_repeat( physdev_src );
2897 if (!use_repeat)
2899 xscale = src->width / (double)dst->width;
2900 yscale = src->height / (double)dst->height;
2902 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2904 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2906 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2908 /* mono -> color blending needs an intermediate color pixmap */
2909 XRenderColor fg, bg;
2910 int width = src->visrect.right - src->visrect.left;
2911 int height = src->visrect.bottom - src->visrect.top;
2913 /* blending doesn't use the destination DC colors */
2914 fg.red = fg.green = fg.blue = 0;
2915 bg.red = bg.green = bg.blue = 0xffff;
2916 fg.alpha = bg.alpha = 0xffff;
2918 wine_tsx11_lock();
2919 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2920 physdev_dst->pict_format->depth );
2921 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2922 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2923 CPRepeat, &pa );
2924 wine_tsx11_unlock();
2926 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2927 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2929 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2931 /* we need a source picture with no alpha */
2932 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2933 if (format != physdev_src->format)
2935 wine_tsx11_lock();
2936 pa.subwindow_mode = IncludeInferiors;
2937 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2938 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2939 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2940 wine_tsx11_unlock();
2944 if (tmp_pict) src_pict = tmp_pict;
2946 EnterCriticalSection( &xrender_cs );
2947 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2949 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2950 physdev_src->x11dev->dc_rect.left + src->x,
2951 physdev_src->x11dev->dc_rect.top + src->y,
2952 physdev_dst->x11dev->dc_rect.left + dst->x,
2953 physdev_dst->x11dev->dc_rect.top + dst->y,
2954 xscale, yscale, dst->width, dst->height );
2956 wine_tsx11_lock();
2957 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2958 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2959 wine_tsx11_unlock();
2961 LeaveCriticalSection( &xrender_cs );
2962 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2963 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2964 return TRUE;
2967 /***********************************************************************
2968 * xrenderdrv_SelectBrush
2970 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, HBITMAP bitmap,
2971 const BITMAPINFO *info, void *bits, UINT usage )
2973 struct xrender_physdev *physdev = get_xrender_dev( dev );
2974 X_PHYSBITMAP *physbitmap;
2975 enum wxr_format format;
2976 BOOL delete_bitmap = FALSE;
2977 BITMAP bm;
2978 Pixmap pixmap;
2979 Picture src_pict, dst_pict;
2980 XRenderPictureAttributes pa;
2982 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2983 if (!bitmap && !info) goto x11drv_fallback;
2984 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2986 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2988 if (!(bitmap = create_brush_bitmap( physdev->x11dev, info, bits, usage ))) return 0;
2989 physbitmap = X11DRV_get_phys_bitmap( bitmap );
2990 delete_bitmap = TRUE;
2993 format = get_xrender_format_from_color_shifts( physbitmap->depth, &physbitmap->color_shifts );
2994 if (format == WXR_FORMAT_MONO || !pict_formats[format]) goto x11drv_fallback;
2996 GetObjectW( bitmap, sizeof(bm), &bm );
2998 X11DRV_DIB_Lock( physbitmap, DIB_Status_GdiMod );
3000 wine_tsx11_lock();
3001 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
3002 physdev->pict_format->depth );
3004 pa.repeat = RepeatNone;
3005 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_formats[format], CPRepeat, &pa);
3006 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
3008 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, bm.bmWidth, bm.bmHeight );
3009 pXRenderFreePicture( gdi_display, src_pict );
3010 pXRenderFreePicture( gdi_display, dst_pict );
3012 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
3013 physdev->x11dev->brush.pixmap = pixmap;
3014 physdev->x11dev->brush.fillStyle = FillTiled;
3015 physdev->x11dev->brush.pixel = 0; /* ignored */
3016 wine_tsx11_unlock();
3018 X11DRV_DIB_Unlock( physbitmap, TRUE );
3019 if (delete_bitmap) DeleteObject( bitmap );
3020 return hbrush;
3022 x11drv_fallback:
3023 if (delete_bitmap) DeleteObject( bitmap );
3024 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
3025 return dev->funcs->pSelectBrush( dev, hbrush, bitmap, info, bits, usage );
3029 static const struct gdi_dc_funcs xrender_funcs =
3031 NULL, /* pAbortDoc */
3032 NULL, /* pAbortPath */
3033 xrenderdrv_AlphaBlend, /* pAlphaBlend */
3034 NULL, /* pAngleArc */
3035 NULL, /* pArc */
3036 NULL, /* pArcTo */
3037 NULL, /* pBeginPath */
3038 xrenderdrv_BlendImage, /* pBlendImage */
3039 NULL, /* pChoosePixelFormat */
3040 NULL, /* pChord */
3041 NULL, /* pCloseFigure */
3042 xrenderdrv_CopyBitmap, /* pCopyBitmap */
3043 xrenderdrv_CreateBitmap, /* pCreateBitmap */
3044 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
3045 xrenderdrv_CreateDC, /* pCreateDC */
3046 NULL, /* pCreateDIBSection */
3047 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
3048 xrenderdrv_DeleteDC, /* pDeleteDC */
3049 NULL, /* pDeleteObject */
3050 NULL, /* pDescribePixelFormat */
3051 NULL, /* pDeviceCapabilities */
3052 NULL, /* pEllipse */
3053 NULL, /* pEndDoc */
3054 NULL, /* pEndPage */
3055 NULL, /* pEndPath */
3056 NULL, /* pEnumFonts */
3057 NULL, /* pEnumICMProfiles */
3058 NULL, /* pExcludeClipRect */
3059 NULL, /* pExtDeviceMode */
3060 xrenderdrv_ExtEscape, /* pExtEscape */
3061 NULL, /* pExtFloodFill */
3062 NULL, /* pExtSelectClipRgn */
3063 xrenderdrv_ExtTextOut, /* pExtTextOut */
3064 NULL, /* pFillPath */
3065 NULL, /* pFillRgn */
3066 NULL, /* pFlattenPath */
3067 NULL, /* pFontIsLinked */
3068 NULL, /* pFrameRgn */
3069 NULL, /* pGdiComment */
3070 NULL, /* pGdiRealizationInfo */
3071 NULL, /* pGetCharABCWidths */
3072 NULL, /* pGetCharABCWidthsI */
3073 NULL, /* pGetCharWidth */
3074 NULL, /* pGetDeviceCaps */
3075 NULL, /* pGetDeviceGammaRamp */
3076 NULL, /* pGetFontData */
3077 NULL, /* pGetFontUnicodeRanges */
3078 NULL, /* pGetGlyphIndices */
3079 NULL, /* pGetGlyphOutline */
3080 NULL, /* pGetICMProfile */
3081 xrenderdrv_GetImage, /* pGetImage */
3082 NULL, /* pGetKerningPairs */
3083 NULL, /* pGetNearestColor */
3084 NULL, /* pGetOutlineTextMetrics */
3085 NULL, /* pGetPixel */
3086 NULL, /* pGetPixelFormat */
3087 NULL, /* pGetSystemPaletteEntries */
3088 NULL, /* pGetTextCharsetInfo */
3089 NULL, /* pGetTextExtentExPoint */
3090 NULL, /* pGetTextExtentExPointI */
3091 NULL, /* pGetTextFace */
3092 NULL, /* pGetTextMetrics */
3093 NULL, /* pGradientFill */
3094 NULL, /* pIntersectClipRect */
3095 NULL, /* pInvertRgn */
3096 NULL, /* pLineTo */
3097 NULL, /* pModifyWorldTransform */
3098 NULL, /* pMoveTo */
3099 NULL, /* pOffsetClipRgn */
3100 NULL, /* pOffsetViewportOrg */
3101 NULL, /* pOffsetWindowOrg */
3102 NULL, /* pPaintRgn */
3103 NULL, /* pPatBlt */
3104 NULL, /* pPie */
3105 NULL, /* pPolyBezier */
3106 NULL, /* pPolyBezierTo */
3107 NULL, /* pPolyDraw */
3108 NULL, /* pPolyPolygon */
3109 NULL, /* pPolyPolyline */
3110 NULL, /* pPolygon */
3111 NULL, /* pPolyline */
3112 NULL, /* pPolylineTo */
3113 xrenderdrv_PutImage, /* pPutImage */
3114 NULL, /* pRealizeDefaultPalette */
3115 NULL, /* pRealizePalette */
3116 NULL, /* pRectangle */
3117 NULL, /* pResetDC */
3118 NULL, /* pRestoreDC */
3119 NULL, /* pRoundRect */
3120 NULL, /* pSaveDC */
3121 NULL, /* pScaleViewportExt */
3122 NULL, /* pScaleWindowExt */
3123 xrenderdrv_SelectBitmap, /* pSelectBitmap */
3124 xrenderdrv_SelectBrush, /* pSelectBrush */
3125 NULL, /* pSelectClipPath */
3126 xrenderdrv_SelectFont, /* pSelectFont */
3127 NULL, /* pSelectPalette */
3128 NULL, /* pSelectPen */
3129 NULL, /* pSetArcDirection */
3130 NULL, /* pSetBkColor */
3131 NULL, /* pSetBkMode */
3132 NULL, /* pSetDCBrushColor */
3133 NULL, /* pSetDCPenColor */
3134 NULL, /* pSetDIBColorTable */
3135 NULL, /* pSetDIBitsToDevice */
3136 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
3137 NULL, /* pSetDeviceGammaRamp */
3138 NULL, /* pSetLayout */
3139 NULL, /* pSetMapMode */
3140 NULL, /* pSetMapperFlags */
3141 NULL, /* pSetPixel */
3142 NULL, /* pSetPixelFormat */
3143 NULL, /* pSetPolyFillMode */
3144 NULL, /* pSetROP2 */
3145 NULL, /* pSetRelAbs */
3146 NULL, /* pSetStretchBltMode */
3147 NULL, /* pSetTextAlign */
3148 NULL, /* pSetTextCharacterExtra */
3149 NULL, /* pSetTextColor */
3150 NULL, /* pSetTextJustification */
3151 NULL, /* pSetViewportExt */
3152 NULL, /* pSetViewportOrg */
3153 NULL, /* pSetWindowExt */
3154 NULL, /* pSetWindowOrg */
3155 NULL, /* pSetWorldTransform */
3156 NULL, /* pStartDoc */
3157 NULL, /* pStartPage */
3158 xrenderdrv_StretchBlt, /* pStretchBlt */
3159 NULL, /* pStretchDIBits */
3160 NULL, /* pStrokeAndFillPath */
3161 NULL, /* pStrokePath */
3162 NULL, /* pSwapBuffers */
3163 NULL, /* pUnrealizePalette */
3164 NULL, /* pWidenPath */
3165 /* OpenGL not supported */
3168 #else /* SONAME_LIBXRENDER */
3170 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
3172 TRACE("XRender support not compiled in.\n");
3173 return NULL;
3176 void X11DRV_XRender_Finalize(void)
3180 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
3182 return FALSE;
3185 #endif /* SONAME_LIBXRENDER */