winex11: Implement the CopyBitmap entry point.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blob7ba61a3b9b3667d84ace6ee5d1ad3f3ddceaf885
1 /*
2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
6 * Copyright 2011 Alexandre Julliard
8 * Some parts also:
9 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <stdlib.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "x11drv.h"
36 #include "winternl.h"
37 #include "wine/library.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 int using_client_side_fonts = FALSE;
43 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
45 #ifdef SONAME_LIBXRENDER
47 static BOOL X11DRV_XRender_Installed = FALSE;
49 #include <X11/Xlib.h>
50 #include <X11/extensions/Xrender.h>
52 #ifndef RepeatNone /* added in 0.10 */
53 #define RepeatNone 0
54 #define RepeatNormal 1
55 #define RepeatPad 2
56 #define RepeatReflect 3
57 #endif
59 enum wxr_format
61 WXR_FORMAT_MONO,
62 WXR_FORMAT_GRAY,
63 WXR_FORMAT_X1R5G5B5,
64 WXR_FORMAT_X1B5G5R5,
65 WXR_FORMAT_R5G6B5,
66 WXR_FORMAT_B5G6R5,
67 WXR_FORMAT_R8G8B8,
68 WXR_FORMAT_B8G8R8,
69 WXR_FORMAT_A8R8G8B8,
70 WXR_FORMAT_B8G8R8A8,
71 WXR_FORMAT_X8R8G8B8,
72 WXR_FORMAT_B8G8R8X8,
73 WXR_NB_FORMATS,
74 WXR_INVALID_FORMAT = WXR_NB_FORMATS
77 typedef struct wine_xrender_format_template
79 unsigned int depth;
80 unsigned int alpha;
81 unsigned int alphaMask;
82 unsigned int red;
83 unsigned int redMask;
84 unsigned int green;
85 unsigned int greenMask;
86 unsigned int blue;
87 unsigned int blueMask;
88 } WineXRenderFormatTemplate;
90 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
92 /* Format depth alpha mask red mask green mask blue mask*/
93 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
94 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
95 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
96 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
97 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
98 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
99 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
101 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
103 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
107 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
109 /* format phys red phys green phys blue log red log green log blue */
110 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
111 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
112 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
113 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
114 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
115 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
116 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
118 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
120 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
124 static enum wxr_format default_format = WXR_INVALID_FORMAT;
125 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
127 typedef struct
129 LOGFONTW lf;
130 XFORM xform;
131 SIZE devsize; /* size in device coords */
132 DWORD hash;
133 } LFANDSIZE;
135 #define INITIAL_REALIZED_BUF_SIZE 128
137 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
139 typedef struct
141 GlyphSet glyphset;
142 XRenderPictFormat *font_format;
143 int nrealized;
144 BOOL *realized;
145 void **bitmaps;
146 XGlyphInfo *gis;
147 } gsCacheEntryFormat;
149 typedef struct
151 LFANDSIZE lfsz;
152 AA_Type aa_default;
153 gsCacheEntryFormat * format[AA_MAXVALUE];
154 INT count;
155 INT next;
156 } gsCacheEntry;
158 struct xrender_physdev
160 struct gdi_physdev dev;
161 X11DRV_PDEVICE *x11dev;
162 enum wxr_format format;
163 int cache_index;
164 BOOL update_clip;
165 Picture pict;
166 Picture pict_src;
167 XRenderPictFormat *pict_format;
170 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
172 return (struct xrender_physdev *)dev;
175 static const struct gdi_dc_funcs xrender_funcs;
177 static gsCacheEntry *glyphsetCache = NULL;
178 static DWORD glyphsetCacheSize = 0;
179 static INT lastfree = -1;
180 static INT mru = -1;
182 #define INIT_CACHE_SIZE 10
184 static int antialias = 1;
186 static void *xrender_handle;
188 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
189 MAKE_FUNCPTR(XRenderAddGlyphs)
190 MAKE_FUNCPTR(XRenderComposite)
191 MAKE_FUNCPTR(XRenderCompositeText16)
192 MAKE_FUNCPTR(XRenderCreateGlyphSet)
193 MAKE_FUNCPTR(XRenderCreatePicture)
194 MAKE_FUNCPTR(XRenderFillRectangle)
195 MAKE_FUNCPTR(XRenderFindFormat)
196 MAKE_FUNCPTR(XRenderFindVisualFormat)
197 MAKE_FUNCPTR(XRenderFreeGlyphSet)
198 MAKE_FUNCPTR(XRenderFreePicture)
199 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
200 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
201 MAKE_FUNCPTR(XRenderSetPictureTransform)
202 #endif
203 MAKE_FUNCPTR(XRenderQueryExtension)
205 #ifdef SONAME_LIBFONTCONFIG
206 #include <fontconfig/fontconfig.h>
207 MAKE_FUNCPTR(FcConfigSubstitute)
208 MAKE_FUNCPTR(FcDefaultSubstitute)
209 MAKE_FUNCPTR(FcFontMatch)
210 MAKE_FUNCPTR(FcInit)
211 MAKE_FUNCPTR(FcPatternCreate)
212 MAKE_FUNCPTR(FcPatternDestroy)
213 MAKE_FUNCPTR(FcPatternAddInteger)
214 MAKE_FUNCPTR(FcPatternAddString)
215 MAKE_FUNCPTR(FcPatternGetBool)
216 MAKE_FUNCPTR(FcPatternGetInteger)
217 MAKE_FUNCPTR(FcPatternGetString)
218 static void *fontconfig_handle;
219 static BOOL fontconfig_installed;
220 #endif
222 #undef MAKE_FUNCPTR
224 static CRITICAL_SECTION xrender_cs;
225 static CRITICAL_SECTION_DEBUG critsect_debug =
227 0, 0, &xrender_cs,
228 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
229 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
231 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
233 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
234 ( ( (ULONG)_x4 << 24 ) | \
235 ( (ULONG)_x3 << 16 ) | \
236 ( (ULONG)_x2 << 8 ) | \
237 (ULONG)_x1 )
239 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
241 #define GASP_GRIDFIT 0x01
242 #define GASP_DOGRAY 0x02
244 #ifdef WORDS_BIGENDIAN
245 #define get_be_word(x) (x)
246 #define NATIVE_BYTE_ORDER MSBFirst
247 #else
248 #define get_be_word(x) RtlUshortByteSwap(x)
249 #define NATIVE_BYTE_ORDER LSBFirst
250 #endif
252 static BOOL has_alpha( enum wxr_format format )
254 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
257 static enum wxr_format get_format_without_alpha( enum wxr_format format )
259 switch (format)
261 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
262 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
263 default: return format;
267 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
269 templ->id = 0;
270 templ->type = PictTypeDirect;
271 templ->depth = fmt->depth;
272 templ->direct.alpha = fmt->alpha;
273 templ->direct.alphaMask = fmt->alphaMask;
274 templ->direct.red = fmt->red;
275 templ->direct.redMask = fmt->redMask;
276 templ->direct.green = fmt->green;
277 templ->direct.greenMask = fmt->greenMask;
278 templ->direct.blue = fmt->blue;
279 templ->direct.blueMask = fmt->blueMask;
280 templ->colormap = 0;
282 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
284 return TRUE;
287 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
289 if(fmt->depth != screen_depth)
290 return FALSE;
291 if( (fmt->redMask << fmt->red) != visual->red_mask)
292 return FALSE;
293 if( (fmt->greenMask << fmt->green) != visual->green_mask)
294 return FALSE;
295 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
296 return FALSE;
298 /* We never select a default ARGB visual */
299 if(fmt->alphaMask)
300 return FALSE;
302 return TRUE;
305 static int load_xrender_formats(void)
307 int count = 0;
308 unsigned int i;
310 for (i = 0; i < WXR_NB_FORMATS; i++)
312 XRenderPictFormat templ;
314 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
316 wine_tsx11_lock();
317 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
318 if (!pict_formats[i])
320 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
321 if (visual->class == DirectColor)
323 XVisualInfo info;
324 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
325 screen_depth, TrueColor, &info ))
327 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
328 if (pict_formats[i]) visual = info.visual;
332 wine_tsx11_unlock();
333 if (pict_formats[i]) default_format = i;
335 else
337 unsigned long mask = 0;
338 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
340 wine_tsx11_lock();
341 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
342 wine_tsx11_unlock();
344 if (pict_formats[i])
346 count++;
347 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
350 return count;
353 /***********************************************************************
354 * X11DRV_XRender_Init
356 * Let's see if our XServer has the extension available
359 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
361 int event_base, i;
363 if (client_side_with_render &&
364 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
367 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
368 LOAD_FUNCPTR(XRenderAddGlyphs)
369 LOAD_FUNCPTR(XRenderComposite)
370 LOAD_FUNCPTR(XRenderCompositeText16)
371 LOAD_FUNCPTR(XRenderCreateGlyphSet)
372 LOAD_FUNCPTR(XRenderCreatePicture)
373 LOAD_FUNCPTR(XRenderFillRectangle)
374 LOAD_FUNCPTR(XRenderFindFormat)
375 LOAD_FUNCPTR(XRenderFindVisualFormat)
376 LOAD_FUNCPTR(XRenderFreeGlyphSet)
377 LOAD_FUNCPTR(XRenderFreePicture)
378 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
379 LOAD_FUNCPTR(XRenderQueryExtension)
380 #undef LOAD_FUNCPTR
381 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
382 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
383 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
384 #undef LOAD_OPTIONAL_FUNCPTR
385 #endif
387 wine_tsx11_lock();
388 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
389 wine_tsx11_unlock();
390 if(X11DRV_XRender_Installed) {
391 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
392 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
394 wine_tsx11_unlock();
395 WINE_MESSAGE(
396 "Wine has detected that you probably have a buggy version\n"
397 "of libXrender.so . Because of this client side font rendering\n"
398 "will be disabled. Please upgrade this library.\n");
399 X11DRV_XRender_Installed = FALSE;
400 return NULL;
403 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
404 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
405 X11DRV_XRender_Installed = FALSE;
410 #ifdef SONAME_LIBFONTCONFIG
411 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
413 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fontconfig_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
414 LOAD_FUNCPTR(FcConfigSubstitute);
415 LOAD_FUNCPTR(FcDefaultSubstitute);
416 LOAD_FUNCPTR(FcFontMatch);
417 LOAD_FUNCPTR(FcInit);
418 LOAD_FUNCPTR(FcPatternCreate);
419 LOAD_FUNCPTR(FcPatternDestroy);
420 LOAD_FUNCPTR(FcPatternAddInteger);
421 LOAD_FUNCPTR(FcPatternAddString);
422 LOAD_FUNCPTR(FcPatternGetBool);
423 LOAD_FUNCPTR(FcPatternGetInteger);
424 LOAD_FUNCPTR(FcPatternGetString);
425 #undef LOAD_FUNCPTR
426 fontconfig_installed = pFcInit();
428 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
429 #endif
431 sym_not_found:
432 if(X11DRV_XRender_Installed || client_side_with_core)
434 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
435 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
437 glyphsetCacheSize = INIT_CACHE_SIZE;
438 lastfree = 0;
439 for(i = 0; i < INIT_CACHE_SIZE; i++) {
440 glyphsetCache[i].next = i + 1;
441 glyphsetCache[i].count = -1;
443 glyphsetCache[i-1].next = -1;
444 using_client_side_fonts = 1;
446 if(!X11DRV_XRender_Installed) {
447 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
448 if(screen_depth <= 8 || !client_side_antialias_with_core)
449 antialias = 0;
450 } else {
451 if(screen_depth <= 8 || !client_side_antialias_with_render)
452 antialias = 0;
454 return &xrender_funcs;
456 TRACE("Using X11 core fonts\n");
457 return NULL;
460 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
461 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
463 if(pf->direct.redMask)
464 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
465 else
466 dst_color->red = 0;
468 if(pf->direct.greenMask)
469 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
470 else
471 dst_color->green = 0;
473 if(pf->direct.blueMask)
474 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
475 else
476 dst_color->blue = 0;
478 dst_color->alpha = 0xffff;
481 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
483 int redMask, greenMask, blueMask;
484 unsigned int i;
486 if (depth == 1) return WXR_FORMAT_MONO;
488 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
489 if (!shifts) return default_format;
491 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
492 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
493 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
495 /* Try to locate a format which matches the specification of the dibsection. */
496 for(i = 0; i < WXR_NB_FORMATS; i++)
498 if( depth == wxr_formats_template[i].depth &&
499 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
500 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
501 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
502 return i;
505 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
506 ERR("No XRender format found for %u %08x/%08x/%08x\n", depth, redMask, greenMask, blueMask);
507 return WXR_INVALID_FORMAT;
510 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
512 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
514 switch (info->bmiHeader.biBitCount)
516 case 1:
517 return WXR_FORMAT_MONO;
518 case 4:
519 case 8:
520 break;
521 case 24:
522 if (info->bmiHeader.biCompression != BI_RGB) break;
523 return WXR_FORMAT_R8G8B8;
524 case 16:
525 case 32:
526 if (info->bmiHeader.biCompression == BI_BITFIELDS)
528 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
529 unsigned int i;
531 for (i = 0; i < WXR_NB_FORMATS; i++)
533 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
534 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
535 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
536 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
537 return i;
539 break;
541 if (info->bmiHeader.biCompression != BI_RGB) break;
542 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
544 return WXR_INVALID_FORMAT;
547 static enum wxr_format get_bitmap_format( int bpp )
549 enum wxr_format format = WXR_INVALID_FORMAT;
551 if (bpp == screen_bpp)
553 switch (bpp)
555 case 16: format = WXR_FORMAT_R5G6B5; break;
556 case 24: format = WXR_FORMAT_R8G8B8; break;
557 case 32: format = WXR_FORMAT_A8R8G8B8; break;
560 return format;
563 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
564 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
566 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
567 XTransform xform = {{
568 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
569 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
570 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
573 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
574 #endif
577 /* check if we can use repeating instead of scaling for the specified source DC */
578 static BOOL use_source_repeat( struct xrender_physdev *dev )
580 return (dev->x11dev->bitmap &&
581 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
582 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
585 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
587 if (!dev->pict && dev->pict_format)
589 XRenderPictureAttributes pa;
591 wine_tsx11_lock();
592 pa.subwindow_mode = IncludeInferiors;
593 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
594 dev->pict_format, CPSubwindowMode, &pa );
595 wine_tsx11_unlock();
596 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
597 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
598 dev->update_clip = TRUE;
601 if (dev->update_clip)
603 RGNDATA *clip_data;
604 HRGN rgn = 0;
606 if (clip_rect)
608 rgn = CreateRectRgnIndirect( clip_rect );
609 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
610 CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
612 else if (clip_rgn)
614 rgn = CreateRectRgn( 0, 0, 0, 0 );
615 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
618 if ((clip_data = X11DRV_GetRegionData( rgn ? rgn : dev->x11dev->region, 0 )))
620 wine_tsx11_lock();
621 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
622 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
623 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
624 wine_tsx11_unlock();
625 HeapFree( GetProcessHeap(), 0, clip_data );
627 dev->update_clip = (rgn != 0); /* have to update again if we are using a custom region */
628 if (rgn) DeleteObject( rgn );
630 return dev->pict;
633 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
635 if (!dev->pict_src && dev->pict_format)
637 XRenderPictureAttributes pa;
639 wine_tsx11_lock();
640 pa.subwindow_mode = IncludeInferiors;
641 pa.repeat = repeat ? RepeatNormal : RepeatNone;
642 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
643 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
644 wine_tsx11_unlock();
646 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
647 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
650 return dev->pict_src;
653 static void free_xrender_picture( struct xrender_physdev *dev )
655 if (dev->pict || dev->pict_src)
657 wine_tsx11_lock();
658 XFlush( gdi_display );
659 if (dev->pict)
661 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
662 pXRenderFreePicture(gdi_display, dev->pict);
663 dev->pict = 0;
665 if(dev->pict_src)
667 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
668 pXRenderFreePicture(gdi_display, dev->pict_src);
669 dev->pict_src = 0;
671 wine_tsx11_unlock();
675 /* return a mask picture used to force alpha to 0 */
676 static Picture get_no_alpha_mask(void)
678 static Pixmap pixmap;
679 static Picture pict;
681 wine_tsx11_lock();
682 if (!pict)
684 XRenderPictureAttributes pa;
685 XRenderColor col;
687 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
688 pa.repeat = RepeatNormal;
689 pa.component_alpha = True;
690 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
691 CPRepeat|CPComponentAlpha, &pa );
692 col.red = col.green = col.blue = 0xffff;
693 col.alpha = 0;
694 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
696 wine_tsx11_unlock();
697 return pict;
700 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
702 if(p1->hash != p2->hash) return TRUE;
703 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
704 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
705 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
706 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
709 #if 0
710 static void walk_cache(void)
712 int i;
714 EnterCriticalSection(&xrender_cs);
715 for(i=mru; i >= 0; i = glyphsetCache[i].next)
716 TRACE("item %d\n", i);
717 LeaveCriticalSection(&xrender_cs);
719 #endif
721 static int LookupEntry(LFANDSIZE *plfsz)
723 int i, prev_i = -1;
725 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
726 TRACE("%d\n", i);
727 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
729 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
730 glyphsetCache[i].count++;
731 if(prev_i >= 0) {
732 glyphsetCache[prev_i].next = glyphsetCache[i].next;
733 glyphsetCache[i].next = mru;
734 mru = i;
736 TRACE("found font in cache %d\n", i);
737 return i;
739 prev_i = i;
741 TRACE("font not in cache\n");
742 return -1;
745 static void FreeEntry(int entry)
747 int i, format;
749 for(format = 0; format < AA_MAXVALUE; format++) {
750 gsCacheEntryFormat * formatEntry;
752 if( !glyphsetCache[entry].format[format] )
753 continue;
755 formatEntry = glyphsetCache[entry].format[format];
757 if(formatEntry->glyphset) {
758 wine_tsx11_lock();
759 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
760 wine_tsx11_unlock();
761 formatEntry->glyphset = 0;
763 if(formatEntry->nrealized) {
764 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
765 formatEntry->realized = NULL;
766 if(formatEntry->bitmaps) {
767 for(i = 0; i < formatEntry->nrealized; i++)
768 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
769 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
770 formatEntry->bitmaps = NULL;
772 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
773 formatEntry->gis = NULL;
774 formatEntry->nrealized = 0;
777 HeapFree(GetProcessHeap(), 0, formatEntry);
778 glyphsetCache[entry].format[format] = NULL;
782 static int AllocEntry(void)
784 int best = -1, prev_best = -1, i, prev_i = -1;
786 if(lastfree >= 0) {
787 assert(glyphsetCache[lastfree].count == -1);
788 glyphsetCache[lastfree].count = 1;
789 best = lastfree;
790 lastfree = glyphsetCache[lastfree].next;
791 assert(best != mru);
792 glyphsetCache[best].next = mru;
793 mru = best;
795 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
796 return mru;
799 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
800 if(glyphsetCache[i].count == 0) {
801 best = i;
802 prev_best = prev_i;
804 prev_i = i;
807 if(best >= 0) {
808 TRACE("freeing unused glyphset at cache %d\n", best);
809 FreeEntry(best);
810 glyphsetCache[best].count = 1;
811 if(prev_best >= 0) {
812 glyphsetCache[prev_best].next = glyphsetCache[best].next;
813 glyphsetCache[best].next = mru;
814 mru = best;
815 } else {
816 assert(mru == best);
818 return mru;
821 TRACE("Growing cache\n");
823 if (glyphsetCache)
824 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
825 glyphsetCache,
826 (glyphsetCacheSize + INIT_CACHE_SIZE)
827 * sizeof(*glyphsetCache));
828 else
829 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
830 (glyphsetCacheSize + INIT_CACHE_SIZE)
831 * sizeof(*glyphsetCache));
833 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
834 i++) {
835 glyphsetCache[i].next = i + 1;
836 glyphsetCache[i].count = -1;
838 glyphsetCache[i-1].next = -1;
839 glyphsetCacheSize += INIT_CACHE_SIZE;
841 lastfree = glyphsetCache[best].next;
842 glyphsetCache[best].count = 1;
843 glyphsetCache[best].next = mru;
844 mru = best;
845 TRACE("new free cache slot at %d\n", mru);
846 return mru;
849 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
851 DWORD size;
852 WORD *gasp, *buffer;
853 WORD num_recs;
854 DWORD ppem;
855 TEXTMETRICW tm;
857 *flags = 0;
859 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
860 if(size == GDI_ERROR)
861 return FALSE;
863 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
864 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
866 GetTextMetricsW(hdc, &tm);
867 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
869 gasp++;
870 num_recs = get_be_word(*gasp);
871 gasp++;
872 while(num_recs--)
874 *flags = get_be_word(*(gasp + 1));
875 if(ppem <= get_be_word(*gasp))
876 break;
877 gasp += 2;
879 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
881 HeapFree(GetProcessHeap(), 0, buffer);
882 return TRUE;
885 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
887 AA_Type ret;
888 WORD flags;
889 UINT font_smoothing_type, font_smoothing_orientation;
891 if (X11DRV_XRender_Installed && subpixel &&
892 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
893 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
895 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
896 &font_smoothing_orientation, 0) &&
897 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
899 ret = AA_BGR;
901 else
902 ret = AA_RGB;
903 /*FIXME
904 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
905 But, Wine's subpixel rendering can support the portrait mode.
908 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
909 ret = AA_Grey;
910 else
911 ret = AA_None;
913 return ret;
916 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
918 int ret;
919 int format;
920 gsCacheEntry *entry;
921 static int hinter = -1;
922 static int subpixel = -1;
923 BOOL font_smoothing;
925 if((ret = LookupEntry(plfsz)) != -1) return ret;
927 ret = AllocEntry();
928 entry = glyphsetCache + ret;
929 entry->lfsz = *plfsz;
930 for( format = 0; format < AA_MAXVALUE; format++ ) {
931 assert( !entry->format[format] );
934 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
936 if(hinter == -1 || subpixel == -1)
938 RASTERIZER_STATUS status;
939 GetRasterizerCaps(&status, sizeof(status));
940 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
941 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
944 switch (plfsz->lf.lfQuality)
946 case ANTIALIASED_QUALITY:
947 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
948 return ret; /* ignore further configuration */
949 case CLEARTYPE_QUALITY:
950 case CLEARTYPE_NATURAL_QUALITY:
951 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
952 break;
953 case DEFAULT_QUALITY:
954 case DRAFT_QUALITY:
955 case PROOF_QUALITY:
956 default:
957 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
958 font_smoothing)
960 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
962 else
963 entry->aa_default = AA_None;
964 break;
967 font_smoothing = TRUE; /* default to enabled */
968 #ifdef SONAME_LIBFONTCONFIG
969 if (fontconfig_installed)
971 FcPattern *match, *pattern;
972 FcResult result;
973 char family[LF_FACESIZE * 4];
975 #if defined(__i386__) && defined(__GNUC__)
976 /* fontconfig generates floating point exceptions, mask them */
977 WORD cw, default_cw = 0x37f;
978 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
979 #endif
981 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
982 pattern = pFcPatternCreate();
983 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
984 if (plfsz->lf.lfWeight != FW_DONTCARE)
986 int weight;
987 switch (plfsz->lf.lfWeight)
989 case FW_THIN: weight = FC_WEIGHT_THIN; break;
990 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
991 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
992 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
993 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
994 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
995 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
996 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
997 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
998 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
1000 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
1002 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
1003 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1004 pFcDefaultSubstitute( pattern );
1005 if ((match = pFcFontMatch( NULL, pattern, &result )))
1007 int rgba;
1008 FcBool antialias;
1010 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
1011 antialias = TRUE;
1012 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
1014 FcChar8 *file;
1015 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
1017 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
1018 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
1020 switch (rgba)
1022 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1023 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1024 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1025 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1026 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1029 if (!antialias) font_smoothing = FALSE;
1030 pFcPatternDestroy( match );
1032 pFcPatternDestroy( pattern );
1034 #if defined(__i386__) && defined(__GNUC__)
1035 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
1036 #endif
1038 #endif /* SONAME_LIBFONTCONFIG */
1040 /* now check Xft resources */
1042 char *value;
1043 BOOL antialias = TRUE;
1045 wine_tsx11_lock();
1046 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1048 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1049 value[0] == '0' || !strcasecmp( value, "off" ))
1050 antialias = FALSE;
1052 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1054 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1055 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1056 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1057 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1058 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1059 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1061 wine_tsx11_unlock();
1062 if (!antialias) font_smoothing = FALSE;
1065 if (!font_smoothing) entry->aa_default = AA_None;
1067 /* we can't support subpixel without xrender */
1068 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1070 else
1071 entry->aa_default = AA_None;
1073 return ret;
1076 static void dec_ref_cache(int index)
1078 assert(index >= 0);
1079 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1080 assert(glyphsetCache[index].count > 0);
1081 glyphsetCache[index].count--;
1084 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1086 DWORD hash = 0, *ptr, two_chars;
1087 WORD *pwc;
1088 int i;
1090 hash ^= plfsz->devsize.cx;
1091 hash ^= plfsz->devsize.cy;
1092 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1093 hash ^= *ptr;
1094 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1095 hash ^= *ptr;
1096 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1097 two_chars = *ptr;
1098 pwc = (WCHAR *)&two_chars;
1099 if(!*pwc) break;
1100 *pwc = toupperW(*pwc);
1101 pwc++;
1102 *pwc = toupperW(*pwc);
1103 hash ^= two_chars;
1104 if(!*pwc) break;
1106 plfsz->hash = hash;
1107 return;
1110 /***********************************************************************
1111 * X11DRV_XRender_Finalize
1113 void X11DRV_XRender_Finalize(void)
1115 int i;
1117 EnterCriticalSection(&xrender_cs);
1118 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1119 FreeEntry(i);
1120 LeaveCriticalSection(&xrender_cs);
1123 /**********************************************************************
1124 * xrenderdrv_SelectFont
1126 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1128 struct xrender_physdev *physdev = get_xrender_dev( dev );
1129 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1130 HFONT ret = next->funcs->pSelectFont( next, hfont );
1132 if (!ret) return 0;
1134 if (physdev->x11dev->has_gdi_font)
1136 LFANDSIZE lfsz;
1138 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1140 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1141 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1142 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1143 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1144 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1145 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1147 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1148 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1149 lfsz.xform.eM21, lfsz.xform.eM22);
1151 /* Not used fields, would break hashing */
1152 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1154 lfsz_calc_hash(&lfsz);
1156 EnterCriticalSection(&xrender_cs);
1157 if (physdev->cache_index != -1)
1158 dec_ref_cache( physdev->cache_index );
1159 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1160 LeaveCriticalSection(&xrender_cs);
1162 else
1164 EnterCriticalSection( &xrender_cs );
1165 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1166 physdev->cache_index = -1;
1167 LeaveCriticalSection( &xrender_cs );
1169 return ret;
1172 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1174 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1175 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1177 if (!physdev) return FALSE;
1178 physdev->x11dev = x11dev;
1179 physdev->cache_index = -1;
1180 physdev->format = format;
1181 physdev->pict_format = pict_formats[format];
1182 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1183 return TRUE;
1186 /* store the color mask data in the bitmap info structure */
1187 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1189 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1191 info->bmiHeader.biPlanes = 1;
1192 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1193 info->bmiHeader.biCompression = BI_RGB;
1194 info->bmiHeader.biClrUsed = 0;
1196 switch (info->bmiHeader.biBitCount)
1198 case 16:
1199 colors[0] = format->direct.redMask << format->direct.red;
1200 colors[1] = format->direct.greenMask << format->direct.green;
1201 colors[2] = format->direct.blueMask << format->direct.blue;
1202 info->bmiHeader.biCompression = BI_BITFIELDS;
1203 break;
1204 case 32:
1205 colors[0] = format->direct.redMask << format->direct.red;
1206 colors[1] = format->direct.greenMask << format->direct.green;
1207 colors[2] = format->direct.blueMask << format->direct.blue;
1208 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1209 info->bmiHeader.biCompression = BI_BITFIELDS;
1210 break;
1215 /**********************************************************************
1216 * xrenderdrv_CreateDC
1218 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1219 LPCWSTR output, const DEVMODEW* initData )
1221 return create_xrender_dc( pdev, default_format );
1224 /**********************************************************************
1225 * xrenderdrv_CreateCompatibleDC
1227 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1229 if (orig) /* chain to x11drv first */
1231 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1232 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1234 /* otherwise we have been called by x11drv */
1236 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1239 /**********************************************************************
1240 * xrenderdrv_DeleteDC
1242 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1244 struct xrender_physdev *physdev = get_xrender_dev( dev );
1246 free_xrender_picture( physdev );
1248 EnterCriticalSection( &xrender_cs );
1249 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1250 LeaveCriticalSection( &xrender_cs );
1252 HeapFree( GetProcessHeap(), 0, physdev );
1253 return TRUE;
1256 /**********************************************************************
1257 * xrenderdrv_ExtEscape
1259 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1260 INT out_count, LPVOID out_data )
1262 struct xrender_physdev *physdev = get_xrender_dev( dev );
1264 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1266 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1268 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1270 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1271 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1272 return ret;
1275 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1278 /****************************************************************************
1279 * xrenderdrv_CopyBitmap
1281 static BOOL xrenderdrv_CopyBitmap( HBITMAP src, HBITMAP dst )
1283 return X11DRV_CopyBitmap( src, dst );
1286 /****************************************************************************
1287 * xrenderdrv_CreateBitmap
1289 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1291 enum wxr_format format;
1292 BITMAP bitmap;
1294 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1296 if (bitmap.bmPlanes != 1) return FALSE;
1297 format = get_bitmap_format( bitmap.bmBitsPixel );
1299 if (pict_formats[format])
1300 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1301 TRUE, &wxr_color_shifts[format] );
1303 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1304 return dev->funcs->pCreateBitmap( dev, hbitmap );
1307 /****************************************************************************
1308 * xrenderdrv_DeleteBitmap
1310 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1312 return X11DRV_DeleteBitmap( hbitmap );
1315 /***********************************************************************
1316 * xrenderdrv_SelectBitmap
1318 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1320 HBITMAP ret;
1321 struct xrender_physdev *physdev = get_xrender_dev( dev );
1323 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1324 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1325 if (ret)
1327 free_xrender_picture( physdev );
1328 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1329 physdev->x11dev->color_shifts );
1330 physdev->pict_format = pict_formats[physdev->format];
1332 return ret;
1335 /***********************************************************************
1336 * xrenderdrv_GetImage
1338 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1339 struct gdi_image_bits *bits, struct bitblt_coords *src )
1341 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1342 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1343 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1346 /***********************************************************************
1347 * xrenderdrv_SetDeviceClipping
1349 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1351 struct xrender_physdev *physdev = get_xrender_dev( dev );
1353 physdev->update_clip = TRUE;
1355 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1356 dev->funcs->pSetDeviceClipping( dev, vis_rgn, clip_rgn );
1360 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1362 XRenderPictFormat *pict_format;
1363 ColorShifts shifts;
1364 const DWORD *bitfields;
1365 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1366 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1369 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1370 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1371 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1372 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1373 return FALSE;
1375 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1376 bitfields = dib->dsBitfields;
1377 else if(bits_pixel == 24 || bits_pixel == 32)
1378 bitfields = bitfields_32;
1379 else
1380 bitfields = bitfields_16;
1382 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1383 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1385 /* Common formats should be in our picture format table. */
1386 if (!pict_format)
1388 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1389 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1390 return FALSE;
1393 physBitmap->depth = pict_format->depth;
1394 physBitmap->trueColor = TRUE;
1395 physBitmap->color_shifts = shifts;
1396 return TRUE;
1399 /************************************************************************
1400 * UploadGlyph
1402 * Helper to ExtTextOut. Must be called inside xrender_cs
1404 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1406 unsigned int buflen;
1407 char *buf;
1408 Glyph gid;
1409 GLYPHMETRICS gm;
1410 XGlyphInfo gi;
1411 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1412 gsCacheEntryFormat *formatEntry;
1413 UINT ggo_format = GGO_GLYPH_INDEX;
1414 enum wxr_format wxr_format;
1415 static const char zero[4];
1416 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1418 switch(format) {
1419 case AA_Grey:
1420 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1421 break;
1422 case AA_RGB:
1423 ggo_format |= WINE_GGO_HRGB_BITMAP;
1424 break;
1425 case AA_BGR:
1426 ggo_format |= WINE_GGO_HBGR_BITMAP;
1427 break;
1428 case AA_VRGB:
1429 ggo_format |= WINE_GGO_VRGB_BITMAP;
1430 break;
1431 case AA_VBGR:
1432 ggo_format |= WINE_GGO_VBGR_BITMAP;
1433 break;
1435 default:
1436 ERR("aa = %d - not implemented\n", format);
1437 case AA_None:
1438 ggo_format |= GGO_BITMAP;
1439 break;
1442 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1443 if(buflen == GDI_ERROR) {
1444 if(format != AA_None) {
1445 format = AA_None;
1446 entry->aa_default = AA_None;
1447 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1448 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1450 if(buflen == GDI_ERROR) {
1451 WARN("GetGlyphOutlineW failed using default glyph\n");
1452 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1453 if(buflen == GDI_ERROR) {
1454 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1455 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1456 if(buflen == GDI_ERROR) {
1457 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1458 return;
1462 TRACE("Turning off antialiasing for this monochrome font\n");
1465 /* If there is nothing for the current type, we create the entry. */
1466 if( !entry->format[format] ) {
1467 entry->format[format] = HeapAlloc(GetProcessHeap(),
1468 HEAP_ZERO_MEMORY,
1469 sizeof(gsCacheEntryFormat));
1471 formatEntry = entry->format[format];
1473 if(formatEntry->nrealized <= glyph) {
1474 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1476 if (formatEntry->realized)
1477 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1478 HEAP_ZERO_MEMORY,
1479 formatEntry->realized,
1480 formatEntry->nrealized * sizeof(BOOL));
1481 else
1482 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1483 HEAP_ZERO_MEMORY,
1484 formatEntry->nrealized * sizeof(BOOL));
1486 if(!X11DRV_XRender_Installed) {
1487 if (formatEntry->bitmaps)
1488 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1489 HEAP_ZERO_MEMORY,
1490 formatEntry->bitmaps,
1491 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1492 else
1493 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1494 HEAP_ZERO_MEMORY,
1495 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1497 if (formatEntry->gis)
1498 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1499 HEAP_ZERO_MEMORY,
1500 formatEntry->gis,
1501 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1502 else
1503 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1504 HEAP_ZERO_MEMORY,
1505 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1509 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1510 switch(format) {
1511 case AA_Grey:
1512 wxr_format = WXR_FORMAT_GRAY;
1513 break;
1515 case AA_RGB:
1516 case AA_BGR:
1517 case AA_VRGB:
1518 case AA_VBGR:
1519 wxr_format = WXR_FORMAT_A8R8G8B8;
1520 break;
1522 default:
1523 ERR("aa = %d - not implemented\n", format);
1524 case AA_None:
1525 wxr_format = WXR_FORMAT_MONO;
1526 break;
1529 wine_tsx11_lock();
1530 formatEntry->font_format = pict_formats[wxr_format];
1531 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1532 wine_tsx11_unlock();
1536 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1537 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1538 formatEntry->realized[glyph] = TRUE;
1540 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1541 buflen,
1542 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1543 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1545 gi.width = gm.gmBlackBoxX;
1546 gi.height = gm.gmBlackBoxY;
1547 gi.x = -gm.gmptGlyphOrigin.x;
1548 gi.y = gm.gmptGlyphOrigin.y;
1549 gi.xOff = gm.gmCellIncX;
1550 gi.yOff = gm.gmCellIncY;
1552 if(TRACE_ON(xrender)) {
1553 int pitch, i, j;
1554 char output[300];
1555 unsigned char *line;
1557 if(format == AA_None) {
1558 pitch = ((gi.width + 31) / 32) * 4;
1559 for(i = 0; i < gi.height; i++) {
1560 line = (unsigned char*) buf + i * pitch;
1561 output[0] = '\0';
1562 for(j = 0; j < pitch * 8; j++) {
1563 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1565 TRACE("%s\n", output);
1567 } else {
1568 static const char blks[] = " .:;!o*#";
1569 char str[2];
1571 str[1] = '\0';
1572 pitch = ((gi.width + 3) / 4) * 4;
1573 for(i = 0; i < gi.height; i++) {
1574 line = (unsigned char*) buf + i * pitch;
1575 output[0] = '\0';
1576 for(j = 0; j < pitch; j++) {
1577 str[0] = blks[line[j] >> 5];
1578 strcat(output, str);
1580 TRACE("%s\n", output);
1586 if(formatEntry->glyphset) {
1587 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1588 unsigned char *byte = (unsigned char*) buf, c;
1589 int i = buflen;
1591 while(i--) {
1592 c = *byte;
1594 /* magic to flip bit order */
1595 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1596 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1597 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1599 *byte++ = c;
1602 else if ( format != AA_Grey &&
1603 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1605 unsigned int i, *data = (unsigned int *)buf;
1606 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1608 gid = glyph;
1611 XRenderCompositeText seems to ignore 0x0 glyphs when
1612 AA_None, which means we lose the advance width of glyphs
1613 like the space. We'll pretend that such glyphs are 1x1
1614 bitmaps.
1617 if(buflen == 0)
1618 gi.width = gi.height = 1;
1620 wine_tsx11_lock();
1621 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1622 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1623 wine_tsx11_unlock();
1624 HeapFree(GetProcessHeap(), 0, buf);
1625 } else {
1626 formatEntry->bitmaps[glyph] = buf;
1629 formatEntry->gis[glyph] = gi;
1632 static void SharpGlyphMono(struct xrender_physdev *physDev, INT x, INT y,
1633 void *bitmap, XGlyphInfo *gi)
1635 unsigned char *srcLine = bitmap, *src;
1636 unsigned char bits, bitsMask;
1637 int width = gi->width;
1638 int stride = ((width + 31) & ~31) >> 3;
1639 int height = gi->height;
1640 int w;
1641 int xspan, lenspan;
1643 TRACE("%d, %d\n", x, y);
1644 x -= gi->x;
1645 y -= gi->y;
1646 while (height--)
1648 src = srcLine;
1649 srcLine += stride;
1650 w = width;
1652 bitsMask = 0x80; /* FreeType is always MSB first */
1653 bits = *src++;
1655 xspan = x;
1656 while (w)
1658 if (bits & bitsMask)
1660 lenspan = 0;
1663 lenspan++;
1664 if (lenspan == w)
1665 break;
1666 bitsMask = bitsMask >> 1;
1667 if (!bitsMask)
1669 bits = *src++;
1670 bitsMask = 0x80;
1672 } while (bits & bitsMask);
1673 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1674 physDev->x11dev->gc, xspan, y, lenspan, 1);
1675 xspan += lenspan;
1676 w -= lenspan;
1678 else
1682 w--;
1683 xspan++;
1684 if (!w)
1685 break;
1686 bitsMask = bitsMask >> 1;
1687 if (!bitsMask)
1689 bits = *src++;
1690 bitsMask = 0x80;
1692 } while (!(bits & bitsMask));
1695 y++;
1699 static void SharpGlyphGray(struct xrender_physdev *physDev, INT x, INT y,
1700 void *bitmap, XGlyphInfo *gi)
1702 unsigned char *srcLine = bitmap, *src, bits;
1703 int width = gi->width;
1704 int stride = ((width + 3) & ~3);
1705 int height = gi->height;
1706 int w;
1707 int xspan, lenspan;
1709 x -= gi->x;
1710 y -= gi->y;
1711 while (height--)
1713 src = srcLine;
1714 srcLine += stride;
1715 w = width;
1717 bits = *src++;
1718 xspan = x;
1719 while (w)
1721 if (bits >= 0x80)
1723 lenspan = 0;
1726 lenspan++;
1727 if (lenspan == w)
1728 break;
1729 bits = *src++;
1730 } while (bits >= 0x80);
1731 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1732 physDev->x11dev->gc, xspan, y, lenspan, 1);
1733 xspan += lenspan;
1734 w -= lenspan;
1736 else
1740 w--;
1741 xspan++;
1742 if (!w)
1743 break;
1744 bits = *src++;
1745 } while (bits < 0x80);
1748 y++;
1753 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1755 int s, l;
1757 s = 0;
1758 while ((mask & 1) == 0)
1760 mask >>= 1;
1761 s++;
1763 l = 0;
1764 while ((mask & 1) == 1)
1766 mask >>= 1;
1767 l++;
1769 *shift = s;
1770 *len = l;
1773 static DWORD GetField (DWORD pixel, int shift, int len)
1775 pixel = pixel & (((1 << (len)) - 1) << shift);
1776 pixel = pixel << (32 - (shift + len)) >> 24;
1777 while (len < 8)
1779 pixel |= (pixel >> len);
1780 len <<= 1;
1782 return pixel;
1786 static DWORD PutField (DWORD pixel, int shift, int len)
1788 shift = shift - (8 - len);
1789 if (len <= 8)
1790 pixel &= (((1 << len) - 1) << (8 - len));
1791 if (shift < 0)
1792 pixel >>= -shift;
1793 else
1794 pixel <<= shift;
1795 return pixel;
1798 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1799 int color)
1801 int r_shift, r_len;
1802 int g_shift, g_len;
1803 int b_shift, b_len;
1804 BYTE *maskLine, *mask, m;
1805 int maskStride;
1806 DWORD pixel;
1807 int width, height;
1808 int w, tx;
1809 BYTE src_r, src_g, src_b;
1811 x -= gi->x;
1812 y -= gi->y;
1813 width = gi->width;
1814 height = gi->height;
1816 maskLine = bitmap;
1817 maskStride = (width + 3) & ~3;
1819 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1820 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1821 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1823 src_r = GetField(color, r_shift, r_len);
1824 src_g = GetField(color, g_shift, g_len);
1825 src_b = GetField(color, b_shift, b_len);
1827 for(; height--; y++)
1829 mask = maskLine;
1830 maskLine += maskStride;
1831 w = width;
1832 tx = x;
1834 if(y < 0) continue;
1835 if(y >= image->height) break;
1837 for(; w--; tx++)
1839 if(tx >= image->width) break;
1841 m = *mask++;
1842 if(tx < 0) continue;
1844 if (m == 0xff)
1845 XPutPixel (image, tx, y, color);
1846 else if (m)
1848 BYTE r, g, b;
1850 pixel = XGetPixel (image, tx, y);
1852 r = GetField(pixel, r_shift, r_len);
1853 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1854 g = GetField(pixel, g_shift, g_len);
1855 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1856 b = GetField(pixel, b_shift, b_len);
1857 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1859 pixel = (PutField (r, r_shift, r_len) |
1860 PutField (g, g_shift, g_len) |
1861 PutField (b, b_shift, b_len));
1862 XPutPixel (image, tx, y, pixel);
1868 /*************************************************************
1869 * get_tile_pict
1871 * Returns an appropriate Picture for tiling the text colour.
1872 * Call and use result within the xrender_cs
1874 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1876 static struct
1878 Pixmap xpm;
1879 Picture pict;
1880 XRenderColor current_color;
1881 } tiles[WXR_NB_FORMATS], *tile;
1883 tile = &tiles[wxr_format];
1885 if(!tile->xpm)
1887 XRenderPictureAttributes pa;
1888 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1890 wine_tsx11_lock();
1891 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1893 pa.repeat = RepeatNormal;
1894 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1895 wine_tsx11_unlock();
1897 /* init current_color to something different from text_pixel */
1898 tile->current_color = *color;
1899 tile->current_color.red ^= 0xffff;
1901 if (wxr_format == WXR_FORMAT_MONO)
1903 /* for a 1bpp bitmap we always need a 1 in the tile */
1904 XRenderColor col;
1905 col.red = col.green = col.blue = 0;
1906 col.alpha = 0xffff;
1907 wine_tsx11_lock();
1908 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1909 wine_tsx11_unlock();
1913 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1915 wine_tsx11_lock();
1916 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1917 wine_tsx11_unlock();
1918 tile->current_color = *color;
1920 return tile->pict;
1923 /*************************************************************
1924 * get_mask_pict
1926 * Returns an appropriate Picture for masking with the specified alpha.
1927 * Call and use result within the xrender_cs
1929 static Picture get_mask_pict( int alpha )
1931 static Pixmap pixmap;
1932 static Picture pict;
1933 static int current_alpha;
1935 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1937 if (!pixmap)
1939 XRenderPictureAttributes pa;
1941 wine_tsx11_lock();
1942 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1943 pa.repeat = RepeatNormal;
1944 pict = pXRenderCreatePicture( gdi_display, pixmap,
1945 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1946 wine_tsx11_unlock();
1947 current_alpha = -1;
1950 if (alpha != current_alpha)
1952 XRenderColor col;
1953 col.red = col.green = col.blue = 0;
1954 col.alpha = current_alpha = alpha;
1955 wine_tsx11_lock();
1956 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1957 wine_tsx11_unlock();
1959 return pict;
1962 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1964 return 1;
1967 /********************************************************************
1968 * is_dib_with_colortable
1970 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1972 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1974 DIBSECTION dib;
1976 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1977 dib.dsBmih.biBitCount <= 8 )
1978 return TRUE;
1980 return FALSE;
1983 /***********************************************************************
1984 * xrenderdrv_ExtTextOut
1986 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1987 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1989 struct xrender_physdev *physdev = get_xrender_dev( dev );
1990 XGCValues xgcval;
1991 gsCacheEntry *entry;
1992 gsCacheEntryFormat *formatEntry;
1993 BOOL retv = FALSE;
1994 int textPixel, backgroundPixel;
1995 RGNDATA *saved_region = NULL;
1996 BOOL disable_antialias = FALSE;
1997 AA_Type aa_type = AA_None;
1998 unsigned int idx;
1999 Picture tile_pict = 0;
2001 if (!physdev->x11dev->has_gdi_font)
2003 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
2004 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
2007 if(is_dib_with_colortable( physdev->x11dev ))
2009 TRACE("Disabling antialiasing\n");
2010 disable_antialias = TRUE;
2013 xgcval.function = GXcopy;
2014 xgcval.background = physdev->x11dev->backgroundPixel;
2015 xgcval.fill_style = FillSolid;
2016 wine_tsx11_lock();
2017 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
2018 wine_tsx11_unlock();
2020 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2022 if(physdev->x11dev->depth == 1) {
2023 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
2024 textPixel = 0;
2025 backgroundPixel = 1;
2026 } else {
2027 textPixel = 1;
2028 backgroundPixel = 0;
2030 } else {
2031 textPixel = physdev->x11dev->textPixel;
2032 backgroundPixel = physdev->x11dev->backgroundPixel;
2035 if(flags & ETO_OPAQUE)
2037 wine_tsx11_lock();
2038 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
2039 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
2040 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
2041 lprect->right - lprect->left, lprect->bottom - lprect->top );
2042 wine_tsx11_unlock();
2045 if(count == 0)
2047 retv = TRUE;
2048 goto done_unlock;
2051 EnterCriticalSection(&xrender_cs);
2053 entry = glyphsetCache + physdev->cache_index;
2054 if( disable_antialias == FALSE )
2055 aa_type = entry->aa_default;
2056 formatEntry = entry->format[aa_type];
2058 for(idx = 0; idx < count; idx++) {
2059 if( !formatEntry ) {
2060 UploadGlyph(physdev, wstr[idx], aa_type);
2061 /* re-evaluate antialias since aa_default may have changed */
2062 if( disable_antialias == FALSE )
2063 aa_type = entry->aa_default;
2064 formatEntry = entry->format[aa_type];
2065 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
2066 UploadGlyph(physdev, wstr[idx], aa_type);
2069 if (!formatEntry)
2071 WARN("could not upload requested glyphs\n");
2072 LeaveCriticalSection(&xrender_cs);
2073 goto done_unlock;
2076 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
2077 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2079 if(X11DRV_XRender_Installed)
2081 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
2082 POINT offset = {0, 0};
2083 POINT desired, current;
2084 int render_op = PictOpOver;
2085 Picture pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
2086 XRenderColor col;
2088 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2089 So we pass zeros to the function and move to our starting position using the first
2090 element of the elts array. */
2092 desired.x = physdev->x11dev->dc_rect.left + x;
2093 desired.y = physdev->x11dev->dc_rect.top + y;
2094 current.x = current.y = 0;
2096 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
2097 tile_pict = get_tile_pict(physdev->format, &col);
2099 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2101 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
2102 render_op = PictOpOutReverse; /* This gives us 'black' text */
2104 for(idx = 0; idx < count; idx++)
2106 elts[idx].glyphset = formatEntry->glyphset;
2107 elts[idx].chars = wstr + idx;
2108 elts[idx].nchars = 1;
2109 elts[idx].xOff = desired.x - current.x;
2110 elts[idx].yOff = desired.y - current.y;
2112 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
2113 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
2115 if(!lpDx)
2117 desired.x += formatEntry->gis[wstr[idx]].xOff;
2118 desired.y += formatEntry->gis[wstr[idx]].yOff;
2120 else
2122 if(flags & ETO_PDY)
2124 offset.x += lpDx[idx * 2];
2125 offset.y += lpDx[idx * 2 + 1];
2127 else
2128 offset.x += lpDx[idx];
2129 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
2130 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
2134 wine_tsx11_lock();
2135 /* Make sure we don't have any transforms set from a previous call */
2136 set_xrender_transformation(pict, 1, 1, 0, 0);
2137 pXRenderCompositeText16(gdi_display, render_op,
2138 tile_pict,
2139 pict,
2140 formatEntry->font_format,
2141 0, 0, 0, 0, elts, count);
2142 wine_tsx11_unlock();
2143 HeapFree(GetProcessHeap(), 0, elts);
2144 } else {
2145 POINT offset = {0, 0};
2147 if (flags & ETO_CLIPPED)
2149 HRGN clip_region = CreateRectRgnIndirect( lprect );
2150 saved_region = add_extra_clipping_region( physdev->x11dev, clip_region );
2151 DeleteObject( clip_region );
2154 wine_tsx11_lock();
2155 XSetForeground( gdi_display, physdev->x11dev->gc, textPixel );
2157 if(aa_type == AA_None || physdev->x11dev->depth == 1)
2159 void (* sharp_glyph_fn)(struct xrender_physdev *, INT, INT, void *, XGlyphInfo *);
2161 if(aa_type == AA_None)
2162 sharp_glyph_fn = SharpGlyphMono;
2163 else
2164 sharp_glyph_fn = SharpGlyphGray;
2166 for(idx = 0; idx < count; idx++) {
2167 sharp_glyph_fn(physdev,
2168 physdev->x11dev->dc_rect.left + x + offset.x,
2169 physdev->x11dev->dc_rect.top + y + offset.y,
2170 formatEntry->bitmaps[wstr[idx]],
2171 &formatEntry->gis[wstr[idx]]);
2172 if(lpDx)
2174 if(flags & ETO_PDY)
2176 offset.x += lpDx[idx * 2];
2177 offset.y += lpDx[idx * 2 + 1];
2179 else
2180 offset.x += lpDx[idx];
2182 else
2184 offset.x += formatEntry->gis[wstr[idx]].xOff;
2185 offset.y += formatEntry->gis[wstr[idx]].yOff;
2188 } else {
2189 XImage *image;
2190 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2191 RECT extents = {0, 0, 0, 0};
2192 POINT cur = {0, 0};
2193 int w = physdev->x11dev->drawable_rect.right - physdev->x11dev->drawable_rect.left;
2194 int h = physdev->x11dev->drawable_rect.bottom - physdev->x11dev->drawable_rect.top;
2196 TRACE("drawable %dx%d\n", w, h);
2198 for(idx = 0; idx < count; idx++) {
2199 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2200 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2201 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2202 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2203 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2204 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2205 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2206 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2208 if(lpDx)
2210 if(flags & ETO_PDY)
2212 cur.x += lpDx[idx * 2];
2213 cur.y += lpDx[idx * 2 + 1];
2215 else
2216 cur.x += lpDx[idx];
2218 else
2220 cur.x += formatEntry->gis[wstr[idx]].xOff;
2221 cur.y += formatEntry->gis[wstr[idx]].yOff;
2224 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2225 extents.right, extents.bottom, physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2227 if(physdev->x11dev->dc_rect.left + x + extents.left >= 0) {
2228 image_x = physdev->x11dev->dc_rect.left + x + extents.left;
2229 image_off_x = 0;
2230 } else {
2231 image_x = 0;
2232 image_off_x = physdev->x11dev->dc_rect.left + x + extents.left;
2234 if(physdev->x11dev->dc_rect.top + y + extents.top >= 0) {
2235 image_y = physdev->x11dev->dc_rect.top + y + extents.top;
2236 image_off_y = 0;
2237 } else {
2238 image_y = 0;
2239 image_off_y = physdev->x11dev->dc_rect.top + y + extents.top;
2241 if(physdev->x11dev->dc_rect.left + x + extents.right < w)
2242 image_w = physdev->x11dev->dc_rect.left + x + extents.right - image_x;
2243 else
2244 image_w = w - image_x;
2245 if(physdev->x11dev->dc_rect.top + y + extents.bottom < h)
2246 image_h = physdev->x11dev->dc_rect.top + y + extents.bottom - image_y;
2247 else
2248 image_h = h - image_y;
2250 if(image_w <= 0 || image_h <= 0) goto no_image;
2252 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2253 image = XGetImage(gdi_display, physdev->x11dev->drawable,
2254 image_x, image_y, image_w, image_h,
2255 AllPlanes, ZPixmap);
2256 X11DRV_check_error();
2258 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2259 gdi_display, (int)physdev->x11dev->drawable, image_x, image_y,
2260 image_w, image_h, AllPlanes, ZPixmap,
2261 physdev->x11dev->depth, image);
2262 if(!image) {
2263 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2264 physdev->x11dev->depth);
2265 GC gc;
2266 XGCValues gcv;
2268 gcv.graphics_exposures = False;
2269 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2270 XCopyArea(gdi_display, physdev->x11dev->drawable, xpm, gc, image_x, image_y,
2271 image_w, image_h, 0, 0);
2272 XFreeGC(gdi_display, gc);
2273 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2274 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2275 ZPixmap);
2276 X11DRV_check_error();
2277 XFreePixmap(gdi_display, xpm);
2279 if(!image) goto no_image;
2281 image->red_mask = visual->red_mask;
2282 image->green_mask = visual->green_mask;
2283 image->blue_mask = visual->blue_mask;
2285 for(idx = 0; idx < count; idx++) {
2286 SmoothGlyphGray(image,
2287 offset.x + image_off_x - extents.left,
2288 offset.y + image_off_y - extents.top,
2289 formatEntry->bitmaps[wstr[idx]],
2290 &formatEntry->gis[wstr[idx]],
2291 physdev->x11dev->textPixel);
2292 if(lpDx)
2294 if(flags & ETO_PDY)
2296 offset.x += lpDx[idx * 2];
2297 offset.y += lpDx[idx * 2 + 1];
2299 else
2300 offset.x += lpDx[idx];
2302 else
2304 offset.x += formatEntry->gis[wstr[idx]].xOff;
2305 offset.y += formatEntry->gis[wstr[idx]].yOff;
2308 XPutImage(gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc, image, 0, 0,
2309 image_x, image_y, image_w, image_h);
2310 XDestroyImage(image);
2312 no_image:
2313 wine_tsx11_unlock();
2314 restore_clipping_region( physdev->x11dev, saved_region );
2316 LeaveCriticalSection(&xrender_cs);
2317 retv = TRUE;
2319 done_unlock:
2320 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2321 return retv;
2324 /* multiply the alpha channel of a picture */
2325 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
2326 int x, int y, int width, int height )
2328 XRenderPictureAttributes pa;
2329 Pixmap src_pixmap, mask_pixmap;
2330 Picture src_pict, mask_pict;
2331 XRenderColor color;
2333 wine_tsx11_lock();
2334 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2335 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2336 pa.repeat = RepeatNormal;
2337 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
2338 pa.component_alpha = True;
2339 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
2340 color.red = color.green = color.blue = color.alpha = 0xffff;
2341 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
2342 color.alpha = alpha;
2343 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
2344 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
2345 0, 0, 0, 0, x, y, width, height );
2346 pXRenderFreePicture( gdi_display, src_pict );
2347 pXRenderFreePicture( gdi_display, mask_pict );
2348 XFreePixmap( gdi_display, src_pixmap );
2349 XFreePixmap( gdi_display, mask_pixmap );
2350 wine_tsx11_unlock();
2353 /* Helper function for (stretched) blitting using xrender */
2354 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2355 int x_src, int y_src, int x_dst, int y_dst,
2356 double xscale, double yscale, int width, int height )
2358 int x_offset, y_offset;
2360 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2361 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2362 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2363 wine_tsx11_lock();
2364 if(xscale != 1.0 || yscale != 1.0)
2366 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2367 * in the wrong quadrant of the x-y plane.
2369 x_offset = (xscale < 0) ? -width : 0;
2370 y_offset = (yscale < 0) ? -height : 0;
2371 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2373 else
2375 x_offset = x_src;
2376 y_offset = y_src;
2377 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2379 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2380 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2381 wine_tsx11_unlock();
2384 /* Helper function for (stretched) mono->color blitting using xrender */
2385 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
2386 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
2387 int x_src, int y_src, int x_dst, int y_dst,
2388 double xscale, double yscale, int width, int height )
2390 Picture tile_pict;
2391 int x_offset, y_offset;
2392 XRenderColor color;
2394 /* When doing a mono->color blit, the source data is used as mask, and the source picture
2395 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
2396 * the tile data.
2398 EnterCriticalSection( &xrender_cs );
2399 color = *bg;
2400 color.alpha = 0xffff; /* tile pict needs 100% alpha */
2401 tile_pict = get_tile_pict( dst_format, &color );
2403 wine_tsx11_lock();
2404 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
2406 if (xscale != 1.0 || yscale != 1.0)
2408 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2409 * in the wrong quadrant of the x-y plane.
2411 x_offset = (xscale < 0) ? -width : 0;
2412 y_offset = (yscale < 0) ? -height : 0;
2413 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2415 else
2417 x_offset = x_src;
2418 y_offset = y_src;
2419 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2421 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
2422 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
2423 wine_tsx11_unlock();
2424 LeaveCriticalSection( &xrender_cs );
2426 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
2427 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
2428 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
2431 /* create a pixmap and render picture for an image */
2432 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
2433 struct bitblt_coords *src, enum wxr_format format,
2434 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
2436 DWORD ret;
2437 int width = src->visrect.right - src->visrect.left;
2438 int height = src->visrect.bottom - src->visrect.top;
2439 int depth = pict_formats[format]->depth;
2440 struct gdi_image_bits dst_bits;
2441 XRenderPictureAttributes pa;
2442 XImage *image;
2444 wine_tsx11_lock();
2445 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2446 info->bmiHeader.biWidth, height, 32, 0 );
2447 wine_tsx11_unlock();
2448 if (!image) return ERROR_OUTOFMEMORY;
2450 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2451 if (ret) return ret;
2453 image->data = dst_bits.ptr;
2454 /* hack: make sure the bits are readable if we are reading from a DIB section */
2455 /* to be removed once we get rid of DIB access protections */
2456 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2458 *use_repeat = (width == 1 && height == 1);
2459 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2461 wine_tsx11_lock();
2462 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2463 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2464 src->visrect.left, 0, 0, 0, width, height );
2465 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2466 wine_tsx11_unlock();
2468 /* make coordinates relative to the pixmap */
2469 src->x -= src->visrect.left;
2470 src->y -= src->visrect.top;
2471 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2473 image->data = NULL;
2474 wine_tsx11_lock();
2475 XDestroyImage( image );
2476 wine_tsx11_unlock();
2477 if (dst_bits.free) dst_bits.free( &dst_bits );
2478 return ret;
2481 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2482 Drawable drawable, const struct bitblt_coords *src,
2483 const struct bitblt_coords *dst )
2485 int width = abs( dst->width );
2486 int height = abs( dst->height );
2487 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2488 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2489 int x_dst, y_dst;
2490 Picture src_pict = 0, dst_pict, mask_pict = 0;
2491 BOOL use_repeat;
2492 double xscale, yscale;
2494 use_repeat = use_source_repeat( physdev_src );
2495 if (!use_repeat)
2497 xscale = src->width / (double)dst->width;
2498 yscale = src->height / (double)dst->height;
2500 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2502 if (drawable) /* using an intermediate pixmap */
2504 XRenderPictureAttributes pa;
2506 x_dst = dst->x;
2507 y_dst = dst->y;
2508 pa.repeat = RepeatNone;
2509 wine_tsx11_lock();
2510 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2511 wine_tsx11_unlock();
2513 else
2515 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2516 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2517 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2520 if (src->width < 0) x_src += src->width + 1;
2521 if (src->height < 0) y_src += src->height + 1;
2522 if (dst->width < 0) x_dst += dst->width + 1;
2523 if (dst->height < 0) y_dst += dst->height + 1;
2525 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2527 /* mono -> color */
2528 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2530 XRenderColor fg, bg;
2532 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, &fg );
2533 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, &bg );
2534 fg.alpha = bg.alpha = 0;
2536 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2537 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2539 else /* color -> color (can be at different depths) or mono -> mono */
2541 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2542 mask_pict = get_no_alpha_mask();
2544 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2545 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2548 if (drawable)
2550 wine_tsx11_lock();
2551 pXRenderFreePicture( gdi_display, dst_pict );
2552 wine_tsx11_unlock();
2557 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2558 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2559 Drawable drawable, struct bitblt_coords *src,
2560 struct bitblt_coords *dst, BOOL use_repeat )
2562 int x_src, y_src, x_dst, y_dst;
2563 Picture dst_pict;
2564 XRenderPictureAttributes pa;
2565 double xscale, yscale;
2567 if (drawable) /* using an intermediate pixmap */
2569 RGNDATA *clip_data = NULL;
2571 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2572 x_dst = dst->x;
2573 y_dst = dst->y;
2574 pa.repeat = RepeatNone;
2575 wine_tsx11_lock();
2576 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2577 if (clip_data)
2578 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2579 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2580 wine_tsx11_unlock();
2581 HeapFree( GetProcessHeap(), 0, clip_data );
2583 else
2585 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2586 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2587 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2590 if (!use_repeat)
2592 xscale = src->width / (double)dst->width;
2593 yscale = src->height / (double)dst->height;
2595 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2597 x_src = src->x;
2598 y_src = src->y;
2599 if (src->width < 0) x_src += src->width + 1;
2600 if (src->height < 0) y_src += src->height + 1;
2601 if (dst->width < 0) x_dst += dst->width + 1;
2602 if (dst->height < 0) y_dst += dst->height + 1;
2604 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2605 xscale, yscale, abs( dst->width ), abs( dst->height ));
2607 if (drawable)
2609 wine_tsx11_lock();
2610 pXRenderFreePicture( gdi_display, dst_pict );
2611 wine_tsx11_unlock();
2616 /***********************************************************************
2617 * xrenderdrv_StretchBlt
2619 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2620 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2622 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2623 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2624 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2626 if (src_dev->funcs != dst_dev->funcs)
2628 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2629 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2632 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2634 /* XRender is of no use for color -> mono */
2635 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2636 goto x11drv_fallback;
2638 /* if not stretching, we only need to handle format conversion */
2639 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2641 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2642 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2644 if (rop != SRCCOPY)
2646 GC tmpGC;
2647 Pixmap tmp_pixmap;
2648 struct bitblt_coords tmp;
2650 /* make coordinates relative to tmp pixmap */
2651 tmp = *dst;
2652 tmp.x -= tmp.visrect.left;
2653 tmp.y -= tmp.visrect.top;
2654 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2656 wine_tsx11_lock();
2657 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2658 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2659 XSetGraphicsExposures( gdi_display, tmpGC, False );
2660 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2661 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2662 wine_tsx11_unlock();
2664 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2665 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2667 wine_tsx11_lock();
2668 XFreePixmap( gdi_display, tmp_pixmap );
2669 XFreeGC( gdi_display, tmpGC );
2670 wine_tsx11_unlock();
2672 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2674 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2675 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2676 return TRUE;
2678 x11drv_fallback:
2679 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2683 /***********************************************************************
2684 * xrenderdrv_PutImage
2686 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2687 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2688 struct bitblt_coords *dst, DWORD rop )
2690 struct xrender_physdev *physdev;
2691 X_PHYSBITMAP *bitmap;
2692 DWORD ret;
2693 Pixmap tmp_pixmap;
2694 GC gc;
2695 enum wxr_format src_format, dst_format;
2696 XRenderPictFormat *pict_format;
2697 Pixmap src_pixmap;
2698 Picture src_pict, mask_pict = 0;
2699 BOOL use_repeat;
2701 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2703 if (hbitmap)
2705 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2706 physdev = NULL;
2707 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2709 else
2711 physdev = get_xrender_dev( dev );
2712 bitmap = NULL;
2713 dst_format = physdev->format;
2716 src_format = get_xrender_format_from_bitmapinfo( info );
2717 if (!(pict_format = pict_formats[src_format])) goto update_format;
2719 /* make sure we can create an image with the same bpp */
2720 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2721 goto update_format;
2723 /* mono <-> color conversions not supported */
2724 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2725 goto x11drv_fallback;
2727 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2729 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2731 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2732 if (!ret)
2734 struct bitblt_coords tmp;
2736 if (bitmap)
2738 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2739 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2741 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2743 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2744 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2746 X11DRV_DIB_Unlock( bitmap, TRUE );
2747 DeleteObject( rgn );
2749 else
2751 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2753 if (rop != SRCCOPY)
2755 RGNDATA *clip_data = NULL;
2757 /* make coordinates relative to tmp pixmap */
2758 tmp = *dst;
2759 tmp.x -= tmp.visrect.left;
2760 tmp.y -= tmp.visrect.top;
2761 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2763 if (clip) clip_data = add_extra_clipping_region( physdev->x11dev, clip );
2765 wine_tsx11_lock();
2766 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2767 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2768 XSetGraphicsExposures( gdi_display, gc, False );
2769 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2770 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2771 wine_tsx11_unlock();
2773 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2774 NULL, tmp_pixmap, src, &tmp, use_repeat );
2775 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2777 wine_tsx11_lock();
2778 XFreePixmap( gdi_display, tmp_pixmap );
2779 XFreeGC( gdi_display, gc );
2780 wine_tsx11_unlock();
2782 restore_clipping_region( physdev->x11dev, clip_data );
2784 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2785 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2787 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2790 wine_tsx11_lock();
2791 pXRenderFreePicture( gdi_display, src_pict );
2792 XFreePixmap( gdi_display, src_pixmap );
2793 wine_tsx11_unlock();
2795 return ret;
2797 update_format:
2798 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2799 set_color_info( pict_formats[dst_format], info );
2800 return ERROR_BAD_FORMAT;
2802 x11drv_fallback:
2803 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2804 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2805 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2809 /***********************************************************************
2810 * xrenderdrv_BlendImage
2812 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2813 struct bitblt_coords *src, struct bitblt_coords *dst,
2814 BLENDFUNCTION func )
2816 struct xrender_physdev *physdev = get_xrender_dev( dev );
2817 DWORD ret;
2818 enum wxr_format format;
2819 XRenderPictFormat *pict_format;
2820 Picture dst_pict, src_pict, mask_pict;
2821 Pixmap src_pixmap;
2822 BOOL use_repeat;
2824 if (!X11DRV_XRender_Installed)
2826 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2827 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2830 format = get_xrender_format_from_bitmapinfo( info );
2831 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2832 format = get_format_without_alpha( format );
2833 else if (format != WXR_FORMAT_A8R8G8B8)
2834 return ERROR_INVALID_PARAMETER;
2836 if (!(pict_format = pict_formats[format])) goto update_format;
2838 /* make sure we can create an image with the same bpp */
2839 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2840 goto update_format;
2842 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2843 goto update_format;
2845 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2847 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2848 if (!ret)
2850 double xscale, yscale;
2852 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2854 if (!use_repeat)
2856 xscale = src->width / (double)dst->width;
2857 yscale = src->height / (double)dst->height;
2859 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2861 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2863 EnterCriticalSection( &xrender_cs );
2864 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2866 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2867 physdev->x11dev->dc_rect.left + dst->x,
2868 physdev->x11dev->dc_rect.top + dst->y,
2869 xscale, yscale, dst->width, dst->height );
2871 wine_tsx11_lock();
2872 pXRenderFreePicture( gdi_display, src_pict );
2873 XFreePixmap( gdi_display, src_pixmap );
2874 wine_tsx11_unlock();
2876 LeaveCriticalSection( &xrender_cs );
2878 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2880 return ret;
2882 update_format:
2883 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2884 set_color_info( physdev->pict_format, info );
2885 return ERROR_BAD_FORMAT;
2889 /***********************************************************************
2890 * xrenderdrv_AlphaBlend
2892 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2893 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2895 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2896 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2897 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2898 XRenderPictureAttributes pa;
2899 Pixmap tmp_pixmap = 0;
2900 double xscale, yscale;
2901 BOOL use_repeat;
2903 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2905 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2906 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2909 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2911 SetLastError( ERROR_INVALID_PARAMETER );
2912 return FALSE;
2915 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2916 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2918 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2920 use_repeat = use_source_repeat( physdev_src );
2921 if (!use_repeat)
2923 xscale = src->width / (double)dst->width;
2924 yscale = src->height / (double)dst->height;
2926 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2928 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2930 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2932 /* mono -> color blending needs an intermediate color pixmap */
2933 XRenderColor fg, bg;
2934 int width = src->visrect.right - src->visrect.left;
2935 int height = src->visrect.bottom - src->visrect.top;
2937 /* blending doesn't use the destination DC colors */
2938 fg.red = fg.green = fg.blue = 0;
2939 bg.red = bg.green = bg.blue = 0xffff;
2940 fg.alpha = bg.alpha = 0xffff;
2942 wine_tsx11_lock();
2943 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2944 physdev_dst->pict_format->depth );
2945 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2946 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2947 CPRepeat, &pa );
2948 wine_tsx11_unlock();
2950 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2951 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2953 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2955 /* we need a source picture with no alpha */
2956 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2957 if (format != physdev_src->format)
2959 wine_tsx11_lock();
2960 pa.subwindow_mode = IncludeInferiors;
2961 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2962 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2963 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2964 wine_tsx11_unlock();
2968 if (tmp_pict) src_pict = tmp_pict;
2970 EnterCriticalSection( &xrender_cs );
2971 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2973 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2974 physdev_src->x11dev->dc_rect.left + src->x,
2975 physdev_src->x11dev->dc_rect.top + src->y,
2976 physdev_dst->x11dev->dc_rect.left + dst->x,
2977 physdev_dst->x11dev->dc_rect.top + dst->y,
2978 xscale, yscale, dst->width, dst->height );
2980 wine_tsx11_lock();
2981 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2982 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2983 wine_tsx11_unlock();
2985 LeaveCriticalSection( &xrender_cs );
2986 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2987 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2988 return TRUE;
2991 /***********************************************************************
2992 * xrenderdrv_SelectBrush
2994 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, HBITMAP bitmap,
2995 const BITMAPINFO *info, void *bits, UINT usage )
2997 struct xrender_physdev *physdev = get_xrender_dev( dev );
2998 X_PHYSBITMAP *physbitmap;
2999 enum wxr_format format;
3000 BOOL delete_bitmap = FALSE;
3001 BITMAP bm;
3002 Pixmap pixmap;
3003 Picture src_pict, dst_pict;
3004 XRenderPictureAttributes pa;
3006 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
3007 if (!bitmap && !info) goto x11drv_fallback;
3008 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
3010 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
3012 format = get_bitmap_format( info->bmiHeader.biBitCount );
3013 if (format == physdev->format || !pict_formats[format]) goto x11drv_fallback;
3014 if (!(bitmap = create_brush_bitmap( physdev->x11dev, info, bits, usage ))) return 0;
3015 physbitmap = X11DRV_get_phys_bitmap( bitmap );
3016 delete_bitmap = TRUE;
3018 else
3020 format = get_xrender_format_from_color_shifts( physbitmap->depth, &physbitmap->color_shifts );
3021 if (format == WXR_FORMAT_MONO || format == physdev->format || !pict_formats[format])
3022 goto x11drv_fallback;
3025 GetObjectW( bitmap, sizeof(bm), &bm );
3027 X11DRV_DIB_Lock( physbitmap, DIB_Status_GdiMod );
3029 wine_tsx11_lock();
3030 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
3031 physdev->pict_format->depth );
3033 pa.repeat = RepeatNone;
3034 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_formats[format], CPRepeat, &pa);
3035 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
3037 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, bm.bmWidth, bm.bmHeight );
3038 pXRenderFreePicture( gdi_display, src_pict );
3039 pXRenderFreePicture( gdi_display, dst_pict );
3041 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
3042 physdev->x11dev->brush.pixmap = pixmap;
3043 physdev->x11dev->brush.fillStyle = FillTiled;
3044 physdev->x11dev->brush.pixel = 0; /* ignored */
3045 wine_tsx11_unlock();
3047 X11DRV_DIB_Unlock( physbitmap, TRUE );
3048 if (delete_bitmap) DeleteObject( bitmap );
3049 return hbrush;
3051 x11drv_fallback:
3052 if (delete_bitmap) DeleteObject( bitmap );
3053 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
3054 return dev->funcs->pSelectBrush( dev, hbrush, bitmap, info, bits, usage );
3058 static const struct gdi_dc_funcs xrender_funcs =
3060 NULL, /* pAbortDoc */
3061 NULL, /* pAbortPath */
3062 xrenderdrv_AlphaBlend, /* pAlphaBlend */
3063 NULL, /* pAngleArc */
3064 NULL, /* pArc */
3065 NULL, /* pArcTo */
3066 NULL, /* pBeginPath */
3067 xrenderdrv_BlendImage, /* pBlendImage */
3068 NULL, /* pChoosePixelFormat */
3069 NULL, /* pChord */
3070 NULL, /* pCloseFigure */
3071 xrenderdrv_CopyBitmap, /* pCopyBitmap */
3072 xrenderdrv_CreateBitmap, /* pCreateBitmap */
3073 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
3074 xrenderdrv_CreateDC, /* pCreateDC */
3075 NULL, /* pCreateDIBSection */
3076 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
3077 xrenderdrv_DeleteDC, /* pDeleteDC */
3078 NULL, /* pDeleteObject */
3079 NULL, /* pDescribePixelFormat */
3080 NULL, /* pDeviceCapabilities */
3081 NULL, /* pEllipse */
3082 NULL, /* pEndDoc */
3083 NULL, /* pEndPage */
3084 NULL, /* pEndPath */
3085 NULL, /* pEnumFonts */
3086 NULL, /* pEnumICMProfiles */
3087 NULL, /* pExcludeClipRect */
3088 NULL, /* pExtDeviceMode */
3089 xrenderdrv_ExtEscape, /* pExtEscape */
3090 NULL, /* pExtFloodFill */
3091 NULL, /* pExtSelectClipRgn */
3092 xrenderdrv_ExtTextOut, /* pExtTextOut */
3093 NULL, /* pFillPath */
3094 NULL, /* pFillRgn */
3095 NULL, /* pFlattenPath */
3096 NULL, /* pFontIsLinked */
3097 NULL, /* pFrameRgn */
3098 NULL, /* pGdiComment */
3099 NULL, /* pGdiRealizationInfo */
3100 NULL, /* pGetCharABCWidths */
3101 NULL, /* pGetCharABCWidthsI */
3102 NULL, /* pGetCharWidth */
3103 NULL, /* pGetDeviceCaps */
3104 NULL, /* pGetDeviceGammaRamp */
3105 NULL, /* pGetFontData */
3106 NULL, /* pGetFontUnicodeRanges */
3107 NULL, /* pGetGlyphIndices */
3108 NULL, /* pGetGlyphOutline */
3109 NULL, /* pGetICMProfile */
3110 xrenderdrv_GetImage, /* pGetImage */
3111 NULL, /* pGetKerningPairs */
3112 NULL, /* pGetNearestColor */
3113 NULL, /* pGetOutlineTextMetrics */
3114 NULL, /* pGetPixel */
3115 NULL, /* pGetPixelFormat */
3116 NULL, /* pGetSystemPaletteEntries */
3117 NULL, /* pGetTextCharsetInfo */
3118 NULL, /* pGetTextExtentExPoint */
3119 NULL, /* pGetTextExtentExPointI */
3120 NULL, /* pGetTextFace */
3121 NULL, /* pGetTextMetrics */
3122 NULL, /* pGradientFill */
3123 NULL, /* pIntersectClipRect */
3124 NULL, /* pInvertRgn */
3125 NULL, /* pLineTo */
3126 NULL, /* pModifyWorldTransform */
3127 NULL, /* pMoveTo */
3128 NULL, /* pOffsetClipRgn */
3129 NULL, /* pOffsetViewportOrg */
3130 NULL, /* pOffsetWindowOrg */
3131 NULL, /* pPaintRgn */
3132 NULL, /* pPatBlt */
3133 NULL, /* pPie */
3134 NULL, /* pPolyBezier */
3135 NULL, /* pPolyBezierTo */
3136 NULL, /* pPolyDraw */
3137 NULL, /* pPolyPolygon */
3138 NULL, /* pPolyPolyline */
3139 NULL, /* pPolygon */
3140 NULL, /* pPolyline */
3141 NULL, /* pPolylineTo */
3142 xrenderdrv_PutImage, /* pPutImage */
3143 NULL, /* pRealizeDefaultPalette */
3144 NULL, /* pRealizePalette */
3145 NULL, /* pRectangle */
3146 NULL, /* pResetDC */
3147 NULL, /* pRestoreDC */
3148 NULL, /* pRoundRect */
3149 NULL, /* pSaveDC */
3150 NULL, /* pScaleViewportExt */
3151 NULL, /* pScaleWindowExt */
3152 xrenderdrv_SelectBitmap, /* pSelectBitmap */
3153 xrenderdrv_SelectBrush, /* pSelectBrush */
3154 NULL, /* pSelectClipPath */
3155 xrenderdrv_SelectFont, /* pSelectFont */
3156 NULL, /* pSelectPalette */
3157 NULL, /* pSelectPen */
3158 NULL, /* pSetArcDirection */
3159 NULL, /* pSetBkColor */
3160 NULL, /* pSetBkMode */
3161 NULL, /* pSetDCBrushColor */
3162 NULL, /* pSetDCPenColor */
3163 NULL, /* pSetDIBColorTable */
3164 NULL, /* pSetDIBitsToDevice */
3165 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
3166 NULL, /* pSetDeviceGammaRamp */
3167 NULL, /* pSetLayout */
3168 NULL, /* pSetMapMode */
3169 NULL, /* pSetMapperFlags */
3170 NULL, /* pSetPixel */
3171 NULL, /* pSetPixelFormat */
3172 NULL, /* pSetPolyFillMode */
3173 NULL, /* pSetROP2 */
3174 NULL, /* pSetRelAbs */
3175 NULL, /* pSetStretchBltMode */
3176 NULL, /* pSetTextAlign */
3177 NULL, /* pSetTextCharacterExtra */
3178 NULL, /* pSetTextColor */
3179 NULL, /* pSetTextJustification */
3180 NULL, /* pSetViewportExt */
3181 NULL, /* pSetViewportOrg */
3182 NULL, /* pSetWindowExt */
3183 NULL, /* pSetWindowOrg */
3184 NULL, /* pSetWorldTransform */
3185 NULL, /* pStartDoc */
3186 NULL, /* pStartPage */
3187 xrenderdrv_StretchBlt, /* pStretchBlt */
3188 NULL, /* pStretchDIBits */
3189 NULL, /* pStrokeAndFillPath */
3190 NULL, /* pStrokePath */
3191 NULL, /* pSwapBuffers */
3192 NULL, /* pUnrealizePalette */
3193 NULL, /* pWidenPath */
3194 /* OpenGL not supported */
3197 #else /* SONAME_LIBXRENDER */
3199 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
3201 TRACE("XRender support not compiled in.\n");
3202 return NULL;
3205 void X11DRV_XRender_Finalize(void)
3209 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
3211 return FALSE;
3214 #endif /* SONAME_LIBXRENDER */