winex11: Pre-compute the color shifts for the supported XRender formats.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
bloba51543b27e5e3bdff1b0a87e225e6cdd7b512043
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(XRenderCompositeString8)
192 MAKE_FUNCPTR(XRenderCompositeString16)
193 MAKE_FUNCPTR(XRenderCompositeString32)
194 MAKE_FUNCPTR(XRenderCompositeText16)
195 MAKE_FUNCPTR(XRenderCreateGlyphSet)
196 MAKE_FUNCPTR(XRenderCreatePicture)
197 MAKE_FUNCPTR(XRenderFillRectangle)
198 MAKE_FUNCPTR(XRenderFindFormat)
199 MAKE_FUNCPTR(XRenderFindVisualFormat)
200 MAKE_FUNCPTR(XRenderFreeGlyphSet)
201 MAKE_FUNCPTR(XRenderFreePicture)
202 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
203 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
204 MAKE_FUNCPTR(XRenderSetPictureTransform)
205 #endif
206 MAKE_FUNCPTR(XRenderQueryExtension)
208 #ifdef SONAME_LIBFONTCONFIG
209 #include <fontconfig/fontconfig.h>
210 MAKE_FUNCPTR(FcConfigSubstitute)
211 MAKE_FUNCPTR(FcDefaultSubstitute)
212 MAKE_FUNCPTR(FcFontMatch)
213 MAKE_FUNCPTR(FcInit)
214 MAKE_FUNCPTR(FcPatternCreate)
215 MAKE_FUNCPTR(FcPatternDestroy)
216 MAKE_FUNCPTR(FcPatternAddInteger)
217 MAKE_FUNCPTR(FcPatternAddString)
218 MAKE_FUNCPTR(FcPatternGetBool)
219 MAKE_FUNCPTR(FcPatternGetInteger)
220 MAKE_FUNCPTR(FcPatternGetString)
221 static void *fontconfig_handle;
222 static BOOL fontconfig_installed;
223 #endif
225 #undef MAKE_FUNCPTR
227 static CRITICAL_SECTION xrender_cs;
228 static CRITICAL_SECTION_DEBUG critsect_debug =
230 0, 0, &xrender_cs,
231 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
232 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
234 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
236 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
237 ( ( (ULONG)_x4 << 24 ) | \
238 ( (ULONG)_x3 << 16 ) | \
239 ( (ULONG)_x2 << 8 ) | \
240 (ULONG)_x1 )
242 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
244 #define GASP_GRIDFIT 0x01
245 #define GASP_DOGRAY 0x02
247 #ifdef WORDS_BIGENDIAN
248 #define get_be_word(x) (x)
249 #define NATIVE_BYTE_ORDER MSBFirst
250 #else
251 #define get_be_word(x) RtlUshortByteSwap(x)
252 #define NATIVE_BYTE_ORDER LSBFirst
253 #endif
255 static enum wxr_format get_format_without_alpha( enum wxr_format format )
257 switch (format)
259 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
260 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
261 default: return format;
265 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
267 templ->id = 0;
268 templ->type = PictTypeDirect;
269 templ->depth = fmt->depth;
270 templ->direct.alpha = fmt->alpha;
271 templ->direct.alphaMask = fmt->alphaMask;
272 templ->direct.red = fmt->red;
273 templ->direct.redMask = fmt->redMask;
274 templ->direct.green = fmt->green;
275 templ->direct.greenMask = fmt->greenMask;
276 templ->direct.blue = fmt->blue;
277 templ->direct.blueMask = fmt->blueMask;
278 templ->colormap = 0;
280 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
282 return TRUE;
285 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
287 if(fmt->depth != screen_depth)
288 return FALSE;
289 if( (fmt->redMask << fmt->red) != visual->red_mask)
290 return FALSE;
291 if( (fmt->greenMask << fmt->green) != visual->green_mask)
292 return FALSE;
293 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
294 return FALSE;
296 /* We never select a default ARGB visual */
297 if(fmt->alphaMask)
298 return FALSE;
300 return TRUE;
303 static int load_xrender_formats(void)
305 int count = 0;
306 unsigned int i;
308 for (i = 0; i < WXR_NB_FORMATS; i++)
310 XRenderPictFormat templ;
312 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
314 wine_tsx11_lock();
315 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
316 if (!pict_formats[i])
318 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
319 if (visual->class == DirectColor)
321 XVisualInfo info;
322 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
323 screen_depth, TrueColor, &info ))
325 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
326 if (pict_formats[i]) visual = info.visual;
330 wine_tsx11_unlock();
331 if (pict_formats[i]) default_format = i;
333 else
335 unsigned long mask = 0;
336 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
338 wine_tsx11_lock();
339 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
340 wine_tsx11_unlock();
342 if (pict_formats[i])
344 count++;
345 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
348 return count;
351 /***********************************************************************
352 * X11DRV_XRender_Init
354 * Let's see if our XServer has the extension available
357 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
359 int event_base, i;
361 if (client_side_with_render &&
362 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
365 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
366 LOAD_FUNCPTR(XRenderAddGlyphs)
367 LOAD_FUNCPTR(XRenderComposite)
368 LOAD_FUNCPTR(XRenderCompositeString8)
369 LOAD_FUNCPTR(XRenderCompositeString16)
370 LOAD_FUNCPTR(XRenderCompositeString32)
371 LOAD_FUNCPTR(XRenderCompositeText16)
372 LOAD_FUNCPTR(XRenderCreateGlyphSet)
373 LOAD_FUNCPTR(XRenderCreatePicture)
374 LOAD_FUNCPTR(XRenderFillRectangle)
375 LOAD_FUNCPTR(XRenderFindFormat)
376 LOAD_FUNCPTR(XRenderFindVisualFormat)
377 LOAD_FUNCPTR(XRenderFreeGlyphSet)
378 LOAD_FUNCPTR(XRenderFreePicture)
379 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
380 LOAD_FUNCPTR(XRenderQueryExtension)
381 #undef LOAD_FUNCPTR
382 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
383 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
384 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
385 #undef LOAD_OPTIONAL_FUNCPTR
386 #endif
388 wine_tsx11_lock();
389 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
390 wine_tsx11_unlock();
391 if(X11DRV_XRender_Installed) {
392 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
393 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
395 wine_tsx11_unlock();
396 WINE_MESSAGE(
397 "Wine has detected that you probably have a buggy version\n"
398 "of libXrender.so . Because of this client side font rendering\n"
399 "will be disabled. Please upgrade this library.\n");
400 X11DRV_XRender_Installed = FALSE;
401 return NULL;
404 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
405 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
406 X11DRV_XRender_Installed = FALSE;
411 #ifdef SONAME_LIBFONTCONFIG
412 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
414 #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;}
415 LOAD_FUNCPTR(FcConfigSubstitute);
416 LOAD_FUNCPTR(FcDefaultSubstitute);
417 LOAD_FUNCPTR(FcFontMatch);
418 LOAD_FUNCPTR(FcInit);
419 LOAD_FUNCPTR(FcPatternCreate);
420 LOAD_FUNCPTR(FcPatternDestroy);
421 LOAD_FUNCPTR(FcPatternAddInteger);
422 LOAD_FUNCPTR(FcPatternAddString);
423 LOAD_FUNCPTR(FcPatternGetBool);
424 LOAD_FUNCPTR(FcPatternGetInteger);
425 LOAD_FUNCPTR(FcPatternGetString);
426 #undef LOAD_FUNCPTR
427 fontconfig_installed = pFcInit();
429 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
430 #endif
432 sym_not_found:
433 if(X11DRV_XRender_Installed || client_side_with_core)
435 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
436 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
438 glyphsetCacheSize = INIT_CACHE_SIZE;
439 lastfree = 0;
440 for(i = 0; i < INIT_CACHE_SIZE; i++) {
441 glyphsetCache[i].next = i + 1;
442 glyphsetCache[i].count = -1;
444 glyphsetCache[i-1].next = -1;
445 using_client_side_fonts = 1;
447 if(!X11DRV_XRender_Installed) {
448 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
449 if(screen_depth <= 8 || !client_side_antialias_with_core)
450 antialias = 0;
451 } else {
452 if(screen_depth <= 8 || !client_side_antialias_with_render)
453 antialias = 0;
455 return &xrender_funcs;
457 TRACE("Using X11 core fonts\n");
458 return NULL;
461 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
462 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
464 if(pf->direct.redMask)
465 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
466 else
467 dst_color->red = 0;
469 if(pf->direct.greenMask)
470 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
471 else
472 dst_color->green = 0;
474 if(pf->direct.blueMask)
475 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
476 else
477 dst_color->blue = 0;
479 dst_color->alpha = 0xffff;
482 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
484 int redMask, greenMask, blueMask;
485 unsigned int i;
487 if (depth == 1) return WXR_FORMAT_MONO;
489 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
490 if (!shifts) return default_format;
492 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
493 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
494 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
496 /* Try to locate a format which matches the specification of the dibsection. */
497 for(i = 0; i < WXR_NB_FORMATS; i++)
499 if( depth == wxr_formats_template[i].depth &&
500 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
501 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
502 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
503 return i;
506 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
507 ERR("No XRender format found for %u %08x/%08x/%08x\n", depth, redMask, greenMask, blueMask);
508 return WXR_INVALID_FORMAT;
511 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info, BOOL use_alpha )
513 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
515 switch (info->bmiHeader.biBitCount)
517 case 1:
518 return WXR_FORMAT_MONO;
519 case 4:
520 case 8:
521 break;
522 case 24:
523 if (info->bmiHeader.biCompression != BI_RGB) break;
524 return WXR_FORMAT_R8G8B8;
525 case 16:
526 case 32:
527 if (info->bmiHeader.biCompression == BI_BITFIELDS)
529 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
530 unsigned int i;
532 for (i = 0; i < WXR_NB_FORMATS; i++)
534 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
535 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
536 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
537 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
538 return i;
540 break;
542 if (info->bmiHeader.biCompression != BI_RGB) break;
543 if (info->bmiHeader.biBitCount == 16) return WXR_FORMAT_X1R5G5B5;
544 return use_alpha ? WXR_FORMAT_A8R8G8B8 : WXR_FORMAT_X8R8G8B8;
546 return WXR_INVALID_FORMAT;
549 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
550 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
552 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
553 XTransform xform = {{
554 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
555 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
556 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
559 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
560 #endif
563 /* check if we can use repeating instead of scaling for the specified source DC */
564 static BOOL use_source_repeat( struct xrender_physdev *dev )
566 return (dev->x11dev->bitmap &&
567 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
568 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
571 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
573 if (!dev->pict && dev->pict_format)
575 XRenderPictureAttributes pa;
577 wine_tsx11_lock();
578 pa.subwindow_mode = IncludeInferiors;
579 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
580 dev->pict_format, CPSubwindowMode, &pa );
581 wine_tsx11_unlock();
582 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
583 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
584 dev->update_clip = TRUE;
587 if (dev->update_clip)
589 RGNDATA *clip_data;
590 HRGN rgn = 0;
592 if (clip_rect)
594 rgn = CreateRectRgnIndirect( clip_rect );
595 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
596 CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
598 else if (clip_rgn)
600 rgn = CreateRectRgn( 0, 0, 0, 0 );
601 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
604 if ((clip_data = X11DRV_GetRegionData( rgn ? rgn : dev->x11dev->region, 0 )))
606 wine_tsx11_lock();
607 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
608 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
609 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
610 wine_tsx11_unlock();
611 HeapFree( GetProcessHeap(), 0, clip_data );
613 dev->update_clip = (rgn != 0); /* have to update again if we are using a custom region */
614 if (rgn) DeleteObject( rgn );
616 return dev->pict;
619 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
621 if (!dev->pict_src && dev->pict_format)
623 XRenderPictureAttributes pa;
625 wine_tsx11_lock();
626 pa.subwindow_mode = IncludeInferiors;
627 pa.repeat = repeat ? RepeatNormal : RepeatNone;
628 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
629 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
630 wine_tsx11_unlock();
632 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
633 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
636 return dev->pict_src;
639 static void free_xrender_picture( struct xrender_physdev *dev )
641 if (dev->pict || dev->pict_src)
643 wine_tsx11_lock();
644 XFlush( gdi_display );
645 if (dev->pict)
647 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
648 pXRenderFreePicture(gdi_display, dev->pict);
649 dev->pict = 0;
651 if(dev->pict_src)
653 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
654 pXRenderFreePicture(gdi_display, dev->pict_src);
655 dev->pict_src = 0;
657 wine_tsx11_unlock();
661 /* return a mask picture used to force alpha to 0 */
662 static Picture get_no_alpha_mask(void)
664 static Pixmap pixmap;
665 static Picture pict;
667 wine_tsx11_lock();
668 if (!pict)
670 XRenderPictureAttributes pa;
671 XRenderColor col;
673 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
674 pa.repeat = RepeatNormal;
675 pa.component_alpha = True;
676 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
677 CPRepeat|CPComponentAlpha, &pa );
678 col.red = col.green = col.blue = 0xffff;
679 col.alpha = 0;
680 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
682 wine_tsx11_unlock();
683 return pict;
686 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
688 if(p1->hash != p2->hash) return TRUE;
689 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
690 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
691 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
692 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
695 #if 0
696 static void walk_cache(void)
698 int i;
700 EnterCriticalSection(&xrender_cs);
701 for(i=mru; i >= 0; i = glyphsetCache[i].next)
702 TRACE("item %d\n", i);
703 LeaveCriticalSection(&xrender_cs);
705 #endif
707 static int LookupEntry(LFANDSIZE *plfsz)
709 int i, prev_i = -1;
711 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
712 TRACE("%d\n", i);
713 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
715 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
716 glyphsetCache[i].count++;
717 if(prev_i >= 0) {
718 glyphsetCache[prev_i].next = glyphsetCache[i].next;
719 glyphsetCache[i].next = mru;
720 mru = i;
722 TRACE("found font in cache %d\n", i);
723 return i;
725 prev_i = i;
727 TRACE("font not in cache\n");
728 return -1;
731 static void FreeEntry(int entry)
733 int i, format;
735 for(format = 0; format < AA_MAXVALUE; format++) {
736 gsCacheEntryFormat * formatEntry;
738 if( !glyphsetCache[entry].format[format] )
739 continue;
741 formatEntry = glyphsetCache[entry].format[format];
743 if(formatEntry->glyphset) {
744 wine_tsx11_lock();
745 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
746 wine_tsx11_unlock();
747 formatEntry->glyphset = 0;
749 if(formatEntry->nrealized) {
750 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
751 formatEntry->realized = NULL;
752 if(formatEntry->bitmaps) {
753 for(i = 0; i < formatEntry->nrealized; i++)
754 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
755 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
756 formatEntry->bitmaps = NULL;
758 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
759 formatEntry->gis = NULL;
760 formatEntry->nrealized = 0;
763 HeapFree(GetProcessHeap(), 0, formatEntry);
764 glyphsetCache[entry].format[format] = NULL;
768 static int AllocEntry(void)
770 int best = -1, prev_best = -1, i, prev_i = -1;
772 if(lastfree >= 0) {
773 assert(glyphsetCache[lastfree].count == -1);
774 glyphsetCache[lastfree].count = 1;
775 best = lastfree;
776 lastfree = glyphsetCache[lastfree].next;
777 assert(best != mru);
778 glyphsetCache[best].next = mru;
779 mru = best;
781 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
782 return mru;
785 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
786 if(glyphsetCache[i].count == 0) {
787 best = i;
788 prev_best = prev_i;
790 prev_i = i;
793 if(best >= 0) {
794 TRACE("freeing unused glyphset at cache %d\n", best);
795 FreeEntry(best);
796 glyphsetCache[best].count = 1;
797 if(prev_best >= 0) {
798 glyphsetCache[prev_best].next = glyphsetCache[best].next;
799 glyphsetCache[best].next = mru;
800 mru = best;
801 } else {
802 assert(mru == best);
804 return mru;
807 TRACE("Growing cache\n");
809 if (glyphsetCache)
810 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
811 glyphsetCache,
812 (glyphsetCacheSize + INIT_CACHE_SIZE)
813 * sizeof(*glyphsetCache));
814 else
815 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
816 (glyphsetCacheSize + INIT_CACHE_SIZE)
817 * sizeof(*glyphsetCache));
819 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
820 i++) {
821 glyphsetCache[i].next = i + 1;
822 glyphsetCache[i].count = -1;
824 glyphsetCache[i-1].next = -1;
825 glyphsetCacheSize += INIT_CACHE_SIZE;
827 lastfree = glyphsetCache[best].next;
828 glyphsetCache[best].count = 1;
829 glyphsetCache[best].next = mru;
830 mru = best;
831 TRACE("new free cache slot at %d\n", mru);
832 return mru;
835 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
837 DWORD size;
838 WORD *gasp, *buffer;
839 WORD num_recs;
840 DWORD ppem;
841 TEXTMETRICW tm;
843 *flags = 0;
845 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
846 if(size == GDI_ERROR)
847 return FALSE;
849 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
850 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
852 GetTextMetricsW(hdc, &tm);
853 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
855 gasp++;
856 num_recs = get_be_word(*gasp);
857 gasp++;
858 while(num_recs--)
860 *flags = get_be_word(*(gasp + 1));
861 if(ppem <= get_be_word(*gasp))
862 break;
863 gasp += 2;
865 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
867 HeapFree(GetProcessHeap(), 0, buffer);
868 return TRUE;
871 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
873 AA_Type ret;
874 WORD flags;
875 UINT font_smoothing_type, font_smoothing_orientation;
877 if (X11DRV_XRender_Installed && subpixel &&
878 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
879 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
881 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
882 &font_smoothing_orientation, 0) &&
883 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
885 ret = AA_BGR;
887 else
888 ret = AA_RGB;
889 /*FIXME
890 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
891 But, Wine's subpixel rendering can support the portrait mode.
894 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
895 ret = AA_Grey;
896 else
897 ret = AA_None;
899 return ret;
902 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
904 int ret;
905 int format;
906 gsCacheEntry *entry;
907 static int hinter = -1;
908 static int subpixel = -1;
909 BOOL font_smoothing;
911 if((ret = LookupEntry(plfsz)) != -1) return ret;
913 ret = AllocEntry();
914 entry = glyphsetCache + ret;
915 entry->lfsz = *plfsz;
916 for( format = 0; format < AA_MAXVALUE; format++ ) {
917 assert( !entry->format[format] );
920 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
922 if(hinter == -1 || subpixel == -1)
924 RASTERIZER_STATUS status;
925 GetRasterizerCaps(&status, sizeof(status));
926 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
927 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
930 switch (plfsz->lf.lfQuality)
932 case ANTIALIASED_QUALITY:
933 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
934 return ret; /* ignore further configuration */
935 case CLEARTYPE_QUALITY:
936 case CLEARTYPE_NATURAL_QUALITY:
937 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
938 break;
939 case DEFAULT_QUALITY:
940 case DRAFT_QUALITY:
941 case PROOF_QUALITY:
942 default:
943 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
944 font_smoothing)
946 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
948 else
949 entry->aa_default = AA_None;
950 break;
953 font_smoothing = TRUE; /* default to enabled */
954 #ifdef SONAME_LIBFONTCONFIG
955 if (fontconfig_installed)
957 FcPattern *match, *pattern = pFcPatternCreate();
958 FcResult result;
959 char family[LF_FACESIZE * 4];
961 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
962 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
963 if (plfsz->lf.lfWeight != FW_DONTCARE)
965 int weight;
966 switch (plfsz->lf.lfWeight)
968 case FW_THIN: weight = FC_WEIGHT_THIN; break;
969 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
970 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
971 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
972 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
973 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
974 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
975 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
976 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
977 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
979 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
981 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
982 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
983 pFcDefaultSubstitute( pattern );
984 if ((match = pFcFontMatch( NULL, pattern, &result )))
986 int rgba;
987 FcBool antialias;
989 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
990 antialias = TRUE;
991 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
993 FcChar8 *file;
994 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
996 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
997 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
999 switch (rgba)
1001 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1002 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1003 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1004 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1005 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1008 if (!antialias) font_smoothing = FALSE;
1009 pFcPatternDestroy( match );
1011 pFcPatternDestroy( pattern );
1013 #endif /* SONAME_LIBFONTCONFIG */
1015 /* now check Xft resources */
1017 char *value;
1018 BOOL antialias = TRUE;
1020 wine_tsx11_lock();
1021 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1023 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1024 value[0] == '0' || !strcasecmp( value, "off" ))
1025 antialias = FALSE;
1027 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1029 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1030 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1031 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1032 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1033 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1034 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1036 wine_tsx11_unlock();
1037 if (!antialias) font_smoothing = FALSE;
1040 if (!font_smoothing) entry->aa_default = AA_None;
1042 /* we can't support subpixel without xrender */
1043 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1045 else
1046 entry->aa_default = AA_None;
1048 return ret;
1051 static void dec_ref_cache(int index)
1053 assert(index >= 0);
1054 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1055 assert(glyphsetCache[index].count > 0);
1056 glyphsetCache[index].count--;
1059 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1061 DWORD hash = 0, *ptr, two_chars;
1062 WORD *pwc;
1063 int i;
1065 hash ^= plfsz->devsize.cx;
1066 hash ^= plfsz->devsize.cy;
1067 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1068 hash ^= *ptr;
1069 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1070 hash ^= *ptr;
1071 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1072 two_chars = *ptr;
1073 pwc = (WCHAR *)&two_chars;
1074 if(!*pwc) break;
1075 *pwc = toupperW(*pwc);
1076 pwc++;
1077 *pwc = toupperW(*pwc);
1078 hash ^= two_chars;
1079 if(!*pwc) break;
1081 plfsz->hash = hash;
1082 return;
1085 /***********************************************************************
1086 * X11DRV_XRender_Finalize
1088 void X11DRV_XRender_Finalize(void)
1090 int i;
1092 EnterCriticalSection(&xrender_cs);
1093 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1094 FreeEntry(i);
1095 LeaveCriticalSection(&xrender_cs);
1098 /**********************************************************************
1099 * xrenderdrv_SelectFont
1101 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
1103 struct xrender_physdev *physdev = get_xrender_dev( dev );
1104 LFANDSIZE lfsz;
1106 if (!GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf )) return HGDI_ERROR;
1108 if (!gdiFont)
1110 dev = GET_NEXT_PHYSDEV( dev, pSelectFont );
1111 return dev->funcs->pSelectFont( dev, hfont, gdiFont );
1114 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1115 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1116 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1117 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1118 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1119 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1121 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1122 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1123 lfsz.xform.eM21, lfsz.xform.eM22);
1125 /* Not used fields, would break hashing */
1126 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1128 lfsz_calc_hash(&lfsz);
1130 EnterCriticalSection(&xrender_cs);
1131 if (physdev->cache_index != -1)
1132 dec_ref_cache( physdev->cache_index );
1133 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1134 LeaveCriticalSection(&xrender_cs);
1135 physdev->x11dev->has_gdi_font = TRUE;
1136 return 0;
1139 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1141 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1142 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1144 if (!physdev) return FALSE;
1145 physdev->x11dev = x11dev;
1146 physdev->cache_index = -1;
1147 physdev->format = format;
1148 physdev->pict_format = pict_formats[format];
1149 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1150 return TRUE;
1153 /* store the color mask data in the bitmap info structure */
1154 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1156 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1158 info->bmiHeader.biPlanes = 1;
1159 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1160 info->bmiHeader.biCompression = BI_RGB;
1161 info->bmiHeader.biClrUsed = 0;
1163 switch (info->bmiHeader.biBitCount)
1165 case 16:
1166 colors[0] = format->direct.redMask << format->direct.red;
1167 colors[1] = format->direct.greenMask << format->direct.green;
1168 colors[2] = format->direct.blueMask << format->direct.blue;
1169 info->bmiHeader.biCompression = BI_BITFIELDS;
1170 break;
1171 case 32:
1172 colors[0] = format->direct.redMask << format->direct.red;
1173 colors[1] = format->direct.greenMask << format->direct.green;
1174 colors[2] = format->direct.blueMask << format->direct.blue;
1175 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1176 info->bmiHeader.biCompression = BI_BITFIELDS;
1177 break;
1182 /**********************************************************************
1183 * xrenderdrv_CreateDC
1185 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1186 LPCWSTR output, const DEVMODEW* initData )
1188 return create_xrender_dc( pdev, default_format );
1191 /**********************************************************************
1192 * xrenderdrv_CreateCompatibleDC
1194 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1196 if (orig) /* chain to x11drv first */
1198 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1199 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1201 /* otherwise we have been called by x11drv */
1203 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1206 /**********************************************************************
1207 * xrenderdrv_DeleteDC
1209 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1211 struct xrender_physdev *physdev = get_xrender_dev( dev );
1213 free_xrender_picture( physdev );
1215 EnterCriticalSection( &xrender_cs );
1216 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1217 LeaveCriticalSection( &xrender_cs );
1219 HeapFree( GetProcessHeap(), 0, physdev );
1220 return TRUE;
1223 /**********************************************************************
1224 * xrenderdrv_ExtEscape
1226 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1227 INT out_count, LPVOID out_data )
1229 struct xrender_physdev *physdev = get_xrender_dev( dev );
1231 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1233 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1235 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1237 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1238 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1239 return ret;
1242 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1245 /****************************************************************************
1246 * xrenderdrv_CreateBitmap
1248 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1250 enum wxr_format format = WXR_INVALID_FORMAT;
1251 BITMAP bitmap;
1253 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1255 if (bitmap.bmPlanes == 1 && bitmap.bmBitsPixel == screen_bpp)
1257 switch (bitmap.bmBitsPixel)
1259 case 16: format = WXR_FORMAT_R5G6B5; break;
1260 case 24: format = WXR_FORMAT_R8G8B8; break;
1261 case 32: format = WXR_FORMAT_A8R8G8B8; break;
1265 if (pict_formats[format])
1266 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1267 TRUE, &wxr_color_shifts[format] );
1269 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1270 return dev->funcs->pCreateBitmap( dev, hbitmap );
1273 /****************************************************************************
1274 * xrenderdrv_DeleteBitmap
1276 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1278 return X11DRV_DeleteBitmap( hbitmap );
1281 /***********************************************************************
1282 * xrenderdrv_SelectBitmap
1284 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1286 HBITMAP ret;
1287 struct xrender_physdev *physdev = get_xrender_dev( dev );
1289 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1290 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1291 if (ret)
1293 free_xrender_picture( physdev );
1294 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1295 physdev->x11dev->color_shifts );
1296 physdev->pict_format = pict_formats[physdev->format];
1298 return ret;
1301 /***********************************************************************
1302 * xrenderdrv_GetImage
1304 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1305 struct gdi_image_bits *bits, struct bitblt_coords *src )
1307 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1308 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1309 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1312 /***********************************************************************
1313 * xrenderdrv_SetDeviceClipping
1315 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1317 struct xrender_physdev *physdev = get_xrender_dev( dev );
1319 physdev->update_clip = TRUE;
1321 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1322 dev->funcs->pSetDeviceClipping( dev, vis_rgn, clip_rgn );
1326 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1328 XRenderPictFormat *pict_format;
1329 ColorShifts shifts;
1330 const DWORD *bitfields;
1331 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1332 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1335 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1336 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1337 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1338 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1339 return FALSE;
1341 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1342 bitfields = dib->dsBitfields;
1343 else if(bits_pixel == 24 || bits_pixel == 32)
1344 bitfields = bitfields_32;
1345 else
1346 bitfields = bitfields_16;
1348 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1349 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1351 /* Common formats should be in our picture format table. */
1352 if (!pict_format)
1354 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1355 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1356 return FALSE;
1359 physBitmap->depth = pict_format->depth;
1360 physBitmap->trueColor = TRUE;
1361 physBitmap->color_shifts = shifts;
1362 return TRUE;
1365 /************************************************************************
1366 * UploadGlyph
1368 * Helper to ExtTextOut. Must be called inside xrender_cs
1370 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1372 unsigned int buflen;
1373 char *buf;
1374 Glyph gid;
1375 GLYPHMETRICS gm;
1376 XGlyphInfo gi;
1377 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1378 gsCacheEntryFormat *formatEntry;
1379 UINT ggo_format = GGO_GLYPH_INDEX;
1380 enum wxr_format wxr_format;
1381 static const char zero[4];
1382 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1384 switch(format) {
1385 case AA_Grey:
1386 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1387 break;
1388 case AA_RGB:
1389 ggo_format |= WINE_GGO_HRGB_BITMAP;
1390 break;
1391 case AA_BGR:
1392 ggo_format |= WINE_GGO_HBGR_BITMAP;
1393 break;
1394 case AA_VRGB:
1395 ggo_format |= WINE_GGO_VRGB_BITMAP;
1396 break;
1397 case AA_VBGR:
1398 ggo_format |= WINE_GGO_VBGR_BITMAP;
1399 break;
1401 default:
1402 ERR("aa = %d - not implemented\n", format);
1403 case AA_None:
1404 ggo_format |= GGO_BITMAP;
1405 break;
1408 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1409 if(buflen == GDI_ERROR) {
1410 if(format != AA_None) {
1411 format = AA_None;
1412 entry->aa_default = AA_None;
1413 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1414 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1416 if(buflen == GDI_ERROR) {
1417 WARN("GetGlyphOutlineW failed using default glyph\n");
1418 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1419 if(buflen == GDI_ERROR) {
1420 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1421 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1422 if(buflen == GDI_ERROR) {
1423 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1424 return;
1428 TRACE("Turning off antialiasing for this monochrome font\n");
1431 /* If there is nothing for the current type, we create the entry. */
1432 if( !entry->format[format] ) {
1433 entry->format[format] = HeapAlloc(GetProcessHeap(),
1434 HEAP_ZERO_MEMORY,
1435 sizeof(gsCacheEntryFormat));
1437 formatEntry = entry->format[format];
1439 if(formatEntry->nrealized <= glyph) {
1440 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1442 if (formatEntry->realized)
1443 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1444 HEAP_ZERO_MEMORY,
1445 formatEntry->realized,
1446 formatEntry->nrealized * sizeof(BOOL));
1447 else
1448 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1449 HEAP_ZERO_MEMORY,
1450 formatEntry->nrealized * sizeof(BOOL));
1452 if(!X11DRV_XRender_Installed) {
1453 if (formatEntry->bitmaps)
1454 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1455 HEAP_ZERO_MEMORY,
1456 formatEntry->bitmaps,
1457 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1458 else
1459 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1460 HEAP_ZERO_MEMORY,
1461 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1463 if (formatEntry->gis)
1464 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1465 HEAP_ZERO_MEMORY,
1466 formatEntry->gis,
1467 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1468 else
1469 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1470 HEAP_ZERO_MEMORY,
1471 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1475 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1476 switch(format) {
1477 case AA_Grey:
1478 wxr_format = WXR_FORMAT_GRAY;
1479 break;
1481 case AA_RGB:
1482 case AA_BGR:
1483 case AA_VRGB:
1484 case AA_VBGR:
1485 wxr_format = WXR_FORMAT_A8R8G8B8;
1486 break;
1488 default:
1489 ERR("aa = %d - not implemented\n", format);
1490 case AA_None:
1491 wxr_format = WXR_FORMAT_MONO;
1492 break;
1495 wine_tsx11_lock();
1496 formatEntry->font_format = pict_formats[wxr_format];
1497 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1498 wine_tsx11_unlock();
1502 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1503 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1504 formatEntry->realized[glyph] = TRUE;
1506 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1507 buflen,
1508 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1509 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1511 gi.width = gm.gmBlackBoxX;
1512 gi.height = gm.gmBlackBoxY;
1513 gi.x = -gm.gmptGlyphOrigin.x;
1514 gi.y = gm.gmptGlyphOrigin.y;
1515 gi.xOff = gm.gmCellIncX;
1516 gi.yOff = gm.gmCellIncY;
1518 if(TRACE_ON(xrender)) {
1519 int pitch, i, j;
1520 char output[300];
1521 unsigned char *line;
1523 if(format == AA_None) {
1524 pitch = ((gi.width + 31) / 32) * 4;
1525 for(i = 0; i < gi.height; i++) {
1526 line = (unsigned char*) buf + i * pitch;
1527 output[0] = '\0';
1528 for(j = 0; j < pitch * 8; j++) {
1529 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1531 TRACE("%s\n", output);
1533 } else {
1534 static const char blks[] = " .:;!o*#";
1535 char str[2];
1537 str[1] = '\0';
1538 pitch = ((gi.width + 3) / 4) * 4;
1539 for(i = 0; i < gi.height; i++) {
1540 line = (unsigned char*) buf + i * pitch;
1541 output[0] = '\0';
1542 for(j = 0; j < pitch; j++) {
1543 str[0] = blks[line[j] >> 5];
1544 strcat(output, str);
1546 TRACE("%s\n", output);
1552 if(formatEntry->glyphset) {
1553 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1554 unsigned char *byte = (unsigned char*) buf, c;
1555 int i = buflen;
1557 while(i--) {
1558 c = *byte;
1560 /* magic to flip bit order */
1561 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1562 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1563 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1565 *byte++ = c;
1568 else if ( format != AA_Grey &&
1569 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1571 unsigned int i, *data = (unsigned int *)buf;
1572 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1574 gid = glyph;
1577 XRenderCompositeText seems to ignore 0x0 glyphs when
1578 AA_None, which means we lose the advance width of glyphs
1579 like the space. We'll pretend that such glyphs are 1x1
1580 bitmaps.
1583 if(buflen == 0)
1584 gi.width = gi.height = 1;
1586 wine_tsx11_lock();
1587 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1588 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1589 wine_tsx11_unlock();
1590 HeapFree(GetProcessHeap(), 0, buf);
1591 } else {
1592 formatEntry->bitmaps[glyph] = buf;
1595 formatEntry->gis[glyph] = gi;
1598 static void SharpGlyphMono(struct xrender_physdev *physDev, INT x, INT y,
1599 void *bitmap, XGlyphInfo *gi)
1601 unsigned char *srcLine = bitmap, *src;
1602 unsigned char bits, bitsMask;
1603 int width = gi->width;
1604 int stride = ((width + 31) & ~31) >> 3;
1605 int height = gi->height;
1606 int w;
1607 int xspan, lenspan;
1609 TRACE("%d, %d\n", x, y);
1610 x -= gi->x;
1611 y -= gi->y;
1612 while (height--)
1614 src = srcLine;
1615 srcLine += stride;
1616 w = width;
1618 bitsMask = 0x80; /* FreeType is always MSB first */
1619 bits = *src++;
1621 xspan = x;
1622 while (w)
1624 if (bits & bitsMask)
1626 lenspan = 0;
1629 lenspan++;
1630 if (lenspan == w)
1631 break;
1632 bitsMask = bitsMask >> 1;
1633 if (!bitsMask)
1635 bits = *src++;
1636 bitsMask = 0x80;
1638 } while (bits & bitsMask);
1639 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1640 physDev->x11dev->gc, xspan, y, lenspan, 1);
1641 xspan += lenspan;
1642 w -= lenspan;
1644 else
1648 w--;
1649 xspan++;
1650 if (!w)
1651 break;
1652 bitsMask = bitsMask >> 1;
1653 if (!bitsMask)
1655 bits = *src++;
1656 bitsMask = 0x80;
1658 } while (!(bits & bitsMask));
1661 y++;
1665 static void SharpGlyphGray(struct xrender_physdev *physDev, INT x, INT y,
1666 void *bitmap, XGlyphInfo *gi)
1668 unsigned char *srcLine = bitmap, *src, bits;
1669 int width = gi->width;
1670 int stride = ((width + 3) & ~3);
1671 int height = gi->height;
1672 int w;
1673 int xspan, lenspan;
1675 x -= gi->x;
1676 y -= gi->y;
1677 while (height--)
1679 src = srcLine;
1680 srcLine += stride;
1681 w = width;
1683 bits = *src++;
1684 xspan = x;
1685 while (w)
1687 if (bits >= 0x80)
1689 lenspan = 0;
1692 lenspan++;
1693 if (lenspan == w)
1694 break;
1695 bits = *src++;
1696 } while (bits >= 0x80);
1697 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1698 physDev->x11dev->gc, xspan, y, lenspan, 1);
1699 xspan += lenspan;
1700 w -= lenspan;
1702 else
1706 w--;
1707 xspan++;
1708 if (!w)
1709 break;
1710 bits = *src++;
1711 } while (bits < 0x80);
1714 y++;
1719 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1721 int s, l;
1723 s = 0;
1724 while ((mask & 1) == 0)
1726 mask >>= 1;
1727 s++;
1729 l = 0;
1730 while ((mask & 1) == 1)
1732 mask >>= 1;
1733 l++;
1735 *shift = s;
1736 *len = l;
1739 static DWORD GetField (DWORD pixel, int shift, int len)
1741 pixel = pixel & (((1 << (len)) - 1) << shift);
1742 pixel = pixel << (32 - (shift + len)) >> 24;
1743 while (len < 8)
1745 pixel |= (pixel >> len);
1746 len <<= 1;
1748 return pixel;
1752 static DWORD PutField (DWORD pixel, int shift, int len)
1754 shift = shift - (8 - len);
1755 if (len <= 8)
1756 pixel &= (((1 << len) - 1) << (8 - len));
1757 if (shift < 0)
1758 pixel >>= -shift;
1759 else
1760 pixel <<= shift;
1761 return pixel;
1764 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1765 int color)
1767 int r_shift, r_len;
1768 int g_shift, g_len;
1769 int b_shift, b_len;
1770 BYTE *maskLine, *mask, m;
1771 int maskStride;
1772 DWORD pixel;
1773 int width, height;
1774 int w, tx;
1775 BYTE src_r, src_g, src_b;
1777 x -= gi->x;
1778 y -= gi->y;
1779 width = gi->width;
1780 height = gi->height;
1782 maskLine = bitmap;
1783 maskStride = (width + 3) & ~3;
1785 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1786 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1787 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1789 src_r = GetField(color, r_shift, r_len);
1790 src_g = GetField(color, g_shift, g_len);
1791 src_b = GetField(color, b_shift, b_len);
1793 for(; height--; y++)
1795 mask = maskLine;
1796 maskLine += maskStride;
1797 w = width;
1798 tx = x;
1800 if(y < 0) continue;
1801 if(y >= image->height) break;
1803 for(; w--; tx++)
1805 if(tx >= image->width) break;
1807 m = *mask++;
1808 if(tx < 0) continue;
1810 if (m == 0xff)
1811 XPutPixel (image, tx, y, color);
1812 else if (m)
1814 BYTE r, g, b;
1816 pixel = XGetPixel (image, tx, y);
1818 r = GetField(pixel, r_shift, r_len);
1819 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1820 g = GetField(pixel, g_shift, g_len);
1821 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1822 b = GetField(pixel, b_shift, b_len);
1823 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1825 pixel = (PutField (r, r_shift, r_len) |
1826 PutField (g, g_shift, g_len) |
1827 PutField (b, b_shift, b_len));
1828 XPutPixel (image, tx, y, pixel);
1834 /*************************************************************
1835 * get_tile_pict
1837 * Returns an appropriate Picture for tiling the text colour.
1838 * Call and use result within the xrender_cs
1840 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1842 static struct
1844 Pixmap xpm;
1845 Picture pict;
1846 XRenderColor current_color;
1847 } tiles[WXR_NB_FORMATS], *tile;
1849 tile = &tiles[wxr_format];
1851 if(!tile->xpm)
1853 XRenderPictureAttributes pa;
1854 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1856 wine_tsx11_lock();
1857 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1859 pa.repeat = RepeatNormal;
1860 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1861 wine_tsx11_unlock();
1863 /* init current_color to something different from text_pixel */
1864 tile->current_color = *color;
1865 tile->current_color.red ^= 0xffff;
1867 if (wxr_format == WXR_FORMAT_MONO)
1869 /* for a 1bpp bitmap we always need a 1 in the tile */
1870 XRenderColor col;
1871 col.red = col.green = col.blue = 0;
1872 col.alpha = 0xffff;
1873 wine_tsx11_lock();
1874 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1875 wine_tsx11_unlock();
1879 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1881 wine_tsx11_lock();
1882 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1883 wine_tsx11_unlock();
1884 tile->current_color = *color;
1886 return tile->pict;
1889 /*************************************************************
1890 * get_mask_pict
1892 * Returns an appropriate Picture for masking with the specified alpha.
1893 * Call and use result within the xrender_cs
1895 static Picture get_mask_pict( int alpha )
1897 static Pixmap pixmap;
1898 static Picture pict;
1899 static int current_alpha;
1901 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1903 if (!pixmap)
1905 XRenderPictureAttributes pa;
1907 wine_tsx11_lock();
1908 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1909 pa.repeat = RepeatNormal;
1910 pict = pXRenderCreatePicture( gdi_display, pixmap,
1911 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1912 wine_tsx11_unlock();
1913 current_alpha = -1;
1916 if (alpha != current_alpha)
1918 XRenderColor col;
1919 col.red = col.green = col.blue = 0;
1920 col.alpha = current_alpha = alpha;
1921 wine_tsx11_lock();
1922 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1923 wine_tsx11_unlock();
1925 return pict;
1928 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1930 return 1;
1933 /********************************************************************
1934 * is_dib_with_colortable
1936 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1938 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1940 DIBSECTION dib;
1942 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1943 dib.dsBmih.biBitCount <= 8 )
1944 return TRUE;
1946 return FALSE;
1949 /***********************************************************************
1950 * xrenderdrv_ExtTextOut
1952 BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1953 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1955 struct xrender_physdev *physdev = get_xrender_dev( dev );
1956 XGCValues xgcval;
1957 gsCacheEntry *entry;
1958 gsCacheEntryFormat *formatEntry;
1959 BOOL retv = FALSE;
1960 int textPixel, backgroundPixel;
1961 RGNDATA *saved_region = NULL;
1962 BOOL disable_antialias = FALSE;
1963 AA_Type aa_type = AA_None;
1964 unsigned int idx;
1965 Picture tile_pict = 0;
1967 if (!physdev->x11dev->has_gdi_font)
1969 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1970 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1973 if(is_dib_with_colortable( physdev->x11dev ))
1975 TRACE("Disabling antialiasing\n");
1976 disable_antialias = TRUE;
1979 xgcval.function = GXcopy;
1980 xgcval.background = physdev->x11dev->backgroundPixel;
1981 xgcval.fill_style = FillSolid;
1982 wine_tsx11_lock();
1983 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1984 wine_tsx11_unlock();
1986 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1988 if(physdev->x11dev->depth == 1) {
1989 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1990 textPixel = 0;
1991 backgroundPixel = 1;
1992 } else {
1993 textPixel = 1;
1994 backgroundPixel = 0;
1996 } else {
1997 textPixel = physdev->x11dev->textPixel;
1998 backgroundPixel = physdev->x11dev->backgroundPixel;
2001 if(flags & ETO_OPAQUE)
2003 wine_tsx11_lock();
2004 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
2005 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
2006 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
2007 lprect->right - lprect->left, lprect->bottom - lprect->top );
2008 wine_tsx11_unlock();
2011 if(count == 0)
2013 retv = TRUE;
2014 goto done_unlock;
2017 EnterCriticalSection(&xrender_cs);
2019 entry = glyphsetCache + physdev->cache_index;
2020 if( disable_antialias == FALSE )
2021 aa_type = entry->aa_default;
2022 formatEntry = entry->format[aa_type];
2024 for(idx = 0; idx < count; idx++) {
2025 if( !formatEntry ) {
2026 UploadGlyph(physdev, wstr[idx], aa_type);
2027 /* re-evaluate antialias since aa_default may have changed */
2028 if( disable_antialias == FALSE )
2029 aa_type = entry->aa_default;
2030 formatEntry = entry->format[aa_type];
2031 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
2032 UploadGlyph(physdev, wstr[idx], aa_type);
2035 if (!formatEntry)
2037 WARN("could not upload requested glyphs\n");
2038 LeaveCriticalSection(&xrender_cs);
2039 goto done_unlock;
2042 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
2043 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2045 if(X11DRV_XRender_Installed)
2047 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
2048 POINT offset = {0, 0};
2049 POINT desired, current;
2050 int render_op = PictOpOver;
2051 Picture pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
2052 XRenderColor col;
2054 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2055 So we pass zeros to the function and move to our starting position using the first
2056 element of the elts array. */
2058 desired.x = physdev->x11dev->dc_rect.left + x;
2059 desired.y = physdev->x11dev->dc_rect.top + y;
2060 current.x = current.y = 0;
2062 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
2063 tile_pict = get_tile_pict(physdev->format, &col);
2065 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2067 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
2068 render_op = PictOpOutReverse; /* This gives us 'black' text */
2070 for(idx = 0; idx < count; idx++)
2072 elts[idx].glyphset = formatEntry->glyphset;
2073 elts[idx].chars = wstr + idx;
2074 elts[idx].nchars = 1;
2075 elts[idx].xOff = desired.x - current.x;
2076 elts[idx].yOff = desired.y - current.y;
2078 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
2079 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
2081 if(!lpDx)
2083 desired.x += formatEntry->gis[wstr[idx]].xOff;
2084 desired.y += formatEntry->gis[wstr[idx]].yOff;
2086 else
2088 if(flags & ETO_PDY)
2090 offset.x += lpDx[idx * 2];
2091 offset.y += lpDx[idx * 2 + 1];
2093 else
2094 offset.x += lpDx[idx];
2095 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
2096 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
2100 wine_tsx11_lock();
2101 /* Make sure we don't have any transforms set from a previous call */
2102 set_xrender_transformation(pict, 1, 1, 0, 0);
2103 pXRenderCompositeText16(gdi_display, render_op,
2104 tile_pict,
2105 pict,
2106 formatEntry->font_format,
2107 0, 0, 0, 0, elts, count);
2108 wine_tsx11_unlock();
2109 HeapFree(GetProcessHeap(), 0, elts);
2110 } else {
2111 POINT offset = {0, 0};
2113 if (flags & ETO_CLIPPED)
2115 HRGN clip_region = CreateRectRgnIndirect( lprect );
2116 saved_region = add_extra_clipping_region( physdev->x11dev, clip_region );
2117 DeleteObject( clip_region );
2120 wine_tsx11_lock();
2121 XSetForeground( gdi_display, physdev->x11dev->gc, textPixel );
2123 if(aa_type == AA_None || physdev->x11dev->depth == 1)
2125 void (* sharp_glyph_fn)(struct xrender_physdev *, INT, INT, void *, XGlyphInfo *);
2127 if(aa_type == AA_None)
2128 sharp_glyph_fn = SharpGlyphMono;
2129 else
2130 sharp_glyph_fn = SharpGlyphGray;
2132 for(idx = 0; idx < count; idx++) {
2133 sharp_glyph_fn(physdev,
2134 physdev->x11dev->dc_rect.left + x + offset.x,
2135 physdev->x11dev->dc_rect.top + y + offset.y,
2136 formatEntry->bitmaps[wstr[idx]],
2137 &formatEntry->gis[wstr[idx]]);
2138 if(lpDx)
2140 if(flags & ETO_PDY)
2142 offset.x += lpDx[idx * 2];
2143 offset.y += lpDx[idx * 2 + 1];
2145 else
2146 offset.x += lpDx[idx];
2148 else
2150 offset.x += formatEntry->gis[wstr[idx]].xOff;
2151 offset.y += formatEntry->gis[wstr[idx]].yOff;
2154 } else {
2155 XImage *image;
2156 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2157 RECT extents = {0, 0, 0, 0};
2158 POINT cur = {0, 0};
2159 int w = physdev->x11dev->drawable_rect.right - physdev->x11dev->drawable_rect.left;
2160 int h = physdev->x11dev->drawable_rect.bottom - physdev->x11dev->drawable_rect.top;
2162 TRACE("drawable %dx%d\n", w, h);
2164 for(idx = 0; idx < count; idx++) {
2165 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2166 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2167 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2168 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2169 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2170 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2171 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2172 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2174 if(lpDx)
2176 if(flags & ETO_PDY)
2178 cur.x += lpDx[idx * 2];
2179 cur.y += lpDx[idx * 2 + 1];
2181 else
2182 cur.x += lpDx[idx];
2184 else
2186 cur.x += formatEntry->gis[wstr[idx]].xOff;
2187 cur.y += formatEntry->gis[wstr[idx]].yOff;
2190 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2191 extents.right, extents.bottom, physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2193 if(physdev->x11dev->dc_rect.left + x + extents.left >= 0) {
2194 image_x = physdev->x11dev->dc_rect.left + x + extents.left;
2195 image_off_x = 0;
2196 } else {
2197 image_x = 0;
2198 image_off_x = physdev->x11dev->dc_rect.left + x + extents.left;
2200 if(physdev->x11dev->dc_rect.top + y + extents.top >= 0) {
2201 image_y = physdev->x11dev->dc_rect.top + y + extents.top;
2202 image_off_y = 0;
2203 } else {
2204 image_y = 0;
2205 image_off_y = physdev->x11dev->dc_rect.top + y + extents.top;
2207 if(physdev->x11dev->dc_rect.left + x + extents.right < w)
2208 image_w = physdev->x11dev->dc_rect.left + x + extents.right - image_x;
2209 else
2210 image_w = w - image_x;
2211 if(physdev->x11dev->dc_rect.top + y + extents.bottom < h)
2212 image_h = physdev->x11dev->dc_rect.top + y + extents.bottom - image_y;
2213 else
2214 image_h = h - image_y;
2216 if(image_w <= 0 || image_h <= 0) goto no_image;
2218 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2219 image = XGetImage(gdi_display, physdev->x11dev->drawable,
2220 image_x, image_y, image_w, image_h,
2221 AllPlanes, ZPixmap);
2222 X11DRV_check_error();
2224 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2225 gdi_display, (int)physdev->x11dev->drawable, image_x, image_y,
2226 image_w, image_h, AllPlanes, ZPixmap,
2227 physdev->x11dev->depth, image);
2228 if(!image) {
2229 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2230 physdev->x11dev->depth);
2231 GC gc;
2232 XGCValues gcv;
2234 gcv.graphics_exposures = False;
2235 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2236 XCopyArea(gdi_display, physdev->x11dev->drawable, xpm, gc, image_x, image_y,
2237 image_w, image_h, 0, 0);
2238 XFreeGC(gdi_display, gc);
2239 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2240 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2241 ZPixmap);
2242 X11DRV_check_error();
2243 XFreePixmap(gdi_display, xpm);
2245 if(!image) goto no_image;
2247 image->red_mask = visual->red_mask;
2248 image->green_mask = visual->green_mask;
2249 image->blue_mask = visual->blue_mask;
2251 for(idx = 0; idx < count; idx++) {
2252 SmoothGlyphGray(image,
2253 offset.x + image_off_x - extents.left,
2254 offset.y + image_off_y - extents.top,
2255 formatEntry->bitmaps[wstr[idx]],
2256 &formatEntry->gis[wstr[idx]],
2257 physdev->x11dev->textPixel);
2258 if(lpDx)
2260 if(flags & ETO_PDY)
2262 offset.x += lpDx[idx * 2];
2263 offset.y += lpDx[idx * 2 + 1];
2265 else
2266 offset.x += lpDx[idx];
2268 else
2270 offset.x += formatEntry->gis[wstr[idx]].xOff;
2271 offset.y += formatEntry->gis[wstr[idx]].yOff;
2274 XPutImage(gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc, image, 0, 0,
2275 image_x, image_y, image_w, image_h);
2276 XDestroyImage(image);
2278 no_image:
2279 wine_tsx11_unlock();
2280 restore_clipping_region( physdev->x11dev, saved_region );
2282 LeaveCriticalSection(&xrender_cs);
2283 retv = TRUE;
2285 done_unlock:
2286 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2287 return retv;
2290 /* multiply the alpha channel of a picture */
2291 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
2292 int x, int y, int width, int height )
2294 XRenderPictureAttributes pa;
2295 Pixmap src_pixmap, mask_pixmap;
2296 Picture src_pict, mask_pict;
2297 XRenderColor color;
2299 wine_tsx11_lock();
2300 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2301 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2302 pa.repeat = RepeatNormal;
2303 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
2304 pa.component_alpha = True;
2305 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
2306 color.red = color.green = color.blue = color.alpha = 0xffff;
2307 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
2308 color.alpha = alpha;
2309 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
2310 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
2311 0, 0, 0, 0, x, y, width, height );
2312 pXRenderFreePicture( gdi_display, src_pict );
2313 pXRenderFreePicture( gdi_display, mask_pict );
2314 XFreePixmap( gdi_display, src_pixmap );
2315 XFreePixmap( gdi_display, mask_pixmap );
2316 wine_tsx11_unlock();
2319 /* Helper function for (stretched) blitting using xrender */
2320 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2321 int x_src, int y_src, int x_dst, int y_dst,
2322 double xscale, double yscale, int width, int height )
2324 int x_offset, y_offset;
2326 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2327 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2328 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2329 wine_tsx11_lock();
2330 if(xscale != 1.0 || yscale != 1.0)
2332 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2333 * in the wrong quadrant of the x-y plane.
2335 x_offset = (xscale < 0) ? -width : 0;
2336 y_offset = (yscale < 0) ? -height : 0;
2337 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2339 else
2341 x_offset = x_src;
2342 y_offset = y_src;
2343 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2345 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2346 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2347 wine_tsx11_unlock();
2350 /* Helper function for (stretched) mono->color blitting using xrender */
2351 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
2352 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
2353 int x_src, int y_src, int x_dst, int y_dst,
2354 double xscale, double yscale, int width, int height )
2356 Picture tile_pict;
2357 int x_offset, y_offset;
2358 XRenderColor color;
2360 /* When doing a mono->color blit, the source data is used as mask, and the source picture
2361 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
2362 * the tile data.
2364 EnterCriticalSection( &xrender_cs );
2365 color = *bg;
2366 color.alpha = 0xffff; /* tile pict needs 100% alpha */
2367 tile_pict = get_tile_pict( dst_format, &color );
2369 wine_tsx11_lock();
2370 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
2372 if (xscale != 1.0 || yscale != 1.0)
2374 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2375 * in the wrong quadrant of the x-y plane.
2377 x_offset = (xscale < 0) ? -width : 0;
2378 y_offset = (yscale < 0) ? -height : 0;
2379 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2381 else
2383 x_offset = x_src;
2384 y_offset = y_src;
2385 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2387 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
2388 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
2389 wine_tsx11_unlock();
2390 LeaveCriticalSection( &xrender_cs );
2392 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
2393 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
2394 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
2397 static void get_colors( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2398 XRenderColor *fg, XRenderColor *bg )
2400 if (physdev_src->format == WXR_FORMAT_MONO)
2402 RGBQUAD rgb[2];
2403 int pixel;
2405 if (GetDIBColorTable( physdev_src->dev.hdc, 0, 2, rgb ) == 2)
2407 pixel = X11DRV_PALETTE_ToPhysical( physdev_dst->x11dev,
2408 RGB( rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue ));
2409 get_xrender_color( physdev_dst->pict_format, pixel, fg );
2410 pixel = X11DRV_PALETTE_ToPhysical( physdev_dst->x11dev,
2411 RGB( rgb[1].rgbRed, rgb[1].rgbGreen, rgb[1].rgbBlue ));
2412 get_xrender_color( physdev_dst->pict_format, pixel, bg );
2413 return;
2416 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, fg );
2417 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, bg );
2420 /* create a pixmap and render picture for an image */
2421 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
2422 struct bitblt_coords *src, enum wxr_format format,
2423 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
2425 DWORD ret;
2426 int width = src->visrect.right - src->visrect.left;
2427 int height = src->visrect.bottom - src->visrect.top;
2428 int depth = pict_formats[format]->depth;
2429 struct gdi_image_bits dst_bits;
2430 XRenderPictureAttributes pa;
2431 XImage *image;
2433 wine_tsx11_lock();
2434 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2435 info->bmiHeader.biWidth, height, 32, 0 );
2436 wine_tsx11_unlock();
2437 if (!image) return ERROR_OUTOFMEMORY;
2439 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2440 if (ret) return ret;
2442 image->data = dst_bits.ptr;
2443 /* hack: make sure the bits are readable if we are reading from a DIB section */
2444 /* to be removed once we get rid of DIB access protections */
2445 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2447 *use_repeat = (width == 1 && height == 1);
2448 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2450 wine_tsx11_lock();
2451 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2452 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2453 src->visrect.left, 0, 0, 0, width, height );
2454 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2455 wine_tsx11_unlock();
2457 /* make coordinates relative to the pixmap */
2458 src->x -= src->visrect.left;
2459 src->y -= src->visrect.top;
2460 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2462 image->data = NULL;
2463 wine_tsx11_lock();
2464 XDestroyImage( image );
2465 wine_tsx11_unlock();
2466 if (dst_bits.free) dst_bits.free( &dst_bits );
2467 return ret;
2470 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2471 Drawable drawable, const struct bitblt_coords *src,
2472 const struct bitblt_coords *dst )
2474 int width = abs( dst->width );
2475 int height = abs( dst->height );
2476 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2477 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2478 int x_dst, y_dst;
2479 Picture src_pict = 0, dst_pict, mask_pict = 0;
2480 BOOL use_repeat;
2481 double xscale, yscale;
2483 use_repeat = use_source_repeat( physdev_src );
2484 if (!use_repeat)
2486 xscale = src->width / (double)dst->width;
2487 yscale = src->height / (double)dst->height;
2489 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2491 if (drawable) /* using an intermediate pixmap */
2493 XRenderPictureAttributes pa;
2495 x_dst = dst->x;
2496 y_dst = dst->y;
2497 pa.repeat = RepeatNone;
2498 wine_tsx11_lock();
2499 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2500 wine_tsx11_unlock();
2502 else
2504 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2505 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2506 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2509 if (src->width < 0) x_src += src->width + 1;
2510 if (src->height < 0) y_src += src->height + 1;
2511 if (dst->width < 0) x_dst += dst->width + 1;
2512 if (dst->height < 0) y_dst += dst->height + 1;
2514 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2516 /* mono -> color */
2517 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2519 XRenderColor fg, bg;
2521 get_colors( physdev_src, physdev_dst, &fg, &bg );
2522 fg.alpha = bg.alpha = 0;
2524 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2525 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2527 else /* color -> color (can be at different depths) or mono -> mono */
2529 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2530 mask_pict = get_no_alpha_mask();
2532 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2533 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2536 if (drawable)
2538 wine_tsx11_lock();
2539 pXRenderFreePicture( gdi_display, dst_pict );
2540 wine_tsx11_unlock();
2545 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, HRGN clip,
2546 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2547 Drawable drawable, struct bitblt_coords *src,
2548 struct bitblt_coords *dst, BOOL use_repeat )
2550 int x_src, y_src, x_dst, y_dst;
2551 Picture dst_pict;
2552 XRenderPictureAttributes pa;
2553 double xscale, yscale;
2555 if (drawable) /* using an intermediate pixmap */
2557 RGNDATA *clip_data = NULL;
2559 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2560 x_dst = dst->x;
2561 y_dst = dst->y;
2562 pa.repeat = RepeatNone;
2563 wine_tsx11_lock();
2564 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2565 if (clip_data)
2566 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2567 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2568 wine_tsx11_unlock();
2569 HeapFree( GetProcessHeap(), 0, clip_data );
2571 else
2573 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2574 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2575 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2578 if (!use_repeat)
2580 xscale = src->width / (double)dst->width;
2581 yscale = src->height / (double)dst->height;
2583 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2585 x_src = src->x;
2586 y_src = src->y;
2587 if (src->width < 0) x_src += src->width + 1;
2588 if (src->height < 0) y_src += src->height + 1;
2589 if (dst->width < 0) x_dst += dst->width + 1;
2590 if (dst->height < 0) y_dst += dst->height + 1;
2592 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, x_src, y_src, x_dst, y_dst,
2593 xscale, yscale, abs( dst->width ), abs( dst->height ));
2595 if (drawable)
2597 wine_tsx11_lock();
2598 pXRenderFreePicture( gdi_display, dst_pict );
2599 wine_tsx11_unlock();
2604 /***********************************************************************
2605 * xrenderdrv_StretchBlt
2607 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2608 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2610 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2611 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2612 INT sSrc, sDst;
2613 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2615 if (src_dev->funcs != dst_dev->funcs)
2617 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2618 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2621 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2623 /* XRender is of no use for color -> mono */
2624 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2625 goto x11drv_fallback;
2627 /* if not stretching, we only need to handle format conversion */
2628 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2630 sSrc = sDst = X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_None );
2631 if (physdev_dst != physdev_src) sSrc = X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_None );
2633 /* try client-side DIB copy */
2634 if (!stretch && sSrc == DIB_Status_AppMod)
2636 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2637 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2638 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2639 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2642 X11DRV_CoerceDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2643 if (physdev_dst != physdev_src) X11DRV_CoerceDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2645 if (rop != SRCCOPY)
2647 GC tmpGC;
2648 Pixmap tmp_pixmap;
2649 struct bitblt_coords tmp;
2651 /* make coordinates relative to tmp pixmap */
2652 tmp = *dst;
2653 tmp.x -= tmp.visrect.left;
2654 tmp.y -= tmp.visrect.top;
2655 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2657 wine_tsx11_lock();
2658 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2659 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2660 XSetGraphicsExposures( gdi_display, tmpGC, False );
2661 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2662 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2663 wine_tsx11_unlock();
2665 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2666 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2668 wine_tsx11_lock();
2669 XFreePixmap( gdi_display, tmp_pixmap );
2670 XFreeGC( gdi_display, tmpGC );
2671 wine_tsx11_unlock();
2673 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2675 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2676 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2677 return TRUE;
2679 x11drv_fallback:
2680 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2684 /***********************************************************************
2685 * xrenderdrv_PutImage
2687 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2688 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2689 struct bitblt_coords *dst, DWORD rop )
2691 struct xrender_physdev *physdev;
2692 X_PHYSBITMAP *bitmap;
2693 DWORD ret;
2694 Pixmap tmp_pixmap;
2695 GC gc;
2696 enum wxr_format src_format, dst_format;
2697 XRenderPictFormat *pict_format;
2698 Pixmap src_pixmap;
2699 Picture src_pict;
2700 BOOL use_repeat;
2702 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2704 if (hbitmap)
2706 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2707 physdev = NULL;
2708 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2710 else
2712 physdev = get_xrender_dev( dev );
2713 bitmap = NULL;
2714 dst_format = physdev->format;
2717 src_format = get_xrender_format_from_bitmapinfo( info, TRUE );
2718 if (!(pict_format = pict_formats[src_format])) goto update_format;
2720 /* make sure we can create an image with the same bpp */
2721 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2722 goto update_format;
2724 /* mono <-> color conversions not supported */
2725 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2726 goto x11drv_fallback;
2728 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2730 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2731 if (!ret)
2733 struct bitblt_coords tmp;
2735 if (bitmap)
2737 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2738 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2740 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2742 xrender_put_image( src_pixmap, src_pict, rgn, pict_formats[dst_format],
2743 NULL, bitmap->pixmap, src, dst, use_repeat );
2745 X11DRV_DIB_Unlock( bitmap, TRUE );
2746 DeleteObject( rgn );
2748 else
2750 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2752 if (rop != SRCCOPY)
2754 RGNDATA *clip_data = NULL;
2756 /* make coordinates relative to tmp pixmap */
2757 tmp = *dst;
2758 tmp.x -= tmp.visrect.left;
2759 tmp.y -= tmp.visrect.top;
2760 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2762 if (clip) clip_data = add_extra_clipping_region( physdev->x11dev, clip );
2764 wine_tsx11_lock();
2765 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2766 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2767 XSetGraphicsExposures( gdi_display, gc, False );
2768 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2769 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2770 wine_tsx11_unlock();
2772 xrender_put_image( src_pixmap, src_pict, NULL, physdev->pict_format,
2773 NULL, tmp_pixmap, src, &tmp, use_repeat );
2774 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2776 wine_tsx11_lock();
2777 XFreePixmap( gdi_display, tmp_pixmap );
2778 XFreeGC( gdi_display, gc );
2779 wine_tsx11_unlock();
2781 restore_clipping_region( physdev->x11dev, clip_data );
2783 else xrender_put_image( src_pixmap, src_pict, clip,
2784 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2786 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2789 wine_tsx11_lock();
2790 pXRenderFreePicture( gdi_display, src_pict );
2791 XFreePixmap( gdi_display, src_pixmap );
2792 wine_tsx11_unlock();
2794 return ret;
2796 update_format:
2797 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2798 set_color_info( pict_formats[dst_format], info );
2799 return ERROR_BAD_FORMAT;
2801 x11drv_fallback:
2802 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2803 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2804 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2808 /***********************************************************************
2809 * xrenderdrv_BlendImage
2811 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2812 struct bitblt_coords *src, struct bitblt_coords *dst,
2813 BLENDFUNCTION func )
2815 struct xrender_physdev *physdev = get_xrender_dev( dev );
2816 DWORD ret;
2817 enum wxr_format format;
2818 XRenderPictFormat *pict_format;
2819 Picture dst_pict, src_pict, mask_pict;
2820 Pixmap src_pixmap;
2821 BOOL use_repeat;
2823 if (!X11DRV_XRender_Installed)
2825 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2826 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2829 format = get_xrender_format_from_bitmapinfo( info, func.AlphaFormat & AC_SRC_ALPHA );
2830 if (!(pict_format = pict_formats[format])) goto update_format;
2832 /* make sure we can create an image with the same bpp */
2833 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2834 goto update_format;
2836 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2837 goto update_format;
2839 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2841 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2842 if (!ret)
2844 double xscale, yscale;
2846 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2848 if (!use_repeat)
2850 xscale = src->width / (double)dst->width;
2851 yscale = src->height / (double)dst->height;
2853 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2855 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2857 EnterCriticalSection( &xrender_cs );
2858 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2860 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2861 physdev->x11dev->dc_rect.left + dst->x,
2862 physdev->x11dev->dc_rect.top + dst->y,
2863 xscale, yscale, dst->width, dst->height );
2865 wine_tsx11_lock();
2866 pXRenderFreePicture( gdi_display, src_pict );
2867 XFreePixmap( gdi_display, src_pixmap );
2868 wine_tsx11_unlock();
2870 LeaveCriticalSection( &xrender_cs );
2872 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2874 return ret;
2876 update_format:
2877 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2878 set_color_info( physdev->pict_format, info );
2879 return ERROR_BAD_FORMAT;
2883 /***********************************************************************
2884 * xrenderdrv_AlphaBlend
2886 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2887 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2889 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2890 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2891 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2892 XRenderPictureAttributes pa;
2893 Pixmap tmp_pixmap = 0;
2894 double xscale, yscale;
2895 BOOL use_repeat;
2897 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2899 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2900 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2903 if (physdev_dst != physdev_src)
2905 int status = X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_None );
2906 if (status == DIB_Status_AppMod || status == DIB_Status_InSync)
2908 X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2909 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2910 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2912 X11DRV_CoerceDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2914 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2916 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2918 use_repeat = use_source_repeat( physdev_src );
2919 if (!use_repeat)
2921 xscale = src->width / (double)dst->width;
2922 yscale = src->height / (double)dst->height;
2924 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2926 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2928 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2930 /* mono -> color blending needs an intermediate color pixmap */
2931 XRenderColor fg, bg;
2932 int width = src->visrect.right - src->visrect.left;
2933 int height = src->visrect.bottom - src->visrect.top;
2935 /* blending doesn't use the destination DC colors */
2936 fg.red = fg.green = fg.blue = 0;
2937 bg.red = bg.green = bg.blue = 0xffff;
2938 fg.alpha = bg.alpha = 0xffff;
2940 wine_tsx11_lock();
2941 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2942 physdev_dst->pict_format->depth );
2943 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2944 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2945 CPRepeat, &pa );
2946 wine_tsx11_unlock();
2948 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2949 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2951 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2953 /* we need a source picture with no alpha */
2954 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2955 if (format != physdev_src->format)
2957 wine_tsx11_lock();
2958 pa.subwindow_mode = IncludeInferiors;
2959 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2960 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2961 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2962 wine_tsx11_unlock();
2966 if (tmp_pict) src_pict = tmp_pict;
2968 EnterCriticalSection( &xrender_cs );
2969 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2971 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2972 physdev_src->x11dev->dc_rect.left + src->x,
2973 physdev_src->x11dev->dc_rect.top + src->y,
2974 physdev_dst->x11dev->dc_rect.left + dst->x,
2975 physdev_dst->x11dev->dc_rect.top + dst->y,
2976 xscale, yscale, dst->width, dst->height );
2978 wine_tsx11_lock();
2979 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2980 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2981 wine_tsx11_unlock();
2983 LeaveCriticalSection( &xrender_cs );
2984 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2985 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2986 return TRUE;
2990 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2992 /* At depths >1, the depth of physBitmap and physDev might not be the same e.g. the physbitmap might be a 16-bit DIB while the physdev uses 24-bit */
2993 int depth = physBitmap->depth == 1 ? 1 : physDev->depth;
2994 enum wxr_format src_format = get_xrender_format_from_color_shifts(physBitmap->depth, &physBitmap->color_shifts);
2995 enum wxr_format dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2997 wine_tsx11_lock();
2998 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
3000 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
3001 if( (physBitmap->depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->depth) ||
3002 (src_format == dst_format) )
3004 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
3005 get_bitmap_gc(physBitmap->depth), 0, 0, width, height, 0, 0 );
3007 else /* We need depth conversion */
3009 Picture src_pict, dst_pict;
3010 XRenderPictureAttributes pa;
3011 pa.subwindow_mode = IncludeInferiors;
3012 pa.repeat = RepeatNone;
3014 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap,
3015 pict_formats[src_format], CPSubwindowMode|CPRepeat, &pa);
3016 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap,
3017 pict_formats[dst_format], CPSubwindowMode|CPRepeat, &pa);
3019 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
3020 pXRenderFreePicture(gdi_display, src_pict);
3021 pXRenderFreePicture(gdi_display, dst_pict);
3023 wine_tsx11_unlock();
3026 static const struct gdi_dc_funcs xrender_funcs =
3028 NULL, /* pAbortDoc */
3029 NULL, /* pAbortPath */
3030 xrenderdrv_AlphaBlend, /* pAlphaBlend */
3031 NULL, /* pAngleArc */
3032 NULL, /* pArc */
3033 NULL, /* pArcTo */
3034 NULL, /* pBeginPath */
3035 xrenderdrv_BlendImage, /* pBlendImage */
3036 NULL, /* pChoosePixelFormat */
3037 NULL, /* pChord */
3038 NULL, /* pCloseFigure */
3039 xrenderdrv_CreateBitmap, /* pCreateBitmap */
3040 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
3041 xrenderdrv_CreateDC, /* pCreateDC */
3042 NULL, /* pCreateDIBSection */
3043 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
3044 xrenderdrv_DeleteDC, /* pDeleteDC */
3045 NULL, /* pDeleteObject */
3046 NULL, /* pDescribePixelFormat */
3047 NULL, /* pDeviceCapabilities */
3048 NULL, /* pEllipse */
3049 NULL, /* pEndDoc */
3050 NULL, /* pEndPage */
3051 NULL, /* pEndPath */
3052 NULL, /* pEnumDeviceFonts */
3053 NULL, /* pEnumICMProfiles */
3054 NULL, /* pExcludeClipRect */
3055 NULL, /* pExtDeviceMode */
3056 xrenderdrv_ExtEscape, /* pExtEscape */
3057 NULL, /* pExtFloodFill */
3058 NULL, /* pExtSelectClipRgn */
3059 xrenderdrv_ExtTextOut, /* pExtTextOut */
3060 NULL, /* pFillPath */
3061 NULL, /* pFillRgn */
3062 NULL, /* pFlattenPath */
3063 NULL, /* pFrameRgn */
3064 NULL, /* pGdiComment */
3065 NULL, /* pGetCharWidth */
3066 NULL, /* pGetDeviceCaps */
3067 NULL, /* pGetDeviceGammaRamp */
3068 NULL, /* pGetICMProfile */
3069 xrenderdrv_GetImage, /* pGetImage */
3070 NULL, /* pGetNearestColor */
3071 NULL, /* pGetPixel */
3072 NULL, /* pGetPixelFormat */
3073 NULL, /* pGetSystemPaletteEntries */
3074 NULL, /* pGetTextExtentExPoint */
3075 NULL, /* pGetTextMetrics */
3076 NULL, /* pIntersectClipRect */
3077 NULL, /* pInvertRgn */
3078 NULL, /* pLineTo */
3079 NULL, /* pModifyWorldTransform */
3080 NULL, /* pMoveTo */
3081 NULL, /* pOffsetClipRgn */
3082 NULL, /* pOffsetViewportOrg */
3083 NULL, /* pOffsetWindowOrg */
3084 NULL, /* pPaintRgn */
3085 NULL, /* pPatBlt */
3086 NULL, /* pPie */
3087 NULL, /* pPolyBezier */
3088 NULL, /* pPolyBezierTo */
3089 NULL, /* pPolyDraw */
3090 NULL, /* pPolyPolygon */
3091 NULL, /* pPolyPolyline */
3092 NULL, /* pPolygon */
3093 NULL, /* pPolyline */
3094 NULL, /* pPolylineTo */
3095 xrenderdrv_PutImage, /* pPutImage */
3096 NULL, /* pRealizeDefaultPalette */
3097 NULL, /* pRealizePalette */
3098 NULL, /* pRectangle */
3099 NULL, /* pResetDC */
3100 NULL, /* pRestoreDC */
3101 NULL, /* pRoundRect */
3102 NULL, /* pSaveDC */
3103 NULL, /* pScaleViewportExt */
3104 NULL, /* pScaleWindowExt */
3105 xrenderdrv_SelectBitmap, /* pSelectBitmap */
3106 NULL, /* pSelectBrush */
3107 NULL, /* pSelectClipPath */
3108 xrenderdrv_SelectFont, /* pSelectFont */
3109 NULL, /* pSelectPalette */
3110 NULL, /* pSelectPen */
3111 NULL, /* pSetArcDirection */
3112 NULL, /* pSetBkColor */
3113 NULL, /* pSetBkMode */
3114 NULL, /* pSetDCBrushColor */
3115 NULL, /* pSetDCPenColor */
3116 NULL, /* pSetDIBColorTable */
3117 NULL, /* pSetDIBitsToDevice */
3118 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
3119 NULL, /* pSetDeviceGammaRamp */
3120 NULL, /* pSetLayout */
3121 NULL, /* pSetMapMode */
3122 NULL, /* pSetMapperFlags */
3123 NULL, /* pSetPixel */
3124 NULL, /* pSetPixelFormat */
3125 NULL, /* pSetPolyFillMode */
3126 NULL, /* pSetROP2 */
3127 NULL, /* pSetRelAbs */
3128 NULL, /* pSetStretchBltMode */
3129 NULL, /* pSetTextAlign */
3130 NULL, /* pSetTextCharacterExtra */
3131 NULL, /* pSetTextColor */
3132 NULL, /* pSetTextJustification */
3133 NULL, /* pSetViewportExt */
3134 NULL, /* pSetViewportOrg */
3135 NULL, /* pSetWindowExt */
3136 NULL, /* pSetWindowOrg */
3137 NULL, /* pSetWorldTransform */
3138 NULL, /* pStartDoc */
3139 NULL, /* pStartPage */
3140 xrenderdrv_StretchBlt, /* pStretchBlt */
3141 NULL, /* pStretchDIBits */
3142 NULL, /* pStrokeAndFillPath */
3143 NULL, /* pStrokePath */
3144 NULL, /* pSwapBuffers */
3145 NULL, /* pUnrealizePalette */
3146 NULL, /* pWidenPath */
3147 /* OpenGL not supported */
3150 #else /* SONAME_LIBXRENDER */
3152 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
3154 TRACE("XRender support not compiled in.\n");
3155 return NULL;
3158 void X11DRV_XRender_Finalize(void)
3162 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
3164 wine_tsx11_lock();
3165 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
3167 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
3168 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
3169 wine_tsx11_unlock();
3172 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
3174 return FALSE;
3177 #endif /* SONAME_LIBXRENDER */