quartz: Free two assert calls from having side effects.
[wine/testsucceed.git] / dlls / winex11.drv / xrender.c
blob33ad4bd9c4f85abad0c96a7e3938c25d60b4f976
1 /*
2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
6 * Copyright 2011 Alexandre Julliard
8 * Some parts also:
9 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <stdlib.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "x11drv.h"
36 #include "winternl.h"
37 #include "wine/library.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 int using_client_side_fonts = FALSE;
43 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
45 #ifdef SONAME_LIBXRENDER
47 static BOOL X11DRV_XRender_Installed = FALSE;
49 #include <X11/Xlib.h>
50 #include <X11/extensions/Xrender.h>
52 #ifndef RepeatNone /* added in 0.10 */
53 #define RepeatNone 0
54 #define RepeatNormal 1
55 #define RepeatPad 2
56 #define RepeatReflect 3
57 #endif
59 enum wxr_format
61 WXR_FORMAT_MONO,
62 WXR_FORMAT_GRAY,
63 WXR_FORMAT_X1R5G5B5,
64 WXR_FORMAT_X1B5G5R5,
65 WXR_FORMAT_R5G6B5,
66 WXR_FORMAT_B5G6R5,
67 WXR_FORMAT_R8G8B8,
68 WXR_FORMAT_B8G8R8,
69 WXR_FORMAT_A8R8G8B8,
70 WXR_FORMAT_B8G8R8A8,
71 WXR_FORMAT_X8R8G8B8,
72 WXR_FORMAT_B8G8R8X8,
73 WXR_NB_FORMATS,
74 WXR_INVALID_FORMAT = WXR_NB_FORMATS
77 typedef struct wine_xrender_format_template
79 unsigned int depth;
80 unsigned int alpha;
81 unsigned int alphaMask;
82 unsigned int red;
83 unsigned int redMask;
84 unsigned int green;
85 unsigned int greenMask;
86 unsigned int blue;
87 unsigned int blueMask;
88 } WineXRenderFormatTemplate;
90 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
92 /* Format depth alpha mask red mask green mask blue mask*/
93 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
94 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
95 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
96 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
97 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
98 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
99 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
101 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
103 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
107 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
109 /* format phys red phys green phys blue log red log green log blue */
110 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
111 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
112 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
113 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
114 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
115 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
116 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
118 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
120 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
124 static enum wxr_format default_format = WXR_INVALID_FORMAT;
125 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
127 typedef struct
129 LOGFONTW lf;
130 XFORM xform;
131 SIZE devsize; /* size in device coords */
132 DWORD hash;
133 } LFANDSIZE;
135 #define INITIAL_REALIZED_BUF_SIZE 128
137 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
139 typedef struct
141 GlyphSet glyphset;
142 XRenderPictFormat *font_format;
143 int nrealized;
144 BOOL *realized;
145 void **bitmaps;
146 XGlyphInfo *gis;
147 } gsCacheEntryFormat;
149 typedef struct
151 LFANDSIZE lfsz;
152 AA_Type aa_default;
153 gsCacheEntryFormat * format[AA_MAXVALUE];
154 INT count;
155 INT next;
156 } gsCacheEntry;
158 struct xrender_physdev
160 struct gdi_physdev dev;
161 X11DRV_PDEVICE *x11dev;
162 enum wxr_format format;
163 int cache_index;
164 BOOL update_clip;
165 Picture pict;
166 Picture pict_src;
167 XRenderPictFormat *pict_format;
170 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
172 return (struct xrender_physdev *)dev;
175 static const struct gdi_dc_funcs xrender_funcs;
177 static gsCacheEntry *glyphsetCache = NULL;
178 static DWORD glyphsetCacheSize = 0;
179 static INT lastfree = -1;
180 static INT mru = -1;
182 #define INIT_CACHE_SIZE 10
184 static int antialias = 1;
186 static void *xrender_handle;
188 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
189 MAKE_FUNCPTR(XRenderAddGlyphs)
190 MAKE_FUNCPTR(XRenderComposite)
191 MAKE_FUNCPTR(XRenderCompositeText16)
192 MAKE_FUNCPTR(XRenderCreateGlyphSet)
193 MAKE_FUNCPTR(XRenderCreatePicture)
194 MAKE_FUNCPTR(XRenderFillRectangle)
195 MAKE_FUNCPTR(XRenderFindFormat)
196 MAKE_FUNCPTR(XRenderFindVisualFormat)
197 MAKE_FUNCPTR(XRenderFreeGlyphSet)
198 MAKE_FUNCPTR(XRenderFreePicture)
199 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
200 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
201 MAKE_FUNCPTR(XRenderSetPictureTransform)
202 #endif
203 MAKE_FUNCPTR(XRenderQueryExtension)
205 #ifdef SONAME_LIBFONTCONFIG
206 #include <fontconfig/fontconfig.h>
207 MAKE_FUNCPTR(FcConfigSubstitute)
208 MAKE_FUNCPTR(FcDefaultSubstitute)
209 MAKE_FUNCPTR(FcFontMatch)
210 MAKE_FUNCPTR(FcInit)
211 MAKE_FUNCPTR(FcPatternCreate)
212 MAKE_FUNCPTR(FcPatternDestroy)
213 MAKE_FUNCPTR(FcPatternAddInteger)
214 MAKE_FUNCPTR(FcPatternAddString)
215 MAKE_FUNCPTR(FcPatternGetBool)
216 MAKE_FUNCPTR(FcPatternGetInteger)
217 MAKE_FUNCPTR(FcPatternGetString)
218 static void *fontconfig_handle;
219 static BOOL fontconfig_installed;
220 #endif
222 #undef MAKE_FUNCPTR
224 static CRITICAL_SECTION xrender_cs;
225 static CRITICAL_SECTION_DEBUG critsect_debug =
227 0, 0, &xrender_cs,
228 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
229 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
231 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
233 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
234 ( ( (ULONG)_x4 << 24 ) | \
235 ( (ULONG)_x3 << 16 ) | \
236 ( (ULONG)_x2 << 8 ) | \
237 (ULONG)_x1 )
239 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
241 #define GASP_GRIDFIT 0x01
242 #define GASP_DOGRAY 0x02
244 #ifdef WORDS_BIGENDIAN
245 #define get_be_word(x) (x)
246 #define NATIVE_BYTE_ORDER MSBFirst
247 #else
248 #define get_be_word(x) RtlUshortByteSwap(x)
249 #define NATIVE_BYTE_ORDER LSBFirst
250 #endif
252 static BOOL has_alpha( enum wxr_format format )
254 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
257 static enum wxr_format get_format_without_alpha( enum wxr_format format )
259 switch (format)
261 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
262 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
263 default: return format;
267 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
269 templ->id = 0;
270 templ->type = PictTypeDirect;
271 templ->depth = fmt->depth;
272 templ->direct.alpha = fmt->alpha;
273 templ->direct.alphaMask = fmt->alphaMask;
274 templ->direct.red = fmt->red;
275 templ->direct.redMask = fmt->redMask;
276 templ->direct.green = fmt->green;
277 templ->direct.greenMask = fmt->greenMask;
278 templ->direct.blue = fmt->blue;
279 templ->direct.blueMask = fmt->blueMask;
280 templ->colormap = 0;
282 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
284 return TRUE;
287 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
289 if(fmt->depth != screen_depth)
290 return FALSE;
291 if( (fmt->redMask << fmt->red) != visual->red_mask)
292 return FALSE;
293 if( (fmt->greenMask << fmt->green) != visual->green_mask)
294 return FALSE;
295 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
296 return FALSE;
298 /* We never select a default ARGB visual */
299 if(fmt->alphaMask)
300 return FALSE;
302 return TRUE;
305 static int load_xrender_formats(void)
307 int count = 0;
308 unsigned int i;
310 for (i = 0; i < WXR_NB_FORMATS; i++)
312 XRenderPictFormat templ;
314 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
316 wine_tsx11_lock();
317 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
318 if (!pict_formats[i])
320 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
321 if (visual->class == DirectColor)
323 XVisualInfo info;
324 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
325 screen_depth, TrueColor, &info ))
327 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
328 if (pict_formats[i]) visual = info.visual;
332 wine_tsx11_unlock();
333 if (pict_formats[i]) default_format = i;
335 else
337 unsigned long mask = 0;
338 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
340 wine_tsx11_lock();
341 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
342 wine_tsx11_unlock();
344 if (pict_formats[i])
346 count++;
347 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
350 return count;
353 /***********************************************************************
354 * X11DRV_XRender_Init
356 * Let's see if our XServer has the extension available
359 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
361 int event_base, i;
363 if (client_side_with_render &&
364 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
367 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
368 LOAD_FUNCPTR(XRenderAddGlyphs)
369 LOAD_FUNCPTR(XRenderComposite)
370 LOAD_FUNCPTR(XRenderCompositeText16)
371 LOAD_FUNCPTR(XRenderCreateGlyphSet)
372 LOAD_FUNCPTR(XRenderCreatePicture)
373 LOAD_FUNCPTR(XRenderFillRectangle)
374 LOAD_FUNCPTR(XRenderFindFormat)
375 LOAD_FUNCPTR(XRenderFindVisualFormat)
376 LOAD_FUNCPTR(XRenderFreeGlyphSet)
377 LOAD_FUNCPTR(XRenderFreePicture)
378 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
379 LOAD_FUNCPTR(XRenderQueryExtension)
380 #undef LOAD_FUNCPTR
381 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
382 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
383 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
384 #undef LOAD_OPTIONAL_FUNCPTR
385 #endif
387 wine_tsx11_lock();
388 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
389 wine_tsx11_unlock();
390 if(X11DRV_XRender_Installed) {
391 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
392 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
394 wine_tsx11_unlock();
395 WINE_MESSAGE(
396 "Wine has detected that you probably have a buggy version\n"
397 "of libXrender.so . Because of this client side font rendering\n"
398 "will be disabled. Please upgrade this library.\n");
399 X11DRV_XRender_Installed = FALSE;
400 return NULL;
403 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
404 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
405 X11DRV_XRender_Installed = FALSE;
410 #ifdef SONAME_LIBFONTCONFIG
411 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
413 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fontconfig_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
414 LOAD_FUNCPTR(FcConfigSubstitute);
415 LOAD_FUNCPTR(FcDefaultSubstitute);
416 LOAD_FUNCPTR(FcFontMatch);
417 LOAD_FUNCPTR(FcInit);
418 LOAD_FUNCPTR(FcPatternCreate);
419 LOAD_FUNCPTR(FcPatternDestroy);
420 LOAD_FUNCPTR(FcPatternAddInteger);
421 LOAD_FUNCPTR(FcPatternAddString);
422 LOAD_FUNCPTR(FcPatternGetBool);
423 LOAD_FUNCPTR(FcPatternGetInteger);
424 LOAD_FUNCPTR(FcPatternGetString);
425 #undef LOAD_FUNCPTR
426 fontconfig_installed = pFcInit();
428 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
429 #endif
431 sym_not_found:
432 if(X11DRV_XRender_Installed || client_side_with_core)
434 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
435 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
437 glyphsetCacheSize = INIT_CACHE_SIZE;
438 lastfree = 0;
439 for(i = 0; i < INIT_CACHE_SIZE; i++) {
440 glyphsetCache[i].next = i + 1;
441 glyphsetCache[i].count = -1;
443 glyphsetCache[i-1].next = -1;
444 using_client_side_fonts = 1;
446 if(!X11DRV_XRender_Installed) {
447 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
448 if(screen_depth <= 8 || !client_side_antialias_with_core)
449 antialias = 0;
450 } else {
451 if(screen_depth <= 8 || !client_side_antialias_with_render)
452 antialias = 0;
454 return &xrender_funcs;
456 TRACE("Using X11 core fonts\n");
457 return NULL;
460 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
461 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
463 if(pf->direct.redMask)
464 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
465 else
466 dst_color->red = 0;
468 if(pf->direct.greenMask)
469 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
470 else
471 dst_color->green = 0;
473 if(pf->direct.blueMask)
474 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
475 else
476 dst_color->blue = 0;
478 dst_color->alpha = 0xffff;
481 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
483 int redMask, greenMask, blueMask;
484 unsigned int i;
486 if (depth == 1) return WXR_FORMAT_MONO;
488 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
489 if (!shifts) return default_format;
491 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
492 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
493 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
495 /* Try to locate a format which matches the specification of the dibsection. */
496 for(i = 0; i < WXR_NB_FORMATS; i++)
498 if( depth == wxr_formats_template[i].depth &&
499 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
500 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
501 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
502 return i;
505 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
506 ERR("No XRender format found for %u %08x/%08x/%08x\n", depth, redMask, greenMask, blueMask);
507 return WXR_INVALID_FORMAT;
510 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info, BOOL use_alpha )
512 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
514 switch (info->bmiHeader.biBitCount)
516 case 1:
517 return WXR_FORMAT_MONO;
518 case 4:
519 case 8:
520 break;
521 case 24:
522 if (info->bmiHeader.biCompression != BI_RGB) break;
523 return WXR_FORMAT_R8G8B8;
524 case 16:
525 case 32:
526 if (info->bmiHeader.biCompression == BI_BITFIELDS)
528 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
529 unsigned int i;
531 for (i = 0; i < WXR_NB_FORMATS; i++)
533 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
534 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
535 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
536 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
537 return i;
539 break;
541 if (info->bmiHeader.biCompression != BI_RGB) break;
542 if (info->bmiHeader.biBitCount == 16) return WXR_FORMAT_X1R5G5B5;
543 return use_alpha ? WXR_FORMAT_A8R8G8B8 : WXR_FORMAT_X8R8G8B8;
545 return WXR_INVALID_FORMAT;
548 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
549 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
551 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
552 XTransform xform = {{
553 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
554 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
555 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
558 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
559 #endif
562 /* check if we can use repeating instead of scaling for the specified source DC */
563 static BOOL use_source_repeat( struct xrender_physdev *dev )
565 return (dev->x11dev->bitmap &&
566 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
567 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
570 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
572 if (!dev->pict && dev->pict_format)
574 XRenderPictureAttributes pa;
576 wine_tsx11_lock();
577 pa.subwindow_mode = IncludeInferiors;
578 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
579 dev->pict_format, CPSubwindowMode, &pa );
580 wine_tsx11_unlock();
581 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
582 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
583 dev->update_clip = TRUE;
586 if (dev->update_clip)
588 RGNDATA *clip_data;
589 HRGN rgn = 0;
591 if (clip_rect)
593 rgn = CreateRectRgnIndirect( clip_rect );
594 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
595 CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
597 else if (clip_rgn)
599 rgn = CreateRectRgn( 0, 0, 0, 0 );
600 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
603 if ((clip_data = X11DRV_GetRegionData( rgn ? rgn : dev->x11dev->region, 0 )))
605 wine_tsx11_lock();
606 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
607 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
608 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
609 wine_tsx11_unlock();
610 HeapFree( GetProcessHeap(), 0, clip_data );
612 dev->update_clip = (rgn != 0); /* have to update again if we are using a custom region */
613 if (rgn) DeleteObject( rgn );
615 return dev->pict;
618 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
620 if (!dev->pict_src && dev->pict_format)
622 XRenderPictureAttributes pa;
624 wine_tsx11_lock();
625 pa.subwindow_mode = IncludeInferiors;
626 pa.repeat = repeat ? RepeatNormal : RepeatNone;
627 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
628 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
629 wine_tsx11_unlock();
631 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
632 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
635 return dev->pict_src;
638 static void free_xrender_picture( struct xrender_physdev *dev )
640 if (dev->pict || dev->pict_src)
642 wine_tsx11_lock();
643 XFlush( gdi_display );
644 if (dev->pict)
646 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
647 pXRenderFreePicture(gdi_display, dev->pict);
648 dev->pict = 0;
650 if(dev->pict_src)
652 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
653 pXRenderFreePicture(gdi_display, dev->pict_src);
654 dev->pict_src = 0;
656 wine_tsx11_unlock();
660 /* return a mask picture used to force alpha to 0 */
661 static Picture get_no_alpha_mask(void)
663 static Pixmap pixmap;
664 static Picture pict;
666 wine_tsx11_lock();
667 if (!pict)
669 XRenderPictureAttributes pa;
670 XRenderColor col;
672 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
673 pa.repeat = RepeatNormal;
674 pa.component_alpha = True;
675 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
676 CPRepeat|CPComponentAlpha, &pa );
677 col.red = col.green = col.blue = 0xffff;
678 col.alpha = 0;
679 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
681 wine_tsx11_unlock();
682 return pict;
685 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
687 if(p1->hash != p2->hash) return TRUE;
688 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
689 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
690 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
691 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
694 #if 0
695 static void walk_cache(void)
697 int i;
699 EnterCriticalSection(&xrender_cs);
700 for(i=mru; i >= 0; i = glyphsetCache[i].next)
701 TRACE("item %d\n", i);
702 LeaveCriticalSection(&xrender_cs);
704 #endif
706 static int LookupEntry(LFANDSIZE *plfsz)
708 int i, prev_i = -1;
710 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
711 TRACE("%d\n", i);
712 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
714 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
715 glyphsetCache[i].count++;
716 if(prev_i >= 0) {
717 glyphsetCache[prev_i].next = glyphsetCache[i].next;
718 glyphsetCache[i].next = mru;
719 mru = i;
721 TRACE("found font in cache %d\n", i);
722 return i;
724 prev_i = i;
726 TRACE("font not in cache\n");
727 return -1;
730 static void FreeEntry(int entry)
732 int i, format;
734 for(format = 0; format < AA_MAXVALUE; format++) {
735 gsCacheEntryFormat * formatEntry;
737 if( !glyphsetCache[entry].format[format] )
738 continue;
740 formatEntry = glyphsetCache[entry].format[format];
742 if(formatEntry->glyphset) {
743 wine_tsx11_lock();
744 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
745 wine_tsx11_unlock();
746 formatEntry->glyphset = 0;
748 if(formatEntry->nrealized) {
749 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
750 formatEntry->realized = NULL;
751 if(formatEntry->bitmaps) {
752 for(i = 0; i < formatEntry->nrealized; i++)
753 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
754 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
755 formatEntry->bitmaps = NULL;
757 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
758 formatEntry->gis = NULL;
759 formatEntry->nrealized = 0;
762 HeapFree(GetProcessHeap(), 0, formatEntry);
763 glyphsetCache[entry].format[format] = NULL;
767 static int AllocEntry(void)
769 int best = -1, prev_best = -1, i, prev_i = -1;
771 if(lastfree >= 0) {
772 assert(glyphsetCache[lastfree].count == -1);
773 glyphsetCache[lastfree].count = 1;
774 best = lastfree;
775 lastfree = glyphsetCache[lastfree].next;
776 assert(best != mru);
777 glyphsetCache[best].next = mru;
778 mru = best;
780 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
781 return mru;
784 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
785 if(glyphsetCache[i].count == 0) {
786 best = i;
787 prev_best = prev_i;
789 prev_i = i;
792 if(best >= 0) {
793 TRACE("freeing unused glyphset at cache %d\n", best);
794 FreeEntry(best);
795 glyphsetCache[best].count = 1;
796 if(prev_best >= 0) {
797 glyphsetCache[prev_best].next = glyphsetCache[best].next;
798 glyphsetCache[best].next = mru;
799 mru = best;
800 } else {
801 assert(mru == best);
803 return mru;
806 TRACE("Growing cache\n");
808 if (glyphsetCache)
809 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
810 glyphsetCache,
811 (glyphsetCacheSize + INIT_CACHE_SIZE)
812 * sizeof(*glyphsetCache));
813 else
814 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
815 (glyphsetCacheSize + INIT_CACHE_SIZE)
816 * sizeof(*glyphsetCache));
818 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
819 i++) {
820 glyphsetCache[i].next = i + 1;
821 glyphsetCache[i].count = -1;
823 glyphsetCache[i-1].next = -1;
824 glyphsetCacheSize += INIT_CACHE_SIZE;
826 lastfree = glyphsetCache[best].next;
827 glyphsetCache[best].count = 1;
828 glyphsetCache[best].next = mru;
829 mru = best;
830 TRACE("new free cache slot at %d\n", mru);
831 return mru;
834 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
836 DWORD size;
837 WORD *gasp, *buffer;
838 WORD num_recs;
839 DWORD ppem;
840 TEXTMETRICW tm;
842 *flags = 0;
844 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
845 if(size == GDI_ERROR)
846 return FALSE;
848 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
849 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
851 GetTextMetricsW(hdc, &tm);
852 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
854 gasp++;
855 num_recs = get_be_word(*gasp);
856 gasp++;
857 while(num_recs--)
859 *flags = get_be_word(*(gasp + 1));
860 if(ppem <= get_be_word(*gasp))
861 break;
862 gasp += 2;
864 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
866 HeapFree(GetProcessHeap(), 0, buffer);
867 return TRUE;
870 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
872 AA_Type ret;
873 WORD flags;
874 UINT font_smoothing_type, font_smoothing_orientation;
876 if (X11DRV_XRender_Installed && subpixel &&
877 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
878 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
880 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
881 &font_smoothing_orientation, 0) &&
882 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
884 ret = AA_BGR;
886 else
887 ret = AA_RGB;
888 /*FIXME
889 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
890 But, Wine's subpixel rendering can support the portrait mode.
893 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
894 ret = AA_Grey;
895 else
896 ret = AA_None;
898 return ret;
901 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
903 int ret;
904 int format;
905 gsCacheEntry *entry;
906 static int hinter = -1;
907 static int subpixel = -1;
908 BOOL font_smoothing;
910 if((ret = LookupEntry(plfsz)) != -1) return ret;
912 ret = AllocEntry();
913 entry = glyphsetCache + ret;
914 entry->lfsz = *plfsz;
915 for( format = 0; format < AA_MAXVALUE; format++ ) {
916 assert( !entry->format[format] );
919 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
921 if(hinter == -1 || subpixel == -1)
923 RASTERIZER_STATUS status;
924 GetRasterizerCaps(&status, sizeof(status));
925 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
926 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
929 switch (plfsz->lf.lfQuality)
931 case ANTIALIASED_QUALITY:
932 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
933 return ret; /* ignore further configuration */
934 case CLEARTYPE_QUALITY:
935 case CLEARTYPE_NATURAL_QUALITY:
936 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
937 break;
938 case DEFAULT_QUALITY:
939 case DRAFT_QUALITY:
940 case PROOF_QUALITY:
941 default:
942 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
943 font_smoothing)
945 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
947 else
948 entry->aa_default = AA_None;
949 break;
952 font_smoothing = TRUE; /* default to enabled */
953 #ifdef SONAME_LIBFONTCONFIG
954 if (fontconfig_installed)
956 FcPattern *match, *pattern = pFcPatternCreate();
957 FcResult result;
958 char family[LF_FACESIZE * 4];
960 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
961 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
962 if (plfsz->lf.lfWeight != FW_DONTCARE)
964 int weight;
965 switch (plfsz->lf.lfWeight)
967 case FW_THIN: weight = FC_WEIGHT_THIN; break;
968 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
969 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
970 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
971 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
972 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
973 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
974 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
975 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
976 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
978 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
980 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
981 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
982 pFcDefaultSubstitute( pattern );
983 if ((match = pFcFontMatch( NULL, pattern, &result )))
985 int rgba;
986 FcBool antialias;
988 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
989 antialias = TRUE;
990 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
992 FcChar8 *file;
993 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
995 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
996 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
998 switch (rgba)
1000 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1001 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1002 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1003 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1004 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1007 if (!antialias) font_smoothing = FALSE;
1008 pFcPatternDestroy( match );
1010 pFcPatternDestroy( pattern );
1012 #endif /* SONAME_LIBFONTCONFIG */
1014 /* now check Xft resources */
1016 char *value;
1017 BOOL antialias = TRUE;
1019 wine_tsx11_lock();
1020 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1022 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1023 value[0] == '0' || !strcasecmp( value, "off" ))
1024 antialias = FALSE;
1026 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1028 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1029 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1030 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1031 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1032 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1033 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1035 wine_tsx11_unlock();
1036 if (!antialias) font_smoothing = FALSE;
1039 if (!font_smoothing) entry->aa_default = AA_None;
1041 /* we can't support subpixel without xrender */
1042 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1044 else
1045 entry->aa_default = AA_None;
1047 return ret;
1050 static void dec_ref_cache(int index)
1052 assert(index >= 0);
1053 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1054 assert(glyphsetCache[index].count > 0);
1055 glyphsetCache[index].count--;
1058 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1060 DWORD hash = 0, *ptr, two_chars;
1061 WORD *pwc;
1062 int i;
1064 hash ^= plfsz->devsize.cx;
1065 hash ^= plfsz->devsize.cy;
1066 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1067 hash ^= *ptr;
1068 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1069 hash ^= *ptr;
1070 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1071 two_chars = *ptr;
1072 pwc = (WCHAR *)&two_chars;
1073 if(!*pwc) break;
1074 *pwc = toupperW(*pwc);
1075 pwc++;
1076 *pwc = toupperW(*pwc);
1077 hash ^= two_chars;
1078 if(!*pwc) break;
1080 plfsz->hash = hash;
1081 return;
1084 /***********************************************************************
1085 * X11DRV_XRender_Finalize
1087 void X11DRV_XRender_Finalize(void)
1089 int i;
1091 EnterCriticalSection(&xrender_cs);
1092 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1093 FreeEntry(i);
1094 LeaveCriticalSection(&xrender_cs);
1097 /**********************************************************************
1098 * xrenderdrv_SelectFont
1100 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
1102 struct xrender_physdev *physdev = get_xrender_dev( dev );
1103 LFANDSIZE lfsz;
1105 if (!GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf )) return HGDI_ERROR;
1107 if (!gdiFont)
1109 dev = GET_NEXT_PHYSDEV( dev, pSelectFont );
1110 return dev->funcs->pSelectFont( dev, hfont, gdiFont );
1113 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1114 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1115 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1116 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1117 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1118 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1120 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1121 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1122 lfsz.xform.eM21, lfsz.xform.eM22);
1124 /* Not used fields, would break hashing */
1125 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1127 lfsz_calc_hash(&lfsz);
1129 EnterCriticalSection(&xrender_cs);
1130 if (physdev->cache_index != -1)
1131 dec_ref_cache( physdev->cache_index );
1132 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1133 LeaveCriticalSection(&xrender_cs);
1134 physdev->x11dev->has_gdi_font = TRUE;
1135 return 0;
1138 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1140 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1141 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1143 if (!physdev) return FALSE;
1144 physdev->x11dev = x11dev;
1145 physdev->cache_index = -1;
1146 physdev->format = format;
1147 physdev->pict_format = pict_formats[format];
1148 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1149 return TRUE;
1152 /* store the color mask data in the bitmap info structure */
1153 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1155 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1157 info->bmiHeader.biPlanes = 1;
1158 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1159 info->bmiHeader.biCompression = BI_RGB;
1160 info->bmiHeader.biClrUsed = 0;
1162 switch (info->bmiHeader.biBitCount)
1164 case 16:
1165 colors[0] = format->direct.redMask << format->direct.red;
1166 colors[1] = format->direct.greenMask << format->direct.green;
1167 colors[2] = format->direct.blueMask << format->direct.blue;
1168 info->bmiHeader.biCompression = BI_BITFIELDS;
1169 break;
1170 case 32:
1171 colors[0] = format->direct.redMask << format->direct.red;
1172 colors[1] = format->direct.greenMask << format->direct.green;
1173 colors[2] = format->direct.blueMask << format->direct.blue;
1174 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1175 info->bmiHeader.biCompression = BI_BITFIELDS;
1176 break;
1181 /**********************************************************************
1182 * xrenderdrv_CreateDC
1184 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1185 LPCWSTR output, const DEVMODEW* initData )
1187 return create_xrender_dc( pdev, default_format );
1190 /**********************************************************************
1191 * xrenderdrv_CreateCompatibleDC
1193 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1195 if (orig) /* chain to x11drv first */
1197 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1198 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1200 /* otherwise we have been called by x11drv */
1202 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1205 /**********************************************************************
1206 * xrenderdrv_DeleteDC
1208 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1210 struct xrender_physdev *physdev = get_xrender_dev( dev );
1212 free_xrender_picture( physdev );
1214 EnterCriticalSection( &xrender_cs );
1215 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1216 LeaveCriticalSection( &xrender_cs );
1218 HeapFree( GetProcessHeap(), 0, physdev );
1219 return TRUE;
1222 /**********************************************************************
1223 * xrenderdrv_ExtEscape
1225 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1226 INT out_count, LPVOID out_data )
1228 struct xrender_physdev *physdev = get_xrender_dev( dev );
1230 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1232 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1234 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1236 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1237 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1238 return ret;
1241 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1244 /****************************************************************************
1245 * xrenderdrv_CreateBitmap
1247 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1249 enum wxr_format format = WXR_INVALID_FORMAT;
1250 BITMAP bitmap;
1252 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1254 if (bitmap.bmPlanes == 1 && bitmap.bmBitsPixel == screen_bpp)
1256 switch (bitmap.bmBitsPixel)
1258 case 16: format = WXR_FORMAT_R5G6B5; break;
1259 case 24: format = WXR_FORMAT_R8G8B8; break;
1260 case 32: format = WXR_FORMAT_A8R8G8B8; break;
1264 if (pict_formats[format])
1265 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1266 TRUE, &wxr_color_shifts[format] );
1268 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1269 return dev->funcs->pCreateBitmap( dev, hbitmap );
1272 /****************************************************************************
1273 * xrenderdrv_DeleteBitmap
1275 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1277 return X11DRV_DeleteBitmap( hbitmap );
1280 /***********************************************************************
1281 * xrenderdrv_SelectBitmap
1283 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1285 HBITMAP ret;
1286 struct xrender_physdev *physdev = get_xrender_dev( dev );
1288 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1289 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1290 if (ret)
1292 free_xrender_picture( physdev );
1293 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1294 physdev->x11dev->color_shifts );
1295 physdev->pict_format = pict_formats[physdev->format];
1297 return ret;
1300 /***********************************************************************
1301 * xrenderdrv_GetImage
1303 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1304 struct gdi_image_bits *bits, struct bitblt_coords *src )
1306 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1307 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1308 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1311 /***********************************************************************
1312 * xrenderdrv_SetDeviceClipping
1314 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1316 struct xrender_physdev *physdev = get_xrender_dev( dev );
1318 physdev->update_clip = TRUE;
1320 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1321 dev->funcs->pSetDeviceClipping( dev, vis_rgn, clip_rgn );
1325 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1327 XRenderPictFormat *pict_format;
1328 ColorShifts shifts;
1329 const DWORD *bitfields;
1330 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1331 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1334 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1335 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1336 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1337 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1338 return FALSE;
1340 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1341 bitfields = dib->dsBitfields;
1342 else if(bits_pixel == 24 || bits_pixel == 32)
1343 bitfields = bitfields_32;
1344 else
1345 bitfields = bitfields_16;
1347 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1348 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1350 /* Common formats should be in our picture format table. */
1351 if (!pict_format)
1353 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1354 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1355 return FALSE;
1358 physBitmap->depth = pict_format->depth;
1359 physBitmap->trueColor = TRUE;
1360 physBitmap->color_shifts = shifts;
1361 return TRUE;
1364 /************************************************************************
1365 * UploadGlyph
1367 * Helper to ExtTextOut. Must be called inside xrender_cs
1369 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1371 unsigned int buflen;
1372 char *buf;
1373 Glyph gid;
1374 GLYPHMETRICS gm;
1375 XGlyphInfo gi;
1376 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1377 gsCacheEntryFormat *formatEntry;
1378 UINT ggo_format = GGO_GLYPH_INDEX;
1379 enum wxr_format wxr_format;
1380 static const char zero[4];
1381 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1383 switch(format) {
1384 case AA_Grey:
1385 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1386 break;
1387 case AA_RGB:
1388 ggo_format |= WINE_GGO_HRGB_BITMAP;
1389 break;
1390 case AA_BGR:
1391 ggo_format |= WINE_GGO_HBGR_BITMAP;
1392 break;
1393 case AA_VRGB:
1394 ggo_format |= WINE_GGO_VRGB_BITMAP;
1395 break;
1396 case AA_VBGR:
1397 ggo_format |= WINE_GGO_VBGR_BITMAP;
1398 break;
1400 default:
1401 ERR("aa = %d - not implemented\n", format);
1402 case AA_None:
1403 ggo_format |= GGO_BITMAP;
1404 break;
1407 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1408 if(buflen == GDI_ERROR) {
1409 if(format != AA_None) {
1410 format = AA_None;
1411 entry->aa_default = AA_None;
1412 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1413 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1415 if(buflen == GDI_ERROR) {
1416 WARN("GetGlyphOutlineW failed using default glyph\n");
1417 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1418 if(buflen == GDI_ERROR) {
1419 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1420 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1421 if(buflen == GDI_ERROR) {
1422 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1423 return;
1427 TRACE("Turning off antialiasing for this monochrome font\n");
1430 /* If there is nothing for the current type, we create the entry. */
1431 if( !entry->format[format] ) {
1432 entry->format[format] = HeapAlloc(GetProcessHeap(),
1433 HEAP_ZERO_MEMORY,
1434 sizeof(gsCacheEntryFormat));
1436 formatEntry = entry->format[format];
1438 if(formatEntry->nrealized <= glyph) {
1439 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1441 if (formatEntry->realized)
1442 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1443 HEAP_ZERO_MEMORY,
1444 formatEntry->realized,
1445 formatEntry->nrealized * sizeof(BOOL));
1446 else
1447 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1448 HEAP_ZERO_MEMORY,
1449 formatEntry->nrealized * sizeof(BOOL));
1451 if(!X11DRV_XRender_Installed) {
1452 if (formatEntry->bitmaps)
1453 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1454 HEAP_ZERO_MEMORY,
1455 formatEntry->bitmaps,
1456 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1457 else
1458 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1459 HEAP_ZERO_MEMORY,
1460 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1462 if (formatEntry->gis)
1463 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1464 HEAP_ZERO_MEMORY,
1465 formatEntry->gis,
1466 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1467 else
1468 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1469 HEAP_ZERO_MEMORY,
1470 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1474 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1475 switch(format) {
1476 case AA_Grey:
1477 wxr_format = WXR_FORMAT_GRAY;
1478 break;
1480 case AA_RGB:
1481 case AA_BGR:
1482 case AA_VRGB:
1483 case AA_VBGR:
1484 wxr_format = WXR_FORMAT_A8R8G8B8;
1485 break;
1487 default:
1488 ERR("aa = %d - not implemented\n", format);
1489 case AA_None:
1490 wxr_format = WXR_FORMAT_MONO;
1491 break;
1494 wine_tsx11_lock();
1495 formatEntry->font_format = pict_formats[wxr_format];
1496 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1497 wine_tsx11_unlock();
1501 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1502 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1503 formatEntry->realized[glyph] = TRUE;
1505 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1506 buflen,
1507 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1508 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1510 gi.width = gm.gmBlackBoxX;
1511 gi.height = gm.gmBlackBoxY;
1512 gi.x = -gm.gmptGlyphOrigin.x;
1513 gi.y = gm.gmptGlyphOrigin.y;
1514 gi.xOff = gm.gmCellIncX;
1515 gi.yOff = gm.gmCellIncY;
1517 if(TRACE_ON(xrender)) {
1518 int pitch, i, j;
1519 char output[300];
1520 unsigned char *line;
1522 if(format == AA_None) {
1523 pitch = ((gi.width + 31) / 32) * 4;
1524 for(i = 0; i < gi.height; i++) {
1525 line = (unsigned char*) buf + i * pitch;
1526 output[0] = '\0';
1527 for(j = 0; j < pitch * 8; j++) {
1528 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1530 TRACE("%s\n", output);
1532 } else {
1533 static const char blks[] = " .:;!o*#";
1534 char str[2];
1536 str[1] = '\0';
1537 pitch = ((gi.width + 3) / 4) * 4;
1538 for(i = 0; i < gi.height; i++) {
1539 line = (unsigned char*) buf + i * pitch;
1540 output[0] = '\0';
1541 for(j = 0; j < pitch; j++) {
1542 str[0] = blks[line[j] >> 5];
1543 strcat(output, str);
1545 TRACE("%s\n", output);
1551 if(formatEntry->glyphset) {
1552 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1553 unsigned char *byte = (unsigned char*) buf, c;
1554 int i = buflen;
1556 while(i--) {
1557 c = *byte;
1559 /* magic to flip bit order */
1560 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1561 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1562 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1564 *byte++ = c;
1567 else if ( format != AA_Grey &&
1568 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1570 unsigned int i, *data = (unsigned int *)buf;
1571 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1573 gid = glyph;
1576 XRenderCompositeText seems to ignore 0x0 glyphs when
1577 AA_None, which means we lose the advance width of glyphs
1578 like the space. We'll pretend that such glyphs are 1x1
1579 bitmaps.
1582 if(buflen == 0)
1583 gi.width = gi.height = 1;
1585 wine_tsx11_lock();
1586 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1587 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1588 wine_tsx11_unlock();
1589 HeapFree(GetProcessHeap(), 0, buf);
1590 } else {
1591 formatEntry->bitmaps[glyph] = buf;
1594 formatEntry->gis[glyph] = gi;
1597 static void SharpGlyphMono(struct xrender_physdev *physDev, INT x, INT y,
1598 void *bitmap, XGlyphInfo *gi)
1600 unsigned char *srcLine = bitmap, *src;
1601 unsigned char bits, bitsMask;
1602 int width = gi->width;
1603 int stride = ((width + 31) & ~31) >> 3;
1604 int height = gi->height;
1605 int w;
1606 int xspan, lenspan;
1608 TRACE("%d, %d\n", x, y);
1609 x -= gi->x;
1610 y -= gi->y;
1611 while (height--)
1613 src = srcLine;
1614 srcLine += stride;
1615 w = width;
1617 bitsMask = 0x80; /* FreeType is always MSB first */
1618 bits = *src++;
1620 xspan = x;
1621 while (w)
1623 if (bits & bitsMask)
1625 lenspan = 0;
1628 lenspan++;
1629 if (lenspan == w)
1630 break;
1631 bitsMask = bitsMask >> 1;
1632 if (!bitsMask)
1634 bits = *src++;
1635 bitsMask = 0x80;
1637 } while (bits & bitsMask);
1638 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1639 physDev->x11dev->gc, xspan, y, lenspan, 1);
1640 xspan += lenspan;
1641 w -= lenspan;
1643 else
1647 w--;
1648 xspan++;
1649 if (!w)
1650 break;
1651 bitsMask = bitsMask >> 1;
1652 if (!bitsMask)
1654 bits = *src++;
1655 bitsMask = 0x80;
1657 } while (!(bits & bitsMask));
1660 y++;
1664 static void SharpGlyphGray(struct xrender_physdev *physDev, INT x, INT y,
1665 void *bitmap, XGlyphInfo *gi)
1667 unsigned char *srcLine = bitmap, *src, bits;
1668 int width = gi->width;
1669 int stride = ((width + 3) & ~3);
1670 int height = gi->height;
1671 int w;
1672 int xspan, lenspan;
1674 x -= gi->x;
1675 y -= gi->y;
1676 while (height--)
1678 src = srcLine;
1679 srcLine += stride;
1680 w = width;
1682 bits = *src++;
1683 xspan = x;
1684 while (w)
1686 if (bits >= 0x80)
1688 lenspan = 0;
1691 lenspan++;
1692 if (lenspan == w)
1693 break;
1694 bits = *src++;
1695 } while (bits >= 0x80);
1696 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1697 physDev->x11dev->gc, xspan, y, lenspan, 1);
1698 xspan += lenspan;
1699 w -= lenspan;
1701 else
1705 w--;
1706 xspan++;
1707 if (!w)
1708 break;
1709 bits = *src++;
1710 } while (bits < 0x80);
1713 y++;
1718 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1720 int s, l;
1722 s = 0;
1723 while ((mask & 1) == 0)
1725 mask >>= 1;
1726 s++;
1728 l = 0;
1729 while ((mask & 1) == 1)
1731 mask >>= 1;
1732 l++;
1734 *shift = s;
1735 *len = l;
1738 static DWORD GetField (DWORD pixel, int shift, int len)
1740 pixel = pixel & (((1 << (len)) - 1) << shift);
1741 pixel = pixel << (32 - (shift + len)) >> 24;
1742 while (len < 8)
1744 pixel |= (pixel >> len);
1745 len <<= 1;
1747 return pixel;
1751 static DWORD PutField (DWORD pixel, int shift, int len)
1753 shift = shift - (8 - len);
1754 if (len <= 8)
1755 pixel &= (((1 << len) - 1) << (8 - len));
1756 if (shift < 0)
1757 pixel >>= -shift;
1758 else
1759 pixel <<= shift;
1760 return pixel;
1763 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1764 int color)
1766 int r_shift, r_len;
1767 int g_shift, g_len;
1768 int b_shift, b_len;
1769 BYTE *maskLine, *mask, m;
1770 int maskStride;
1771 DWORD pixel;
1772 int width, height;
1773 int w, tx;
1774 BYTE src_r, src_g, src_b;
1776 x -= gi->x;
1777 y -= gi->y;
1778 width = gi->width;
1779 height = gi->height;
1781 maskLine = bitmap;
1782 maskStride = (width + 3) & ~3;
1784 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1785 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1786 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1788 src_r = GetField(color, r_shift, r_len);
1789 src_g = GetField(color, g_shift, g_len);
1790 src_b = GetField(color, b_shift, b_len);
1792 for(; height--; y++)
1794 mask = maskLine;
1795 maskLine += maskStride;
1796 w = width;
1797 tx = x;
1799 if(y < 0) continue;
1800 if(y >= image->height) break;
1802 for(; w--; tx++)
1804 if(tx >= image->width) break;
1806 m = *mask++;
1807 if(tx < 0) continue;
1809 if (m == 0xff)
1810 XPutPixel (image, tx, y, color);
1811 else if (m)
1813 BYTE r, g, b;
1815 pixel = XGetPixel (image, tx, y);
1817 r = GetField(pixel, r_shift, r_len);
1818 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1819 g = GetField(pixel, g_shift, g_len);
1820 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1821 b = GetField(pixel, b_shift, b_len);
1822 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1824 pixel = (PutField (r, r_shift, r_len) |
1825 PutField (g, g_shift, g_len) |
1826 PutField (b, b_shift, b_len));
1827 XPutPixel (image, tx, y, pixel);
1833 /*************************************************************
1834 * get_tile_pict
1836 * Returns an appropriate Picture for tiling the text colour.
1837 * Call and use result within the xrender_cs
1839 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1841 static struct
1843 Pixmap xpm;
1844 Picture pict;
1845 XRenderColor current_color;
1846 } tiles[WXR_NB_FORMATS], *tile;
1848 tile = &tiles[wxr_format];
1850 if(!tile->xpm)
1852 XRenderPictureAttributes pa;
1853 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1855 wine_tsx11_lock();
1856 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1858 pa.repeat = RepeatNormal;
1859 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1860 wine_tsx11_unlock();
1862 /* init current_color to something different from text_pixel */
1863 tile->current_color = *color;
1864 tile->current_color.red ^= 0xffff;
1866 if (wxr_format == WXR_FORMAT_MONO)
1868 /* for a 1bpp bitmap we always need a 1 in the tile */
1869 XRenderColor col;
1870 col.red = col.green = col.blue = 0;
1871 col.alpha = 0xffff;
1872 wine_tsx11_lock();
1873 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1874 wine_tsx11_unlock();
1878 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1880 wine_tsx11_lock();
1881 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1882 wine_tsx11_unlock();
1883 tile->current_color = *color;
1885 return tile->pict;
1888 /*************************************************************
1889 * get_mask_pict
1891 * Returns an appropriate Picture for masking with the specified alpha.
1892 * Call and use result within the xrender_cs
1894 static Picture get_mask_pict( int alpha )
1896 static Pixmap pixmap;
1897 static Picture pict;
1898 static int current_alpha;
1900 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1902 if (!pixmap)
1904 XRenderPictureAttributes pa;
1906 wine_tsx11_lock();
1907 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1908 pa.repeat = RepeatNormal;
1909 pict = pXRenderCreatePicture( gdi_display, pixmap,
1910 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1911 wine_tsx11_unlock();
1912 current_alpha = -1;
1915 if (alpha != current_alpha)
1917 XRenderColor col;
1918 col.red = col.green = col.blue = 0;
1919 col.alpha = current_alpha = alpha;
1920 wine_tsx11_lock();
1921 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1922 wine_tsx11_unlock();
1924 return pict;
1927 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1929 return 1;
1932 /********************************************************************
1933 * is_dib_with_colortable
1935 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1937 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1939 DIBSECTION dib;
1941 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1942 dib.dsBmih.biBitCount <= 8 )
1943 return TRUE;
1945 return FALSE;
1948 /***********************************************************************
1949 * xrenderdrv_ExtTextOut
1951 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1952 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1954 struct xrender_physdev *physdev = get_xrender_dev( dev );
1955 XGCValues xgcval;
1956 gsCacheEntry *entry;
1957 gsCacheEntryFormat *formatEntry;
1958 BOOL retv = FALSE;
1959 int textPixel, backgroundPixel;
1960 RGNDATA *saved_region = NULL;
1961 BOOL disable_antialias = FALSE;
1962 AA_Type aa_type = AA_None;
1963 unsigned int idx;
1964 Picture tile_pict = 0;
1966 if (!physdev->x11dev->has_gdi_font)
1968 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1969 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1972 if(is_dib_with_colortable( physdev->x11dev ))
1974 TRACE("Disabling antialiasing\n");
1975 disable_antialias = TRUE;
1978 xgcval.function = GXcopy;
1979 xgcval.background = physdev->x11dev->backgroundPixel;
1980 xgcval.fill_style = FillSolid;
1981 wine_tsx11_lock();
1982 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1983 wine_tsx11_unlock();
1985 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1987 if(physdev->x11dev->depth == 1) {
1988 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1989 textPixel = 0;
1990 backgroundPixel = 1;
1991 } else {
1992 textPixel = 1;
1993 backgroundPixel = 0;
1995 } else {
1996 textPixel = physdev->x11dev->textPixel;
1997 backgroundPixel = physdev->x11dev->backgroundPixel;
2000 if(flags & ETO_OPAQUE)
2002 wine_tsx11_lock();
2003 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
2004 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
2005 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
2006 lprect->right - lprect->left, lprect->bottom - lprect->top );
2007 wine_tsx11_unlock();
2010 if(count == 0)
2012 retv = TRUE;
2013 goto done_unlock;
2016 EnterCriticalSection(&xrender_cs);
2018 entry = glyphsetCache + physdev->cache_index;
2019 if( disable_antialias == FALSE )
2020 aa_type = entry->aa_default;
2021 formatEntry = entry->format[aa_type];
2023 for(idx = 0; idx < count; idx++) {
2024 if( !formatEntry ) {
2025 UploadGlyph(physdev, wstr[idx], aa_type);
2026 /* re-evaluate antialias since aa_default may have changed */
2027 if( disable_antialias == FALSE )
2028 aa_type = entry->aa_default;
2029 formatEntry = entry->format[aa_type];
2030 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
2031 UploadGlyph(physdev, wstr[idx], aa_type);
2034 if (!formatEntry)
2036 WARN("could not upload requested glyphs\n");
2037 LeaveCriticalSection(&xrender_cs);
2038 goto done_unlock;
2041 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
2042 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2044 if(X11DRV_XRender_Installed)
2046 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
2047 POINT offset = {0, 0};
2048 POINT desired, current;
2049 int render_op = PictOpOver;
2050 Picture pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
2051 XRenderColor col;
2053 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2054 So we pass zeros to the function and move to our starting position using the first
2055 element of the elts array. */
2057 desired.x = physdev->x11dev->dc_rect.left + x;
2058 desired.y = physdev->x11dev->dc_rect.top + y;
2059 current.x = current.y = 0;
2061 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
2062 tile_pict = get_tile_pict(physdev->format, &col);
2064 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2066 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
2067 render_op = PictOpOutReverse; /* This gives us 'black' text */
2069 for(idx = 0; idx < count; idx++)
2071 elts[idx].glyphset = formatEntry->glyphset;
2072 elts[idx].chars = wstr + idx;
2073 elts[idx].nchars = 1;
2074 elts[idx].xOff = desired.x - current.x;
2075 elts[idx].yOff = desired.y - current.y;
2077 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
2078 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
2080 if(!lpDx)
2082 desired.x += formatEntry->gis[wstr[idx]].xOff;
2083 desired.y += formatEntry->gis[wstr[idx]].yOff;
2085 else
2087 if(flags & ETO_PDY)
2089 offset.x += lpDx[idx * 2];
2090 offset.y += lpDx[idx * 2 + 1];
2092 else
2093 offset.x += lpDx[idx];
2094 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
2095 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
2099 wine_tsx11_lock();
2100 /* Make sure we don't have any transforms set from a previous call */
2101 set_xrender_transformation(pict, 1, 1, 0, 0);
2102 pXRenderCompositeText16(gdi_display, render_op,
2103 tile_pict,
2104 pict,
2105 formatEntry->font_format,
2106 0, 0, 0, 0, elts, count);
2107 wine_tsx11_unlock();
2108 HeapFree(GetProcessHeap(), 0, elts);
2109 } else {
2110 POINT offset = {0, 0};
2112 if (flags & ETO_CLIPPED)
2114 HRGN clip_region = CreateRectRgnIndirect( lprect );
2115 saved_region = add_extra_clipping_region( physdev->x11dev, clip_region );
2116 DeleteObject( clip_region );
2119 wine_tsx11_lock();
2120 XSetForeground( gdi_display, physdev->x11dev->gc, textPixel );
2122 if(aa_type == AA_None || physdev->x11dev->depth == 1)
2124 void (* sharp_glyph_fn)(struct xrender_physdev *, INT, INT, void *, XGlyphInfo *);
2126 if(aa_type == AA_None)
2127 sharp_glyph_fn = SharpGlyphMono;
2128 else
2129 sharp_glyph_fn = SharpGlyphGray;
2131 for(idx = 0; idx < count; idx++) {
2132 sharp_glyph_fn(physdev,
2133 physdev->x11dev->dc_rect.left + x + offset.x,
2134 physdev->x11dev->dc_rect.top + y + offset.y,
2135 formatEntry->bitmaps[wstr[idx]],
2136 &formatEntry->gis[wstr[idx]]);
2137 if(lpDx)
2139 if(flags & ETO_PDY)
2141 offset.x += lpDx[idx * 2];
2142 offset.y += lpDx[idx * 2 + 1];
2144 else
2145 offset.x += lpDx[idx];
2147 else
2149 offset.x += formatEntry->gis[wstr[idx]].xOff;
2150 offset.y += formatEntry->gis[wstr[idx]].yOff;
2153 } else {
2154 XImage *image;
2155 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2156 RECT extents = {0, 0, 0, 0};
2157 POINT cur = {0, 0};
2158 int w = physdev->x11dev->drawable_rect.right - physdev->x11dev->drawable_rect.left;
2159 int h = physdev->x11dev->drawable_rect.bottom - physdev->x11dev->drawable_rect.top;
2161 TRACE("drawable %dx%d\n", w, h);
2163 for(idx = 0; idx < count; idx++) {
2164 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2165 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2166 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2167 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2168 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2169 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2170 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2171 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2173 if(lpDx)
2175 if(flags & ETO_PDY)
2177 cur.x += lpDx[idx * 2];
2178 cur.y += lpDx[idx * 2 + 1];
2180 else
2181 cur.x += lpDx[idx];
2183 else
2185 cur.x += formatEntry->gis[wstr[idx]].xOff;
2186 cur.y += formatEntry->gis[wstr[idx]].yOff;
2189 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2190 extents.right, extents.bottom, physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2192 if(physdev->x11dev->dc_rect.left + x + extents.left >= 0) {
2193 image_x = physdev->x11dev->dc_rect.left + x + extents.left;
2194 image_off_x = 0;
2195 } else {
2196 image_x = 0;
2197 image_off_x = physdev->x11dev->dc_rect.left + x + extents.left;
2199 if(physdev->x11dev->dc_rect.top + y + extents.top >= 0) {
2200 image_y = physdev->x11dev->dc_rect.top + y + extents.top;
2201 image_off_y = 0;
2202 } else {
2203 image_y = 0;
2204 image_off_y = physdev->x11dev->dc_rect.top + y + extents.top;
2206 if(physdev->x11dev->dc_rect.left + x + extents.right < w)
2207 image_w = physdev->x11dev->dc_rect.left + x + extents.right - image_x;
2208 else
2209 image_w = w - image_x;
2210 if(physdev->x11dev->dc_rect.top + y + extents.bottom < h)
2211 image_h = physdev->x11dev->dc_rect.top + y + extents.bottom - image_y;
2212 else
2213 image_h = h - image_y;
2215 if(image_w <= 0 || image_h <= 0) goto no_image;
2217 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2218 image = XGetImage(gdi_display, physdev->x11dev->drawable,
2219 image_x, image_y, image_w, image_h,
2220 AllPlanes, ZPixmap);
2221 X11DRV_check_error();
2223 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2224 gdi_display, (int)physdev->x11dev->drawable, image_x, image_y,
2225 image_w, image_h, AllPlanes, ZPixmap,
2226 physdev->x11dev->depth, image);
2227 if(!image) {
2228 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2229 physdev->x11dev->depth);
2230 GC gc;
2231 XGCValues gcv;
2233 gcv.graphics_exposures = False;
2234 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2235 XCopyArea(gdi_display, physdev->x11dev->drawable, xpm, gc, image_x, image_y,
2236 image_w, image_h, 0, 0);
2237 XFreeGC(gdi_display, gc);
2238 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2239 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2240 ZPixmap);
2241 X11DRV_check_error();
2242 XFreePixmap(gdi_display, xpm);
2244 if(!image) goto no_image;
2246 image->red_mask = visual->red_mask;
2247 image->green_mask = visual->green_mask;
2248 image->blue_mask = visual->blue_mask;
2250 for(idx = 0; idx < count; idx++) {
2251 SmoothGlyphGray(image,
2252 offset.x + image_off_x - extents.left,
2253 offset.y + image_off_y - extents.top,
2254 formatEntry->bitmaps[wstr[idx]],
2255 &formatEntry->gis[wstr[idx]],
2256 physdev->x11dev->textPixel);
2257 if(lpDx)
2259 if(flags & ETO_PDY)
2261 offset.x += lpDx[idx * 2];
2262 offset.y += lpDx[idx * 2 + 1];
2264 else
2265 offset.x += lpDx[idx];
2267 else
2269 offset.x += formatEntry->gis[wstr[idx]].xOff;
2270 offset.y += formatEntry->gis[wstr[idx]].yOff;
2273 XPutImage(gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc, image, 0, 0,
2274 image_x, image_y, image_w, image_h);
2275 XDestroyImage(image);
2277 no_image:
2278 wine_tsx11_unlock();
2279 restore_clipping_region( physdev->x11dev, saved_region );
2281 LeaveCriticalSection(&xrender_cs);
2282 retv = TRUE;
2284 done_unlock:
2285 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2286 return retv;
2289 /* multiply the alpha channel of a picture */
2290 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
2291 int x, int y, int width, int height )
2293 XRenderPictureAttributes pa;
2294 Pixmap src_pixmap, mask_pixmap;
2295 Picture src_pict, mask_pict;
2296 XRenderColor color;
2298 wine_tsx11_lock();
2299 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2300 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2301 pa.repeat = RepeatNormal;
2302 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
2303 pa.component_alpha = True;
2304 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
2305 color.red = color.green = color.blue = color.alpha = 0xffff;
2306 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
2307 color.alpha = alpha;
2308 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
2309 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
2310 0, 0, 0, 0, x, y, width, height );
2311 pXRenderFreePicture( gdi_display, src_pict );
2312 pXRenderFreePicture( gdi_display, mask_pict );
2313 XFreePixmap( gdi_display, src_pixmap );
2314 XFreePixmap( gdi_display, mask_pixmap );
2315 wine_tsx11_unlock();
2318 /* Helper function for (stretched) blitting using xrender */
2319 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2320 int x_src, int y_src, int x_dst, int y_dst,
2321 double xscale, double yscale, int width, int height )
2323 int x_offset, y_offset;
2325 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2326 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2327 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2328 wine_tsx11_lock();
2329 if(xscale != 1.0 || yscale != 1.0)
2331 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2332 * in the wrong quadrant of the x-y plane.
2334 x_offset = (xscale < 0) ? -width : 0;
2335 y_offset = (yscale < 0) ? -height : 0;
2336 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2338 else
2340 x_offset = x_src;
2341 y_offset = y_src;
2342 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2344 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2345 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2346 wine_tsx11_unlock();
2349 /* Helper function for (stretched) mono->color blitting using xrender */
2350 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
2351 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
2352 int x_src, int y_src, int x_dst, int y_dst,
2353 double xscale, double yscale, int width, int height )
2355 Picture tile_pict;
2356 int x_offset, y_offset;
2357 XRenderColor color;
2359 /* When doing a mono->color blit, the source data is used as mask, and the source picture
2360 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
2361 * the tile data.
2363 EnterCriticalSection( &xrender_cs );
2364 color = *bg;
2365 color.alpha = 0xffff; /* tile pict needs 100% alpha */
2366 tile_pict = get_tile_pict( dst_format, &color );
2368 wine_tsx11_lock();
2369 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
2371 if (xscale != 1.0 || yscale != 1.0)
2373 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2374 * in the wrong quadrant of the x-y plane.
2376 x_offset = (xscale < 0) ? -width : 0;
2377 y_offset = (yscale < 0) ? -height : 0;
2378 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2380 else
2382 x_offset = x_src;
2383 y_offset = y_src;
2384 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2386 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
2387 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
2388 wine_tsx11_unlock();
2389 LeaveCriticalSection( &xrender_cs );
2391 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
2392 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
2393 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
2396 /* create a pixmap and render picture for an image */
2397 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
2398 struct bitblt_coords *src, enum wxr_format format,
2399 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
2401 DWORD ret;
2402 int width = src->visrect.right - src->visrect.left;
2403 int height = src->visrect.bottom - src->visrect.top;
2404 int depth = pict_formats[format]->depth;
2405 struct gdi_image_bits dst_bits;
2406 XRenderPictureAttributes pa;
2407 XImage *image;
2409 wine_tsx11_lock();
2410 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2411 info->bmiHeader.biWidth, height, 32, 0 );
2412 wine_tsx11_unlock();
2413 if (!image) return ERROR_OUTOFMEMORY;
2415 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2416 if (ret) return ret;
2418 image->data = dst_bits.ptr;
2419 /* hack: make sure the bits are readable if we are reading from a DIB section */
2420 /* to be removed once we get rid of DIB access protections */
2421 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2423 *use_repeat = (width == 1 && height == 1);
2424 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2426 wine_tsx11_lock();
2427 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2428 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2429 src->visrect.left, 0, 0, 0, width, height );
2430 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2431 wine_tsx11_unlock();
2433 /* make coordinates relative to the pixmap */
2434 src->x -= src->visrect.left;
2435 src->y -= src->visrect.top;
2436 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2438 image->data = NULL;
2439 wine_tsx11_lock();
2440 XDestroyImage( image );
2441 wine_tsx11_unlock();
2442 if (dst_bits.free) dst_bits.free( &dst_bits );
2443 return ret;
2446 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2447 Drawable drawable, const struct bitblt_coords *src,
2448 const struct bitblt_coords *dst )
2450 int width = abs( dst->width );
2451 int height = abs( dst->height );
2452 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2453 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2454 int x_dst, y_dst;
2455 Picture src_pict = 0, dst_pict, mask_pict = 0;
2456 BOOL use_repeat;
2457 double xscale, yscale;
2459 use_repeat = use_source_repeat( physdev_src );
2460 if (!use_repeat)
2462 xscale = src->width / (double)dst->width;
2463 yscale = src->height / (double)dst->height;
2465 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2467 if (drawable) /* using an intermediate pixmap */
2469 XRenderPictureAttributes pa;
2471 x_dst = dst->x;
2472 y_dst = dst->y;
2473 pa.repeat = RepeatNone;
2474 wine_tsx11_lock();
2475 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2476 wine_tsx11_unlock();
2478 else
2480 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2481 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2482 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2485 if (src->width < 0) x_src += src->width + 1;
2486 if (src->height < 0) y_src += src->height + 1;
2487 if (dst->width < 0) x_dst += dst->width + 1;
2488 if (dst->height < 0) y_dst += dst->height + 1;
2490 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2492 /* mono -> color */
2493 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2495 XRenderColor fg, bg;
2497 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, &fg );
2498 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, &bg );
2499 fg.alpha = bg.alpha = 0;
2501 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2502 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2504 else /* color -> color (can be at different depths) or mono -> mono */
2506 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2507 mask_pict = get_no_alpha_mask();
2509 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2510 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2513 if (drawable)
2515 wine_tsx11_lock();
2516 pXRenderFreePicture( gdi_display, dst_pict );
2517 wine_tsx11_unlock();
2522 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2523 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2524 Drawable drawable, struct bitblt_coords *src,
2525 struct bitblt_coords *dst, BOOL use_repeat )
2527 int x_src, y_src, x_dst, y_dst;
2528 Picture dst_pict;
2529 XRenderPictureAttributes pa;
2530 double xscale, yscale;
2532 if (drawable) /* using an intermediate pixmap */
2534 RGNDATA *clip_data = NULL;
2536 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2537 x_dst = dst->x;
2538 y_dst = dst->y;
2539 pa.repeat = RepeatNone;
2540 wine_tsx11_lock();
2541 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2542 if (clip_data)
2543 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2544 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2545 wine_tsx11_unlock();
2546 HeapFree( GetProcessHeap(), 0, clip_data );
2548 else
2550 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2551 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2552 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2555 if (!use_repeat)
2557 xscale = src->width / (double)dst->width;
2558 yscale = src->height / (double)dst->height;
2560 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2562 x_src = src->x;
2563 y_src = src->y;
2564 if (src->width < 0) x_src += src->width + 1;
2565 if (src->height < 0) y_src += src->height + 1;
2566 if (dst->width < 0) x_dst += dst->width + 1;
2567 if (dst->height < 0) y_dst += dst->height + 1;
2569 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2570 xscale, yscale, abs( dst->width ), abs( dst->height ));
2572 if (drawable)
2574 wine_tsx11_lock();
2575 pXRenderFreePicture( gdi_display, dst_pict );
2576 wine_tsx11_unlock();
2581 /***********************************************************************
2582 * xrenderdrv_StretchBlt
2584 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2585 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2587 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2588 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2589 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2591 if (src_dev->funcs != dst_dev->funcs)
2593 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2594 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2597 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2599 /* XRender is of no use for color -> mono */
2600 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2601 goto x11drv_fallback;
2603 /* if not stretching, we only need to handle format conversion */
2604 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2606 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2607 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2609 if (rop != SRCCOPY)
2611 GC tmpGC;
2612 Pixmap tmp_pixmap;
2613 struct bitblt_coords tmp;
2615 /* make coordinates relative to tmp pixmap */
2616 tmp = *dst;
2617 tmp.x -= tmp.visrect.left;
2618 tmp.y -= tmp.visrect.top;
2619 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2621 wine_tsx11_lock();
2622 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2623 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2624 XSetGraphicsExposures( gdi_display, tmpGC, False );
2625 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2626 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2627 wine_tsx11_unlock();
2629 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2630 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2632 wine_tsx11_lock();
2633 XFreePixmap( gdi_display, tmp_pixmap );
2634 XFreeGC( gdi_display, tmpGC );
2635 wine_tsx11_unlock();
2637 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2639 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2640 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2641 return TRUE;
2643 x11drv_fallback:
2644 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2648 /***********************************************************************
2649 * xrenderdrv_PutImage
2651 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2652 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2653 struct bitblt_coords *dst, DWORD rop )
2655 struct xrender_physdev *physdev;
2656 X_PHYSBITMAP *bitmap;
2657 DWORD ret;
2658 Pixmap tmp_pixmap;
2659 GC gc;
2660 enum wxr_format src_format, dst_format;
2661 XRenderPictFormat *pict_format;
2662 Pixmap src_pixmap;
2663 Picture src_pict, mask_pict = 0;
2664 BOOL use_repeat;
2666 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2668 if (hbitmap)
2670 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2671 physdev = NULL;
2672 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2674 else
2676 physdev = get_xrender_dev( dev );
2677 bitmap = NULL;
2678 dst_format = physdev->format;
2681 src_format = get_xrender_format_from_bitmapinfo( info, TRUE );
2682 if (!(pict_format = pict_formats[src_format])) goto update_format;
2684 /* make sure we can create an image with the same bpp */
2685 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2686 goto update_format;
2688 /* mono <-> color conversions not supported */
2689 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2690 goto x11drv_fallback;
2692 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2694 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2696 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2697 if (!ret)
2699 struct bitblt_coords tmp;
2701 if (bitmap)
2703 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2704 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2706 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2708 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2709 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2711 X11DRV_DIB_Unlock( bitmap, TRUE );
2712 DeleteObject( rgn );
2714 else
2716 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2718 if (rop != SRCCOPY)
2720 RGNDATA *clip_data = NULL;
2722 /* make coordinates relative to tmp pixmap */
2723 tmp = *dst;
2724 tmp.x -= tmp.visrect.left;
2725 tmp.y -= tmp.visrect.top;
2726 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2728 if (clip) clip_data = add_extra_clipping_region( physdev->x11dev, clip );
2730 wine_tsx11_lock();
2731 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2732 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2733 XSetGraphicsExposures( gdi_display, gc, False );
2734 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2735 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2736 wine_tsx11_unlock();
2738 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2739 NULL, tmp_pixmap, src, &tmp, use_repeat );
2740 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2742 wine_tsx11_lock();
2743 XFreePixmap( gdi_display, tmp_pixmap );
2744 XFreeGC( gdi_display, gc );
2745 wine_tsx11_unlock();
2747 restore_clipping_region( physdev->x11dev, clip_data );
2749 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2750 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2752 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2755 wine_tsx11_lock();
2756 pXRenderFreePicture( gdi_display, src_pict );
2757 XFreePixmap( gdi_display, src_pixmap );
2758 wine_tsx11_unlock();
2760 return ret;
2762 update_format:
2763 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2764 set_color_info( pict_formats[dst_format], info );
2765 return ERROR_BAD_FORMAT;
2767 x11drv_fallback:
2768 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2769 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2770 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2774 /***********************************************************************
2775 * xrenderdrv_BlendImage
2777 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2778 struct bitblt_coords *src, struct bitblt_coords *dst,
2779 BLENDFUNCTION func )
2781 struct xrender_physdev *physdev = get_xrender_dev( dev );
2782 DWORD ret;
2783 enum wxr_format format;
2784 XRenderPictFormat *pict_format;
2785 Picture dst_pict, src_pict, mask_pict;
2786 Pixmap src_pixmap;
2787 BOOL use_repeat;
2789 if (!X11DRV_XRender_Installed)
2791 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2792 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2795 format = get_xrender_format_from_bitmapinfo( info, func.AlphaFormat & AC_SRC_ALPHA );
2796 if (!(pict_format = pict_formats[format])) goto update_format;
2798 /* make sure we can create an image with the same bpp */
2799 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2800 goto update_format;
2802 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2803 goto update_format;
2805 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2807 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2808 if (!ret)
2810 double xscale, yscale;
2812 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2814 if (!use_repeat)
2816 xscale = src->width / (double)dst->width;
2817 yscale = src->height / (double)dst->height;
2819 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2821 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2823 EnterCriticalSection( &xrender_cs );
2824 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2826 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2827 physdev->x11dev->dc_rect.left + dst->x,
2828 physdev->x11dev->dc_rect.top + dst->y,
2829 xscale, yscale, dst->width, dst->height );
2831 wine_tsx11_lock();
2832 pXRenderFreePicture( gdi_display, src_pict );
2833 XFreePixmap( gdi_display, src_pixmap );
2834 wine_tsx11_unlock();
2836 LeaveCriticalSection( &xrender_cs );
2838 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2840 return ret;
2842 update_format:
2843 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2844 set_color_info( physdev->pict_format, info );
2845 return ERROR_BAD_FORMAT;
2849 /***********************************************************************
2850 * xrenderdrv_AlphaBlend
2852 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2853 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2855 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2856 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2857 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2858 XRenderPictureAttributes pa;
2859 Pixmap tmp_pixmap = 0;
2860 double xscale, yscale;
2861 BOOL use_repeat;
2863 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2865 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2866 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2869 if (physdev_dst != physdev_src)
2871 int status = X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_None );
2872 if (status == DIB_Status_AppMod || status == DIB_Status_InSync)
2874 X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2875 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2876 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2878 X11DRV_CoerceDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2880 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2882 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2884 use_repeat = use_source_repeat( physdev_src );
2885 if (!use_repeat)
2887 xscale = src->width / (double)dst->width;
2888 yscale = src->height / (double)dst->height;
2890 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2892 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2894 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2896 /* mono -> color blending needs an intermediate color pixmap */
2897 XRenderColor fg, bg;
2898 int width = src->visrect.right - src->visrect.left;
2899 int height = src->visrect.bottom - src->visrect.top;
2901 /* blending doesn't use the destination DC colors */
2902 fg.red = fg.green = fg.blue = 0;
2903 bg.red = bg.green = bg.blue = 0xffff;
2904 fg.alpha = bg.alpha = 0xffff;
2906 wine_tsx11_lock();
2907 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2908 physdev_dst->pict_format->depth );
2909 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2910 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2911 CPRepeat, &pa );
2912 wine_tsx11_unlock();
2914 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2915 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2917 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2919 /* we need a source picture with no alpha */
2920 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2921 if (format != physdev_src->format)
2923 wine_tsx11_lock();
2924 pa.subwindow_mode = IncludeInferiors;
2925 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2926 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2927 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2928 wine_tsx11_unlock();
2932 if (tmp_pict) src_pict = tmp_pict;
2934 EnterCriticalSection( &xrender_cs );
2935 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2937 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2938 physdev_src->x11dev->dc_rect.left + src->x,
2939 physdev_src->x11dev->dc_rect.top + src->y,
2940 physdev_dst->x11dev->dc_rect.left + dst->x,
2941 physdev_dst->x11dev->dc_rect.top + dst->y,
2942 xscale, yscale, dst->width, dst->height );
2944 wine_tsx11_lock();
2945 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2946 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2947 wine_tsx11_unlock();
2949 LeaveCriticalSection( &xrender_cs );
2950 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2951 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2952 return TRUE;
2956 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2958 /* 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 */
2959 int depth = physBitmap->depth == 1 ? 1 : physDev->depth;
2960 enum wxr_format src_format = get_xrender_format_from_color_shifts(physBitmap->depth, &physBitmap->color_shifts);
2961 enum wxr_format dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2963 wine_tsx11_lock();
2964 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2966 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2967 if( (physBitmap->depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->depth) ||
2968 (src_format == dst_format) )
2970 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2971 get_bitmap_gc(physBitmap->depth), 0, 0, width, height, 0, 0 );
2973 else /* We need depth conversion */
2975 Picture src_pict, dst_pict;
2976 XRenderPictureAttributes pa;
2977 pa.subwindow_mode = IncludeInferiors;
2978 pa.repeat = RepeatNone;
2980 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap,
2981 pict_formats[src_format], CPSubwindowMode|CPRepeat, &pa);
2982 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap,
2983 pict_formats[dst_format], CPSubwindowMode|CPRepeat, &pa);
2985 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2986 pXRenderFreePicture(gdi_display, src_pict);
2987 pXRenderFreePicture(gdi_display, dst_pict);
2989 wine_tsx11_unlock();
2992 static const struct gdi_dc_funcs xrender_funcs =
2994 NULL, /* pAbortDoc */
2995 NULL, /* pAbortPath */
2996 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2997 NULL, /* pAngleArc */
2998 NULL, /* pArc */
2999 NULL, /* pArcTo */
3000 NULL, /* pBeginPath */
3001 xrenderdrv_BlendImage, /* pBlendImage */
3002 NULL, /* pChoosePixelFormat */
3003 NULL, /* pChord */
3004 NULL, /* pCloseFigure */
3005 xrenderdrv_CreateBitmap, /* pCreateBitmap */
3006 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
3007 xrenderdrv_CreateDC, /* pCreateDC */
3008 NULL, /* pCreateDIBSection */
3009 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
3010 xrenderdrv_DeleteDC, /* pDeleteDC */
3011 NULL, /* pDeleteObject */
3012 NULL, /* pDescribePixelFormat */
3013 NULL, /* pDeviceCapabilities */
3014 NULL, /* pEllipse */
3015 NULL, /* pEndDoc */
3016 NULL, /* pEndPage */
3017 NULL, /* pEndPath */
3018 NULL, /* pEnumDeviceFonts */
3019 NULL, /* pEnumICMProfiles */
3020 NULL, /* pExcludeClipRect */
3021 NULL, /* pExtDeviceMode */
3022 xrenderdrv_ExtEscape, /* pExtEscape */
3023 NULL, /* pExtFloodFill */
3024 NULL, /* pExtSelectClipRgn */
3025 xrenderdrv_ExtTextOut, /* pExtTextOut */
3026 NULL, /* pFillPath */
3027 NULL, /* pFillRgn */
3028 NULL, /* pFlattenPath */
3029 NULL, /* pFrameRgn */
3030 NULL, /* pGdiComment */
3031 NULL, /* pGetCharWidth */
3032 NULL, /* pGetDeviceCaps */
3033 NULL, /* pGetDeviceGammaRamp */
3034 NULL, /* pGetICMProfile */
3035 xrenderdrv_GetImage, /* pGetImage */
3036 NULL, /* pGetNearestColor */
3037 NULL, /* pGetPixel */
3038 NULL, /* pGetPixelFormat */
3039 NULL, /* pGetSystemPaletteEntries */
3040 NULL, /* pGetTextExtentExPoint */
3041 NULL, /* pGetTextMetrics */
3042 NULL, /* pIntersectClipRect */
3043 NULL, /* pInvertRgn */
3044 NULL, /* pLineTo */
3045 NULL, /* pModifyWorldTransform */
3046 NULL, /* pMoveTo */
3047 NULL, /* pOffsetClipRgn */
3048 NULL, /* pOffsetViewportOrg */
3049 NULL, /* pOffsetWindowOrg */
3050 NULL, /* pPaintRgn */
3051 NULL, /* pPatBlt */
3052 NULL, /* pPie */
3053 NULL, /* pPolyBezier */
3054 NULL, /* pPolyBezierTo */
3055 NULL, /* pPolyDraw */
3056 NULL, /* pPolyPolygon */
3057 NULL, /* pPolyPolyline */
3058 NULL, /* pPolygon */
3059 NULL, /* pPolyline */
3060 NULL, /* pPolylineTo */
3061 xrenderdrv_PutImage, /* pPutImage */
3062 NULL, /* pRealizeDefaultPalette */
3063 NULL, /* pRealizePalette */
3064 NULL, /* pRectangle */
3065 NULL, /* pResetDC */
3066 NULL, /* pRestoreDC */
3067 NULL, /* pRoundRect */
3068 NULL, /* pSaveDC */
3069 NULL, /* pScaleViewportExt */
3070 NULL, /* pScaleWindowExt */
3071 xrenderdrv_SelectBitmap, /* pSelectBitmap */
3072 NULL, /* pSelectBrush */
3073 NULL, /* pSelectClipPath */
3074 xrenderdrv_SelectFont, /* pSelectFont */
3075 NULL, /* pSelectPalette */
3076 NULL, /* pSelectPen */
3077 NULL, /* pSetArcDirection */
3078 NULL, /* pSetBkColor */
3079 NULL, /* pSetBkMode */
3080 NULL, /* pSetDCBrushColor */
3081 NULL, /* pSetDCPenColor */
3082 NULL, /* pSetDIBColorTable */
3083 NULL, /* pSetDIBitsToDevice */
3084 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
3085 NULL, /* pSetDeviceGammaRamp */
3086 NULL, /* pSetLayout */
3087 NULL, /* pSetMapMode */
3088 NULL, /* pSetMapperFlags */
3089 NULL, /* pSetPixel */
3090 NULL, /* pSetPixelFormat */
3091 NULL, /* pSetPolyFillMode */
3092 NULL, /* pSetROP2 */
3093 NULL, /* pSetRelAbs */
3094 NULL, /* pSetStretchBltMode */
3095 NULL, /* pSetTextAlign */
3096 NULL, /* pSetTextCharacterExtra */
3097 NULL, /* pSetTextColor */
3098 NULL, /* pSetTextJustification */
3099 NULL, /* pSetViewportExt */
3100 NULL, /* pSetViewportOrg */
3101 NULL, /* pSetWindowExt */
3102 NULL, /* pSetWindowOrg */
3103 NULL, /* pSetWorldTransform */
3104 NULL, /* pStartDoc */
3105 NULL, /* pStartPage */
3106 xrenderdrv_StretchBlt, /* pStretchBlt */
3107 NULL, /* pStretchDIBits */
3108 NULL, /* pStrokeAndFillPath */
3109 NULL, /* pStrokePath */
3110 NULL, /* pSwapBuffers */
3111 NULL, /* pUnrealizePalette */
3112 NULL, /* pWidenPath */
3113 /* OpenGL not supported */
3116 #else /* SONAME_LIBXRENDER */
3118 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
3120 TRACE("XRender support not compiled in.\n");
3121 return NULL;
3124 void X11DRV_XRender_Finalize(void)
3128 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
3130 wine_tsx11_lock();
3131 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
3133 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
3134 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
3135 wine_tsx11_unlock();
3138 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
3140 return FALSE;
3143 #endif /* SONAME_LIBXRENDER */