winex11: Get rid of the client-side DIB optimization in AlphaBlend.
[wine/wine-gecko.git] / dlls / winex11.drv / xrender.c
blob1986fa3877052b1e37a5310b08ef5679f2311a5b
1 /*
2 * Functions to use the XRender extension
4 * Copyright 2001, 2002 Huw D M Davies for CodeWeavers
5 * Copyright 2009 Roderick Colenbrander
6 * Copyright 2011 Alexandre Julliard
8 * Some parts also:
9 * Copyright 2000 Keith Packard, member of The XFree86 Project, Inc.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <stdlib.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "x11drv.h"
36 #include "winternl.h"
37 #include "wine/library.h"
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 int using_client_side_fonts = FALSE;
43 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
45 #ifdef SONAME_LIBXRENDER
47 static BOOL X11DRV_XRender_Installed = FALSE;
49 #include <X11/Xlib.h>
50 #include <X11/extensions/Xrender.h>
52 #ifndef RepeatNone /* added in 0.10 */
53 #define RepeatNone 0
54 #define RepeatNormal 1
55 #define RepeatPad 2
56 #define RepeatReflect 3
57 #endif
59 enum wxr_format
61 WXR_FORMAT_MONO,
62 WXR_FORMAT_GRAY,
63 WXR_FORMAT_X1R5G5B5,
64 WXR_FORMAT_X1B5G5R5,
65 WXR_FORMAT_R5G6B5,
66 WXR_FORMAT_B5G6R5,
67 WXR_FORMAT_R8G8B8,
68 WXR_FORMAT_B8G8R8,
69 WXR_FORMAT_A8R8G8B8,
70 WXR_FORMAT_B8G8R8A8,
71 WXR_FORMAT_X8R8G8B8,
72 WXR_FORMAT_B8G8R8X8,
73 WXR_NB_FORMATS,
74 WXR_INVALID_FORMAT = WXR_NB_FORMATS
77 typedef struct wine_xrender_format_template
79 unsigned int depth;
80 unsigned int alpha;
81 unsigned int alphaMask;
82 unsigned int red;
83 unsigned int redMask;
84 unsigned int green;
85 unsigned int greenMask;
86 unsigned int blue;
87 unsigned int blueMask;
88 } WineXRenderFormatTemplate;
90 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
92 /* Format depth alpha mask red mask green mask blue mask*/
93 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
94 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
95 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
96 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
97 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
98 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
99 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
101 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
103 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
107 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
109 /* format phys red phys green phys blue log red log green log blue */
110 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
111 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
112 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
113 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
114 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
115 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
116 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
118 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
120 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
124 static enum wxr_format default_format = WXR_INVALID_FORMAT;
125 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
127 typedef struct
129 LOGFONTW lf;
130 XFORM xform;
131 SIZE devsize; /* size in device coords */
132 DWORD hash;
133 } LFANDSIZE;
135 #define INITIAL_REALIZED_BUF_SIZE 128
137 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
139 typedef struct
141 GlyphSet glyphset;
142 XRenderPictFormat *font_format;
143 int nrealized;
144 BOOL *realized;
145 void **bitmaps;
146 XGlyphInfo *gis;
147 } gsCacheEntryFormat;
149 typedef struct
151 LFANDSIZE lfsz;
152 AA_Type aa_default;
153 gsCacheEntryFormat * format[AA_MAXVALUE];
154 INT count;
155 INT next;
156 } gsCacheEntry;
158 struct xrender_physdev
160 struct gdi_physdev dev;
161 X11DRV_PDEVICE *x11dev;
162 enum wxr_format format;
163 int cache_index;
164 BOOL update_clip;
165 Picture pict;
166 Picture pict_src;
167 XRenderPictFormat *pict_format;
170 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
172 return (struct xrender_physdev *)dev;
175 static const struct gdi_dc_funcs xrender_funcs;
177 static gsCacheEntry *glyphsetCache = NULL;
178 static DWORD glyphsetCacheSize = 0;
179 static INT lastfree = -1;
180 static INT mru = -1;
182 #define INIT_CACHE_SIZE 10
184 static int antialias = 1;
186 static void *xrender_handle;
188 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
189 MAKE_FUNCPTR(XRenderAddGlyphs)
190 MAKE_FUNCPTR(XRenderComposite)
191 MAKE_FUNCPTR(XRenderCompositeText16)
192 MAKE_FUNCPTR(XRenderCreateGlyphSet)
193 MAKE_FUNCPTR(XRenderCreatePicture)
194 MAKE_FUNCPTR(XRenderFillRectangle)
195 MAKE_FUNCPTR(XRenderFindFormat)
196 MAKE_FUNCPTR(XRenderFindVisualFormat)
197 MAKE_FUNCPTR(XRenderFreeGlyphSet)
198 MAKE_FUNCPTR(XRenderFreePicture)
199 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
200 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
201 MAKE_FUNCPTR(XRenderSetPictureTransform)
202 #endif
203 MAKE_FUNCPTR(XRenderQueryExtension)
205 #ifdef SONAME_LIBFONTCONFIG
206 #include <fontconfig/fontconfig.h>
207 MAKE_FUNCPTR(FcConfigSubstitute)
208 MAKE_FUNCPTR(FcDefaultSubstitute)
209 MAKE_FUNCPTR(FcFontMatch)
210 MAKE_FUNCPTR(FcInit)
211 MAKE_FUNCPTR(FcPatternCreate)
212 MAKE_FUNCPTR(FcPatternDestroy)
213 MAKE_FUNCPTR(FcPatternAddInteger)
214 MAKE_FUNCPTR(FcPatternAddString)
215 MAKE_FUNCPTR(FcPatternGetBool)
216 MAKE_FUNCPTR(FcPatternGetInteger)
217 MAKE_FUNCPTR(FcPatternGetString)
218 static void *fontconfig_handle;
219 static BOOL fontconfig_installed;
220 #endif
222 #undef MAKE_FUNCPTR
224 static CRITICAL_SECTION xrender_cs;
225 static CRITICAL_SECTION_DEBUG critsect_debug =
227 0, 0, &xrender_cs,
228 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
229 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
231 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
233 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
234 ( ( (ULONG)_x4 << 24 ) | \
235 ( (ULONG)_x3 << 16 ) | \
236 ( (ULONG)_x2 << 8 ) | \
237 (ULONG)_x1 )
239 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
241 #define GASP_GRIDFIT 0x01
242 #define GASP_DOGRAY 0x02
244 #ifdef WORDS_BIGENDIAN
245 #define get_be_word(x) (x)
246 #define NATIVE_BYTE_ORDER MSBFirst
247 #else
248 #define get_be_word(x) RtlUshortByteSwap(x)
249 #define NATIVE_BYTE_ORDER LSBFirst
250 #endif
252 static BOOL has_alpha( enum wxr_format format )
254 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
257 static enum wxr_format get_format_without_alpha( enum wxr_format format )
259 switch (format)
261 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
262 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
263 default: return format;
267 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
269 templ->id = 0;
270 templ->type = PictTypeDirect;
271 templ->depth = fmt->depth;
272 templ->direct.alpha = fmt->alpha;
273 templ->direct.alphaMask = fmt->alphaMask;
274 templ->direct.red = fmt->red;
275 templ->direct.redMask = fmt->redMask;
276 templ->direct.green = fmt->green;
277 templ->direct.greenMask = fmt->greenMask;
278 templ->direct.blue = fmt->blue;
279 templ->direct.blueMask = fmt->blueMask;
280 templ->colormap = 0;
282 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
284 return TRUE;
287 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
289 if(fmt->depth != screen_depth)
290 return FALSE;
291 if( (fmt->redMask << fmt->red) != visual->red_mask)
292 return FALSE;
293 if( (fmt->greenMask << fmt->green) != visual->green_mask)
294 return FALSE;
295 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
296 return FALSE;
298 /* We never select a default ARGB visual */
299 if(fmt->alphaMask)
300 return FALSE;
302 return TRUE;
305 static int load_xrender_formats(void)
307 int count = 0;
308 unsigned int i;
310 for (i = 0; i < WXR_NB_FORMATS; i++)
312 XRenderPictFormat templ;
314 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
316 wine_tsx11_lock();
317 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
318 if (!pict_formats[i])
320 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
321 if (visual->class == DirectColor)
323 XVisualInfo info;
324 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
325 screen_depth, TrueColor, &info ))
327 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
328 if (pict_formats[i]) visual = info.visual;
332 wine_tsx11_unlock();
333 if (pict_formats[i]) default_format = i;
335 else
337 unsigned long mask = 0;
338 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
340 wine_tsx11_lock();
341 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
342 wine_tsx11_unlock();
344 if (pict_formats[i])
346 count++;
347 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
350 return count;
353 /***********************************************************************
354 * X11DRV_XRender_Init
356 * Let's see if our XServer has the extension available
359 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
361 int event_base, i;
363 if (client_side_with_render &&
364 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
367 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
368 LOAD_FUNCPTR(XRenderAddGlyphs)
369 LOAD_FUNCPTR(XRenderComposite)
370 LOAD_FUNCPTR(XRenderCompositeText16)
371 LOAD_FUNCPTR(XRenderCreateGlyphSet)
372 LOAD_FUNCPTR(XRenderCreatePicture)
373 LOAD_FUNCPTR(XRenderFillRectangle)
374 LOAD_FUNCPTR(XRenderFindFormat)
375 LOAD_FUNCPTR(XRenderFindVisualFormat)
376 LOAD_FUNCPTR(XRenderFreeGlyphSet)
377 LOAD_FUNCPTR(XRenderFreePicture)
378 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
379 LOAD_FUNCPTR(XRenderQueryExtension)
380 #undef LOAD_FUNCPTR
381 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
382 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
383 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
384 #undef LOAD_OPTIONAL_FUNCPTR
385 #endif
387 wine_tsx11_lock();
388 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
389 wine_tsx11_unlock();
390 if(X11DRV_XRender_Installed) {
391 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
392 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
394 wine_tsx11_unlock();
395 WINE_MESSAGE(
396 "Wine has detected that you probably have a buggy version\n"
397 "of libXrender.so . Because of this client side font rendering\n"
398 "will be disabled. Please upgrade this library.\n");
399 X11DRV_XRender_Installed = FALSE;
400 return NULL;
403 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
404 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
405 X11DRV_XRender_Installed = FALSE;
410 #ifdef SONAME_LIBFONTCONFIG
411 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
413 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fontconfig_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
414 LOAD_FUNCPTR(FcConfigSubstitute);
415 LOAD_FUNCPTR(FcDefaultSubstitute);
416 LOAD_FUNCPTR(FcFontMatch);
417 LOAD_FUNCPTR(FcInit);
418 LOAD_FUNCPTR(FcPatternCreate);
419 LOAD_FUNCPTR(FcPatternDestroy);
420 LOAD_FUNCPTR(FcPatternAddInteger);
421 LOAD_FUNCPTR(FcPatternAddString);
422 LOAD_FUNCPTR(FcPatternGetBool);
423 LOAD_FUNCPTR(FcPatternGetInteger);
424 LOAD_FUNCPTR(FcPatternGetString);
425 #undef LOAD_FUNCPTR
426 fontconfig_installed = pFcInit();
428 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
429 #endif
431 sym_not_found:
432 if(X11DRV_XRender_Installed || client_side_with_core)
434 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
435 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
437 glyphsetCacheSize = INIT_CACHE_SIZE;
438 lastfree = 0;
439 for(i = 0; i < INIT_CACHE_SIZE; i++) {
440 glyphsetCache[i].next = i + 1;
441 glyphsetCache[i].count = -1;
443 glyphsetCache[i-1].next = -1;
444 using_client_side_fonts = 1;
446 if(!X11DRV_XRender_Installed) {
447 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
448 if(screen_depth <= 8 || !client_side_antialias_with_core)
449 antialias = 0;
450 } else {
451 if(screen_depth <= 8 || !client_side_antialias_with_render)
452 antialias = 0;
454 return &xrender_funcs;
456 TRACE("Using X11 core fonts\n");
457 return NULL;
460 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
461 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
463 if(pf->direct.redMask)
464 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
465 else
466 dst_color->red = 0;
468 if(pf->direct.greenMask)
469 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
470 else
471 dst_color->green = 0;
473 if(pf->direct.blueMask)
474 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
475 else
476 dst_color->blue = 0;
478 dst_color->alpha = 0xffff;
481 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
483 int redMask, greenMask, blueMask;
484 unsigned int i;
486 if (depth == 1) return WXR_FORMAT_MONO;
488 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
489 if (!shifts) return default_format;
491 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
492 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
493 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
495 /* Try to locate a format which matches the specification of the dibsection. */
496 for(i = 0; i < WXR_NB_FORMATS; i++)
498 if( depth == wxr_formats_template[i].depth &&
499 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
500 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
501 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
502 return i;
505 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
506 ERR("No XRender format found for %u %08x/%08x/%08x\n", depth, redMask, greenMask, blueMask);
507 return WXR_INVALID_FORMAT;
510 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
512 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
514 switch (info->bmiHeader.biBitCount)
516 case 1:
517 return WXR_FORMAT_MONO;
518 case 4:
519 case 8:
520 break;
521 case 24:
522 if (info->bmiHeader.biCompression != BI_RGB) break;
523 return WXR_FORMAT_R8G8B8;
524 case 16:
525 case 32:
526 if (info->bmiHeader.biCompression == BI_BITFIELDS)
528 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
529 unsigned int i;
531 for (i = 0; i < WXR_NB_FORMATS; i++)
533 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
534 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
535 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
536 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
537 return i;
539 break;
541 if (info->bmiHeader.biCompression != BI_RGB) break;
542 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
544 return WXR_INVALID_FORMAT;
547 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
548 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
550 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
551 XTransform xform = {{
552 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
553 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
554 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
557 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
558 #endif
561 /* check if we can use repeating instead of scaling for the specified source DC */
562 static BOOL use_source_repeat( struct xrender_physdev *dev )
564 return (dev->x11dev->bitmap &&
565 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
566 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
569 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
571 if (!dev->pict && dev->pict_format)
573 XRenderPictureAttributes pa;
575 wine_tsx11_lock();
576 pa.subwindow_mode = IncludeInferiors;
577 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
578 dev->pict_format, CPSubwindowMode, &pa );
579 wine_tsx11_unlock();
580 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
581 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
582 dev->update_clip = TRUE;
585 if (dev->update_clip)
587 RGNDATA *clip_data;
588 HRGN rgn = 0;
590 if (clip_rect)
592 rgn = CreateRectRgnIndirect( clip_rect );
593 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
594 CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
596 else if (clip_rgn)
598 rgn = CreateRectRgn( 0, 0, 0, 0 );
599 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
602 if ((clip_data = X11DRV_GetRegionData( rgn ? rgn : dev->x11dev->region, 0 )))
604 wine_tsx11_lock();
605 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
606 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
607 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
608 wine_tsx11_unlock();
609 HeapFree( GetProcessHeap(), 0, clip_data );
611 dev->update_clip = (rgn != 0); /* have to update again if we are using a custom region */
612 if (rgn) DeleteObject( rgn );
614 return dev->pict;
617 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
619 if (!dev->pict_src && dev->pict_format)
621 XRenderPictureAttributes pa;
623 wine_tsx11_lock();
624 pa.subwindow_mode = IncludeInferiors;
625 pa.repeat = repeat ? RepeatNormal : RepeatNone;
626 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
627 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
628 wine_tsx11_unlock();
630 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
631 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
634 return dev->pict_src;
637 static void free_xrender_picture( struct xrender_physdev *dev )
639 if (dev->pict || dev->pict_src)
641 wine_tsx11_lock();
642 XFlush( gdi_display );
643 if (dev->pict)
645 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
646 pXRenderFreePicture(gdi_display, dev->pict);
647 dev->pict = 0;
649 if(dev->pict_src)
651 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
652 pXRenderFreePicture(gdi_display, dev->pict_src);
653 dev->pict_src = 0;
655 wine_tsx11_unlock();
659 /* return a mask picture used to force alpha to 0 */
660 static Picture get_no_alpha_mask(void)
662 static Pixmap pixmap;
663 static Picture pict;
665 wine_tsx11_lock();
666 if (!pict)
668 XRenderPictureAttributes pa;
669 XRenderColor col;
671 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
672 pa.repeat = RepeatNormal;
673 pa.component_alpha = True;
674 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
675 CPRepeat|CPComponentAlpha, &pa );
676 col.red = col.green = col.blue = 0xffff;
677 col.alpha = 0;
678 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
680 wine_tsx11_unlock();
681 return pict;
684 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
686 if(p1->hash != p2->hash) return TRUE;
687 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
688 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
689 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
690 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
693 #if 0
694 static void walk_cache(void)
696 int i;
698 EnterCriticalSection(&xrender_cs);
699 for(i=mru; i >= 0; i = glyphsetCache[i].next)
700 TRACE("item %d\n", i);
701 LeaveCriticalSection(&xrender_cs);
703 #endif
705 static int LookupEntry(LFANDSIZE *plfsz)
707 int i, prev_i = -1;
709 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
710 TRACE("%d\n", i);
711 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
713 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
714 glyphsetCache[i].count++;
715 if(prev_i >= 0) {
716 glyphsetCache[prev_i].next = glyphsetCache[i].next;
717 glyphsetCache[i].next = mru;
718 mru = i;
720 TRACE("found font in cache %d\n", i);
721 return i;
723 prev_i = i;
725 TRACE("font not in cache\n");
726 return -1;
729 static void FreeEntry(int entry)
731 int i, format;
733 for(format = 0; format < AA_MAXVALUE; format++) {
734 gsCacheEntryFormat * formatEntry;
736 if( !glyphsetCache[entry].format[format] )
737 continue;
739 formatEntry = glyphsetCache[entry].format[format];
741 if(formatEntry->glyphset) {
742 wine_tsx11_lock();
743 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
744 wine_tsx11_unlock();
745 formatEntry->glyphset = 0;
747 if(formatEntry->nrealized) {
748 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
749 formatEntry->realized = NULL;
750 if(formatEntry->bitmaps) {
751 for(i = 0; i < formatEntry->nrealized; i++)
752 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
753 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
754 formatEntry->bitmaps = NULL;
756 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
757 formatEntry->gis = NULL;
758 formatEntry->nrealized = 0;
761 HeapFree(GetProcessHeap(), 0, formatEntry);
762 glyphsetCache[entry].format[format] = NULL;
766 static int AllocEntry(void)
768 int best = -1, prev_best = -1, i, prev_i = -1;
770 if(lastfree >= 0) {
771 assert(glyphsetCache[lastfree].count == -1);
772 glyphsetCache[lastfree].count = 1;
773 best = lastfree;
774 lastfree = glyphsetCache[lastfree].next;
775 assert(best != mru);
776 glyphsetCache[best].next = mru;
777 mru = best;
779 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
780 return mru;
783 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
784 if(glyphsetCache[i].count == 0) {
785 best = i;
786 prev_best = prev_i;
788 prev_i = i;
791 if(best >= 0) {
792 TRACE("freeing unused glyphset at cache %d\n", best);
793 FreeEntry(best);
794 glyphsetCache[best].count = 1;
795 if(prev_best >= 0) {
796 glyphsetCache[prev_best].next = glyphsetCache[best].next;
797 glyphsetCache[best].next = mru;
798 mru = best;
799 } else {
800 assert(mru == best);
802 return mru;
805 TRACE("Growing cache\n");
807 if (glyphsetCache)
808 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
809 glyphsetCache,
810 (glyphsetCacheSize + INIT_CACHE_SIZE)
811 * sizeof(*glyphsetCache));
812 else
813 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
814 (glyphsetCacheSize + INIT_CACHE_SIZE)
815 * sizeof(*glyphsetCache));
817 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
818 i++) {
819 glyphsetCache[i].next = i + 1;
820 glyphsetCache[i].count = -1;
822 glyphsetCache[i-1].next = -1;
823 glyphsetCacheSize += INIT_CACHE_SIZE;
825 lastfree = glyphsetCache[best].next;
826 glyphsetCache[best].count = 1;
827 glyphsetCache[best].next = mru;
828 mru = best;
829 TRACE("new free cache slot at %d\n", mru);
830 return mru;
833 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
835 DWORD size;
836 WORD *gasp, *buffer;
837 WORD num_recs;
838 DWORD ppem;
839 TEXTMETRICW tm;
841 *flags = 0;
843 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
844 if(size == GDI_ERROR)
845 return FALSE;
847 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
848 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
850 GetTextMetricsW(hdc, &tm);
851 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
853 gasp++;
854 num_recs = get_be_word(*gasp);
855 gasp++;
856 while(num_recs--)
858 *flags = get_be_word(*(gasp + 1));
859 if(ppem <= get_be_word(*gasp))
860 break;
861 gasp += 2;
863 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
865 HeapFree(GetProcessHeap(), 0, buffer);
866 return TRUE;
869 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
871 AA_Type ret;
872 WORD flags;
873 UINT font_smoothing_type, font_smoothing_orientation;
875 if (X11DRV_XRender_Installed && subpixel &&
876 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
877 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
879 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
880 &font_smoothing_orientation, 0) &&
881 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
883 ret = AA_BGR;
885 else
886 ret = AA_RGB;
887 /*FIXME
888 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
889 But, Wine's subpixel rendering can support the portrait mode.
892 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
893 ret = AA_Grey;
894 else
895 ret = AA_None;
897 return ret;
900 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
902 int ret;
903 int format;
904 gsCacheEntry *entry;
905 static int hinter = -1;
906 static int subpixel = -1;
907 BOOL font_smoothing;
909 if((ret = LookupEntry(plfsz)) != -1) return ret;
911 ret = AllocEntry();
912 entry = glyphsetCache + ret;
913 entry->lfsz = *plfsz;
914 for( format = 0; format < AA_MAXVALUE; format++ ) {
915 assert( !entry->format[format] );
918 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
920 if(hinter == -1 || subpixel == -1)
922 RASTERIZER_STATUS status;
923 GetRasterizerCaps(&status, sizeof(status));
924 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
925 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
928 switch (plfsz->lf.lfQuality)
930 case ANTIALIASED_QUALITY:
931 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
932 return ret; /* ignore further configuration */
933 case CLEARTYPE_QUALITY:
934 case CLEARTYPE_NATURAL_QUALITY:
935 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
936 break;
937 case DEFAULT_QUALITY:
938 case DRAFT_QUALITY:
939 case PROOF_QUALITY:
940 default:
941 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
942 font_smoothing)
944 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
946 else
947 entry->aa_default = AA_None;
948 break;
951 font_smoothing = TRUE; /* default to enabled */
952 #ifdef SONAME_LIBFONTCONFIG
953 if (fontconfig_installed)
955 FcPattern *match, *pattern = pFcPatternCreate();
956 FcResult result;
957 char family[LF_FACESIZE * 4];
959 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
960 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
961 if (plfsz->lf.lfWeight != FW_DONTCARE)
963 int weight;
964 switch (plfsz->lf.lfWeight)
966 case FW_THIN: weight = FC_WEIGHT_THIN; break;
967 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
968 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
969 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
970 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
971 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
972 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
973 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
974 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
975 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
977 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
979 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
980 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
981 pFcDefaultSubstitute( pattern );
982 if ((match = pFcFontMatch( NULL, pattern, &result )))
984 int rgba;
985 FcBool antialias;
987 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
988 antialias = TRUE;
989 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
991 FcChar8 *file;
992 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
994 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
995 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
997 switch (rgba)
999 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1000 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1001 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1002 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1003 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1006 if (!antialias) font_smoothing = FALSE;
1007 pFcPatternDestroy( match );
1009 pFcPatternDestroy( pattern );
1011 #endif /* SONAME_LIBFONTCONFIG */
1013 /* now check Xft resources */
1015 char *value;
1016 BOOL antialias = TRUE;
1018 wine_tsx11_lock();
1019 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1021 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1022 value[0] == '0' || !strcasecmp( value, "off" ))
1023 antialias = FALSE;
1025 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1027 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1028 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1029 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1030 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1031 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1032 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1034 wine_tsx11_unlock();
1035 if (!antialias) font_smoothing = FALSE;
1038 if (!font_smoothing) entry->aa_default = AA_None;
1040 /* we can't support subpixel without xrender */
1041 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1043 else
1044 entry->aa_default = AA_None;
1046 return ret;
1049 static void dec_ref_cache(int index)
1051 assert(index >= 0);
1052 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1053 assert(glyphsetCache[index].count > 0);
1054 glyphsetCache[index].count--;
1057 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1059 DWORD hash = 0, *ptr, two_chars;
1060 WORD *pwc;
1061 int i;
1063 hash ^= plfsz->devsize.cx;
1064 hash ^= plfsz->devsize.cy;
1065 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1066 hash ^= *ptr;
1067 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1068 hash ^= *ptr;
1069 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1070 two_chars = *ptr;
1071 pwc = (WCHAR *)&two_chars;
1072 if(!*pwc) break;
1073 *pwc = toupperW(*pwc);
1074 pwc++;
1075 *pwc = toupperW(*pwc);
1076 hash ^= two_chars;
1077 if(!*pwc) break;
1079 plfsz->hash = hash;
1080 return;
1083 /***********************************************************************
1084 * X11DRV_XRender_Finalize
1086 void X11DRV_XRender_Finalize(void)
1088 int i;
1090 EnterCriticalSection(&xrender_cs);
1091 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1092 FreeEntry(i);
1093 LeaveCriticalSection(&xrender_cs);
1096 /**********************************************************************
1097 * xrenderdrv_SelectFont
1099 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
1101 struct xrender_physdev *physdev = get_xrender_dev( dev );
1102 LFANDSIZE lfsz;
1104 if (!GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf )) return HGDI_ERROR;
1106 if (!gdiFont)
1108 dev = GET_NEXT_PHYSDEV( dev, pSelectFont );
1109 return dev->funcs->pSelectFont( dev, hfont, gdiFont );
1112 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1113 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1114 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1115 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1116 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1117 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1119 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1120 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1121 lfsz.xform.eM21, lfsz.xform.eM22);
1123 /* Not used fields, would break hashing */
1124 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1126 lfsz_calc_hash(&lfsz);
1128 EnterCriticalSection(&xrender_cs);
1129 if (physdev->cache_index != -1)
1130 dec_ref_cache( physdev->cache_index );
1131 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1132 LeaveCriticalSection(&xrender_cs);
1133 physdev->x11dev->has_gdi_font = TRUE;
1134 return 0;
1137 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1139 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1140 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1142 if (!physdev) return FALSE;
1143 physdev->x11dev = x11dev;
1144 physdev->cache_index = -1;
1145 physdev->format = format;
1146 physdev->pict_format = pict_formats[format];
1147 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1148 return TRUE;
1151 /* store the color mask data in the bitmap info structure */
1152 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1154 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1156 info->bmiHeader.biPlanes = 1;
1157 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1158 info->bmiHeader.biCompression = BI_RGB;
1159 info->bmiHeader.biClrUsed = 0;
1161 switch (info->bmiHeader.biBitCount)
1163 case 16:
1164 colors[0] = format->direct.redMask << format->direct.red;
1165 colors[1] = format->direct.greenMask << format->direct.green;
1166 colors[2] = format->direct.blueMask << format->direct.blue;
1167 info->bmiHeader.biCompression = BI_BITFIELDS;
1168 break;
1169 case 32:
1170 colors[0] = format->direct.redMask << format->direct.red;
1171 colors[1] = format->direct.greenMask << format->direct.green;
1172 colors[2] = format->direct.blueMask << format->direct.blue;
1173 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1174 info->bmiHeader.biCompression = BI_BITFIELDS;
1175 break;
1180 /**********************************************************************
1181 * xrenderdrv_CreateDC
1183 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1184 LPCWSTR output, const DEVMODEW* initData )
1186 return create_xrender_dc( pdev, default_format );
1189 /**********************************************************************
1190 * xrenderdrv_CreateCompatibleDC
1192 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1194 if (orig) /* chain to x11drv first */
1196 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1197 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1199 /* otherwise we have been called by x11drv */
1201 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1204 /**********************************************************************
1205 * xrenderdrv_DeleteDC
1207 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1209 struct xrender_physdev *physdev = get_xrender_dev( dev );
1211 free_xrender_picture( physdev );
1213 EnterCriticalSection( &xrender_cs );
1214 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1215 LeaveCriticalSection( &xrender_cs );
1217 HeapFree( GetProcessHeap(), 0, physdev );
1218 return TRUE;
1221 /**********************************************************************
1222 * xrenderdrv_ExtEscape
1224 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1225 INT out_count, LPVOID out_data )
1227 struct xrender_physdev *physdev = get_xrender_dev( dev );
1229 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1231 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1233 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1235 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1236 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1237 return ret;
1240 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1243 /****************************************************************************
1244 * xrenderdrv_CreateBitmap
1246 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1248 enum wxr_format format = WXR_INVALID_FORMAT;
1249 BITMAP bitmap;
1251 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1253 if (bitmap.bmPlanes == 1 && bitmap.bmBitsPixel == screen_bpp)
1255 switch (bitmap.bmBitsPixel)
1257 case 16: format = WXR_FORMAT_R5G6B5; break;
1258 case 24: format = WXR_FORMAT_R8G8B8; break;
1259 case 32: format = WXR_FORMAT_A8R8G8B8; break;
1263 if (pict_formats[format])
1264 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1265 TRUE, &wxr_color_shifts[format] );
1267 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1268 return dev->funcs->pCreateBitmap( dev, hbitmap );
1271 /****************************************************************************
1272 * xrenderdrv_DeleteBitmap
1274 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1276 return X11DRV_DeleteBitmap( hbitmap );
1279 /***********************************************************************
1280 * xrenderdrv_SelectBitmap
1282 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1284 HBITMAP ret;
1285 struct xrender_physdev *physdev = get_xrender_dev( dev );
1287 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1288 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1289 if (ret)
1291 free_xrender_picture( physdev );
1292 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1293 physdev->x11dev->color_shifts );
1294 physdev->pict_format = pict_formats[physdev->format];
1296 return ret;
1299 /***********************************************************************
1300 * xrenderdrv_GetImage
1302 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1303 struct gdi_image_bits *bits, struct bitblt_coords *src )
1305 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1306 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1307 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1310 /***********************************************************************
1311 * xrenderdrv_SetDeviceClipping
1313 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1315 struct xrender_physdev *physdev = get_xrender_dev( dev );
1317 physdev->update_clip = TRUE;
1319 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1320 dev->funcs->pSetDeviceClipping( dev, vis_rgn, clip_rgn );
1324 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1326 XRenderPictFormat *pict_format;
1327 ColorShifts shifts;
1328 const DWORD *bitfields;
1329 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1330 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1333 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1334 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1335 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1336 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1337 return FALSE;
1339 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1340 bitfields = dib->dsBitfields;
1341 else if(bits_pixel == 24 || bits_pixel == 32)
1342 bitfields = bitfields_32;
1343 else
1344 bitfields = bitfields_16;
1346 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1347 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1349 /* Common formats should be in our picture format table. */
1350 if (!pict_format)
1352 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1353 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1354 return FALSE;
1357 physBitmap->depth = pict_format->depth;
1358 physBitmap->trueColor = TRUE;
1359 physBitmap->color_shifts = shifts;
1360 return TRUE;
1363 /************************************************************************
1364 * UploadGlyph
1366 * Helper to ExtTextOut. Must be called inside xrender_cs
1368 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1370 unsigned int buflen;
1371 char *buf;
1372 Glyph gid;
1373 GLYPHMETRICS gm;
1374 XGlyphInfo gi;
1375 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1376 gsCacheEntryFormat *formatEntry;
1377 UINT ggo_format = GGO_GLYPH_INDEX;
1378 enum wxr_format wxr_format;
1379 static const char zero[4];
1380 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1382 switch(format) {
1383 case AA_Grey:
1384 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1385 break;
1386 case AA_RGB:
1387 ggo_format |= WINE_GGO_HRGB_BITMAP;
1388 break;
1389 case AA_BGR:
1390 ggo_format |= WINE_GGO_HBGR_BITMAP;
1391 break;
1392 case AA_VRGB:
1393 ggo_format |= WINE_GGO_VRGB_BITMAP;
1394 break;
1395 case AA_VBGR:
1396 ggo_format |= WINE_GGO_VBGR_BITMAP;
1397 break;
1399 default:
1400 ERR("aa = %d - not implemented\n", format);
1401 case AA_None:
1402 ggo_format |= GGO_BITMAP;
1403 break;
1406 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1407 if(buflen == GDI_ERROR) {
1408 if(format != AA_None) {
1409 format = AA_None;
1410 entry->aa_default = AA_None;
1411 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1412 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1414 if(buflen == GDI_ERROR) {
1415 WARN("GetGlyphOutlineW failed using default glyph\n");
1416 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1417 if(buflen == GDI_ERROR) {
1418 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1419 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1420 if(buflen == GDI_ERROR) {
1421 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1422 return;
1426 TRACE("Turning off antialiasing for this monochrome font\n");
1429 /* If there is nothing for the current type, we create the entry. */
1430 if( !entry->format[format] ) {
1431 entry->format[format] = HeapAlloc(GetProcessHeap(),
1432 HEAP_ZERO_MEMORY,
1433 sizeof(gsCacheEntryFormat));
1435 formatEntry = entry->format[format];
1437 if(formatEntry->nrealized <= glyph) {
1438 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1440 if (formatEntry->realized)
1441 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1442 HEAP_ZERO_MEMORY,
1443 formatEntry->realized,
1444 formatEntry->nrealized * sizeof(BOOL));
1445 else
1446 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1447 HEAP_ZERO_MEMORY,
1448 formatEntry->nrealized * sizeof(BOOL));
1450 if(!X11DRV_XRender_Installed) {
1451 if (formatEntry->bitmaps)
1452 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1453 HEAP_ZERO_MEMORY,
1454 formatEntry->bitmaps,
1455 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1456 else
1457 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1458 HEAP_ZERO_MEMORY,
1459 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1461 if (formatEntry->gis)
1462 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1463 HEAP_ZERO_MEMORY,
1464 formatEntry->gis,
1465 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1466 else
1467 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1468 HEAP_ZERO_MEMORY,
1469 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1473 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1474 switch(format) {
1475 case AA_Grey:
1476 wxr_format = WXR_FORMAT_GRAY;
1477 break;
1479 case AA_RGB:
1480 case AA_BGR:
1481 case AA_VRGB:
1482 case AA_VBGR:
1483 wxr_format = WXR_FORMAT_A8R8G8B8;
1484 break;
1486 default:
1487 ERR("aa = %d - not implemented\n", format);
1488 case AA_None:
1489 wxr_format = WXR_FORMAT_MONO;
1490 break;
1493 wine_tsx11_lock();
1494 formatEntry->font_format = pict_formats[wxr_format];
1495 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1496 wine_tsx11_unlock();
1500 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1501 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1502 formatEntry->realized[glyph] = TRUE;
1504 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1505 buflen,
1506 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1507 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1509 gi.width = gm.gmBlackBoxX;
1510 gi.height = gm.gmBlackBoxY;
1511 gi.x = -gm.gmptGlyphOrigin.x;
1512 gi.y = gm.gmptGlyphOrigin.y;
1513 gi.xOff = gm.gmCellIncX;
1514 gi.yOff = gm.gmCellIncY;
1516 if(TRACE_ON(xrender)) {
1517 int pitch, i, j;
1518 char output[300];
1519 unsigned char *line;
1521 if(format == AA_None) {
1522 pitch = ((gi.width + 31) / 32) * 4;
1523 for(i = 0; i < gi.height; i++) {
1524 line = (unsigned char*) buf + i * pitch;
1525 output[0] = '\0';
1526 for(j = 0; j < pitch * 8; j++) {
1527 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1529 TRACE("%s\n", output);
1531 } else {
1532 static const char blks[] = " .:;!o*#";
1533 char str[2];
1535 str[1] = '\0';
1536 pitch = ((gi.width + 3) / 4) * 4;
1537 for(i = 0; i < gi.height; i++) {
1538 line = (unsigned char*) buf + i * pitch;
1539 output[0] = '\0';
1540 for(j = 0; j < pitch; j++) {
1541 str[0] = blks[line[j] >> 5];
1542 strcat(output, str);
1544 TRACE("%s\n", output);
1550 if(formatEntry->glyphset) {
1551 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1552 unsigned char *byte = (unsigned char*) buf, c;
1553 int i = buflen;
1555 while(i--) {
1556 c = *byte;
1558 /* magic to flip bit order */
1559 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1560 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1561 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1563 *byte++ = c;
1566 else if ( format != AA_Grey &&
1567 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1569 unsigned int i, *data = (unsigned int *)buf;
1570 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1572 gid = glyph;
1575 XRenderCompositeText seems to ignore 0x0 glyphs when
1576 AA_None, which means we lose the advance width of glyphs
1577 like the space. We'll pretend that such glyphs are 1x1
1578 bitmaps.
1581 if(buflen == 0)
1582 gi.width = gi.height = 1;
1584 wine_tsx11_lock();
1585 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1586 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1587 wine_tsx11_unlock();
1588 HeapFree(GetProcessHeap(), 0, buf);
1589 } else {
1590 formatEntry->bitmaps[glyph] = buf;
1593 formatEntry->gis[glyph] = gi;
1596 static void SharpGlyphMono(struct xrender_physdev *physDev, INT x, INT y,
1597 void *bitmap, XGlyphInfo *gi)
1599 unsigned char *srcLine = bitmap, *src;
1600 unsigned char bits, bitsMask;
1601 int width = gi->width;
1602 int stride = ((width + 31) & ~31) >> 3;
1603 int height = gi->height;
1604 int w;
1605 int xspan, lenspan;
1607 TRACE("%d, %d\n", x, y);
1608 x -= gi->x;
1609 y -= gi->y;
1610 while (height--)
1612 src = srcLine;
1613 srcLine += stride;
1614 w = width;
1616 bitsMask = 0x80; /* FreeType is always MSB first */
1617 bits = *src++;
1619 xspan = x;
1620 while (w)
1622 if (bits & bitsMask)
1624 lenspan = 0;
1627 lenspan++;
1628 if (lenspan == w)
1629 break;
1630 bitsMask = bitsMask >> 1;
1631 if (!bitsMask)
1633 bits = *src++;
1634 bitsMask = 0x80;
1636 } while (bits & bitsMask);
1637 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1638 physDev->x11dev->gc, xspan, y, lenspan, 1);
1639 xspan += lenspan;
1640 w -= lenspan;
1642 else
1646 w--;
1647 xspan++;
1648 if (!w)
1649 break;
1650 bitsMask = bitsMask >> 1;
1651 if (!bitsMask)
1653 bits = *src++;
1654 bitsMask = 0x80;
1656 } while (!(bits & bitsMask));
1659 y++;
1663 static void SharpGlyphGray(struct xrender_physdev *physDev, INT x, INT y,
1664 void *bitmap, XGlyphInfo *gi)
1666 unsigned char *srcLine = bitmap, *src, bits;
1667 int width = gi->width;
1668 int stride = ((width + 3) & ~3);
1669 int height = gi->height;
1670 int w;
1671 int xspan, lenspan;
1673 x -= gi->x;
1674 y -= gi->y;
1675 while (height--)
1677 src = srcLine;
1678 srcLine += stride;
1679 w = width;
1681 bits = *src++;
1682 xspan = x;
1683 while (w)
1685 if (bits >= 0x80)
1687 lenspan = 0;
1690 lenspan++;
1691 if (lenspan == w)
1692 break;
1693 bits = *src++;
1694 } while (bits >= 0x80);
1695 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1696 physDev->x11dev->gc, xspan, y, lenspan, 1);
1697 xspan += lenspan;
1698 w -= lenspan;
1700 else
1704 w--;
1705 xspan++;
1706 if (!w)
1707 break;
1708 bits = *src++;
1709 } while (bits < 0x80);
1712 y++;
1717 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1719 int s, l;
1721 s = 0;
1722 while ((mask & 1) == 0)
1724 mask >>= 1;
1725 s++;
1727 l = 0;
1728 while ((mask & 1) == 1)
1730 mask >>= 1;
1731 l++;
1733 *shift = s;
1734 *len = l;
1737 static DWORD GetField (DWORD pixel, int shift, int len)
1739 pixel = pixel & (((1 << (len)) - 1) << shift);
1740 pixel = pixel << (32 - (shift + len)) >> 24;
1741 while (len < 8)
1743 pixel |= (pixel >> len);
1744 len <<= 1;
1746 return pixel;
1750 static DWORD PutField (DWORD pixel, int shift, int len)
1752 shift = shift - (8 - len);
1753 if (len <= 8)
1754 pixel &= (((1 << len) - 1) << (8 - len));
1755 if (shift < 0)
1756 pixel >>= -shift;
1757 else
1758 pixel <<= shift;
1759 return pixel;
1762 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1763 int color)
1765 int r_shift, r_len;
1766 int g_shift, g_len;
1767 int b_shift, b_len;
1768 BYTE *maskLine, *mask, m;
1769 int maskStride;
1770 DWORD pixel;
1771 int width, height;
1772 int w, tx;
1773 BYTE src_r, src_g, src_b;
1775 x -= gi->x;
1776 y -= gi->y;
1777 width = gi->width;
1778 height = gi->height;
1780 maskLine = bitmap;
1781 maskStride = (width + 3) & ~3;
1783 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1784 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1785 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1787 src_r = GetField(color, r_shift, r_len);
1788 src_g = GetField(color, g_shift, g_len);
1789 src_b = GetField(color, b_shift, b_len);
1791 for(; height--; y++)
1793 mask = maskLine;
1794 maskLine += maskStride;
1795 w = width;
1796 tx = x;
1798 if(y < 0) continue;
1799 if(y >= image->height) break;
1801 for(; w--; tx++)
1803 if(tx >= image->width) break;
1805 m = *mask++;
1806 if(tx < 0) continue;
1808 if (m == 0xff)
1809 XPutPixel (image, tx, y, color);
1810 else if (m)
1812 BYTE r, g, b;
1814 pixel = XGetPixel (image, tx, y);
1816 r = GetField(pixel, r_shift, r_len);
1817 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1818 g = GetField(pixel, g_shift, g_len);
1819 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1820 b = GetField(pixel, b_shift, b_len);
1821 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1823 pixel = (PutField (r, r_shift, r_len) |
1824 PutField (g, g_shift, g_len) |
1825 PutField (b, b_shift, b_len));
1826 XPutPixel (image, tx, y, pixel);
1832 /*************************************************************
1833 * get_tile_pict
1835 * Returns an appropriate Picture for tiling the text colour.
1836 * Call and use result within the xrender_cs
1838 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1840 static struct
1842 Pixmap xpm;
1843 Picture pict;
1844 XRenderColor current_color;
1845 } tiles[WXR_NB_FORMATS], *tile;
1847 tile = &tiles[wxr_format];
1849 if(!tile->xpm)
1851 XRenderPictureAttributes pa;
1852 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1854 wine_tsx11_lock();
1855 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1857 pa.repeat = RepeatNormal;
1858 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1859 wine_tsx11_unlock();
1861 /* init current_color to something different from text_pixel */
1862 tile->current_color = *color;
1863 tile->current_color.red ^= 0xffff;
1865 if (wxr_format == WXR_FORMAT_MONO)
1867 /* for a 1bpp bitmap we always need a 1 in the tile */
1868 XRenderColor col;
1869 col.red = col.green = col.blue = 0;
1870 col.alpha = 0xffff;
1871 wine_tsx11_lock();
1872 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1873 wine_tsx11_unlock();
1877 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1879 wine_tsx11_lock();
1880 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1881 wine_tsx11_unlock();
1882 tile->current_color = *color;
1884 return tile->pict;
1887 /*************************************************************
1888 * get_mask_pict
1890 * Returns an appropriate Picture for masking with the specified alpha.
1891 * Call and use result within the xrender_cs
1893 static Picture get_mask_pict( int alpha )
1895 static Pixmap pixmap;
1896 static Picture pict;
1897 static int current_alpha;
1899 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1901 if (!pixmap)
1903 XRenderPictureAttributes pa;
1905 wine_tsx11_lock();
1906 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1907 pa.repeat = RepeatNormal;
1908 pict = pXRenderCreatePicture( gdi_display, pixmap,
1909 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1910 wine_tsx11_unlock();
1911 current_alpha = -1;
1914 if (alpha != current_alpha)
1916 XRenderColor col;
1917 col.red = col.green = col.blue = 0;
1918 col.alpha = current_alpha = alpha;
1919 wine_tsx11_lock();
1920 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1921 wine_tsx11_unlock();
1923 return pict;
1926 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1928 return 1;
1931 /********************************************************************
1932 * is_dib_with_colortable
1934 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1936 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1938 DIBSECTION dib;
1940 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1941 dib.dsBmih.biBitCount <= 8 )
1942 return TRUE;
1944 return FALSE;
1947 /***********************************************************************
1948 * xrenderdrv_ExtTextOut
1950 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1951 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1953 struct xrender_physdev *physdev = get_xrender_dev( dev );
1954 XGCValues xgcval;
1955 gsCacheEntry *entry;
1956 gsCacheEntryFormat *formatEntry;
1957 BOOL retv = FALSE;
1958 int textPixel, backgroundPixel;
1959 RGNDATA *saved_region = NULL;
1960 BOOL disable_antialias = FALSE;
1961 AA_Type aa_type = AA_None;
1962 unsigned int idx;
1963 Picture tile_pict = 0;
1965 if (!physdev->x11dev->has_gdi_font)
1967 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1968 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1971 if(is_dib_with_colortable( physdev->x11dev ))
1973 TRACE("Disabling antialiasing\n");
1974 disable_antialias = TRUE;
1977 xgcval.function = GXcopy;
1978 xgcval.background = physdev->x11dev->backgroundPixel;
1979 xgcval.fill_style = FillSolid;
1980 wine_tsx11_lock();
1981 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1982 wine_tsx11_unlock();
1984 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1986 if(physdev->x11dev->depth == 1) {
1987 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1988 textPixel = 0;
1989 backgroundPixel = 1;
1990 } else {
1991 textPixel = 1;
1992 backgroundPixel = 0;
1994 } else {
1995 textPixel = physdev->x11dev->textPixel;
1996 backgroundPixel = physdev->x11dev->backgroundPixel;
1999 if(flags & ETO_OPAQUE)
2001 wine_tsx11_lock();
2002 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
2003 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
2004 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
2005 lprect->right - lprect->left, lprect->bottom - lprect->top );
2006 wine_tsx11_unlock();
2009 if(count == 0)
2011 retv = TRUE;
2012 goto done_unlock;
2015 EnterCriticalSection(&xrender_cs);
2017 entry = glyphsetCache + physdev->cache_index;
2018 if( disable_antialias == FALSE )
2019 aa_type = entry->aa_default;
2020 formatEntry = entry->format[aa_type];
2022 for(idx = 0; idx < count; idx++) {
2023 if( !formatEntry ) {
2024 UploadGlyph(physdev, wstr[idx], aa_type);
2025 /* re-evaluate antialias since aa_default may have changed */
2026 if( disable_antialias == FALSE )
2027 aa_type = entry->aa_default;
2028 formatEntry = entry->format[aa_type];
2029 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
2030 UploadGlyph(physdev, wstr[idx], aa_type);
2033 if (!formatEntry)
2035 WARN("could not upload requested glyphs\n");
2036 LeaveCriticalSection(&xrender_cs);
2037 goto done_unlock;
2040 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
2041 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2043 if(X11DRV_XRender_Installed)
2045 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
2046 POINT offset = {0, 0};
2047 POINT desired, current;
2048 int render_op = PictOpOver;
2049 Picture pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
2050 XRenderColor col;
2052 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2053 So we pass zeros to the function and move to our starting position using the first
2054 element of the elts array. */
2056 desired.x = physdev->x11dev->dc_rect.left + x;
2057 desired.y = physdev->x11dev->dc_rect.top + y;
2058 current.x = current.y = 0;
2060 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
2061 tile_pict = get_tile_pict(physdev->format, &col);
2063 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2065 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
2066 render_op = PictOpOutReverse; /* This gives us 'black' text */
2068 for(idx = 0; idx < count; idx++)
2070 elts[idx].glyphset = formatEntry->glyphset;
2071 elts[idx].chars = wstr + idx;
2072 elts[idx].nchars = 1;
2073 elts[idx].xOff = desired.x - current.x;
2074 elts[idx].yOff = desired.y - current.y;
2076 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
2077 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
2079 if(!lpDx)
2081 desired.x += formatEntry->gis[wstr[idx]].xOff;
2082 desired.y += formatEntry->gis[wstr[idx]].yOff;
2084 else
2086 if(flags & ETO_PDY)
2088 offset.x += lpDx[idx * 2];
2089 offset.y += lpDx[idx * 2 + 1];
2091 else
2092 offset.x += lpDx[idx];
2093 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
2094 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
2098 wine_tsx11_lock();
2099 /* Make sure we don't have any transforms set from a previous call */
2100 set_xrender_transformation(pict, 1, 1, 0, 0);
2101 pXRenderCompositeText16(gdi_display, render_op,
2102 tile_pict,
2103 pict,
2104 formatEntry->font_format,
2105 0, 0, 0, 0, elts, count);
2106 wine_tsx11_unlock();
2107 HeapFree(GetProcessHeap(), 0, elts);
2108 } else {
2109 POINT offset = {0, 0};
2111 if (flags & ETO_CLIPPED)
2113 HRGN clip_region = CreateRectRgnIndirect( lprect );
2114 saved_region = add_extra_clipping_region( physdev->x11dev, clip_region );
2115 DeleteObject( clip_region );
2118 wine_tsx11_lock();
2119 XSetForeground( gdi_display, physdev->x11dev->gc, textPixel );
2121 if(aa_type == AA_None || physdev->x11dev->depth == 1)
2123 void (* sharp_glyph_fn)(struct xrender_physdev *, INT, INT, void *, XGlyphInfo *);
2125 if(aa_type == AA_None)
2126 sharp_glyph_fn = SharpGlyphMono;
2127 else
2128 sharp_glyph_fn = SharpGlyphGray;
2130 for(idx = 0; idx < count; idx++) {
2131 sharp_glyph_fn(physdev,
2132 physdev->x11dev->dc_rect.left + x + offset.x,
2133 physdev->x11dev->dc_rect.top + y + offset.y,
2134 formatEntry->bitmaps[wstr[idx]],
2135 &formatEntry->gis[wstr[idx]]);
2136 if(lpDx)
2138 if(flags & ETO_PDY)
2140 offset.x += lpDx[idx * 2];
2141 offset.y += lpDx[idx * 2 + 1];
2143 else
2144 offset.x += lpDx[idx];
2146 else
2148 offset.x += formatEntry->gis[wstr[idx]].xOff;
2149 offset.y += formatEntry->gis[wstr[idx]].yOff;
2152 } else {
2153 XImage *image;
2154 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2155 RECT extents = {0, 0, 0, 0};
2156 POINT cur = {0, 0};
2157 int w = physdev->x11dev->drawable_rect.right - physdev->x11dev->drawable_rect.left;
2158 int h = physdev->x11dev->drawable_rect.bottom - physdev->x11dev->drawable_rect.top;
2160 TRACE("drawable %dx%d\n", w, h);
2162 for(idx = 0; idx < count; idx++) {
2163 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2164 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2165 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2166 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2167 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2168 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2169 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2170 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2172 if(lpDx)
2174 if(flags & ETO_PDY)
2176 cur.x += lpDx[idx * 2];
2177 cur.y += lpDx[idx * 2 + 1];
2179 else
2180 cur.x += lpDx[idx];
2182 else
2184 cur.x += formatEntry->gis[wstr[idx]].xOff;
2185 cur.y += formatEntry->gis[wstr[idx]].yOff;
2188 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2189 extents.right, extents.bottom, physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2191 if(physdev->x11dev->dc_rect.left + x + extents.left >= 0) {
2192 image_x = physdev->x11dev->dc_rect.left + x + extents.left;
2193 image_off_x = 0;
2194 } else {
2195 image_x = 0;
2196 image_off_x = physdev->x11dev->dc_rect.left + x + extents.left;
2198 if(physdev->x11dev->dc_rect.top + y + extents.top >= 0) {
2199 image_y = physdev->x11dev->dc_rect.top + y + extents.top;
2200 image_off_y = 0;
2201 } else {
2202 image_y = 0;
2203 image_off_y = physdev->x11dev->dc_rect.top + y + extents.top;
2205 if(physdev->x11dev->dc_rect.left + x + extents.right < w)
2206 image_w = physdev->x11dev->dc_rect.left + x + extents.right - image_x;
2207 else
2208 image_w = w - image_x;
2209 if(physdev->x11dev->dc_rect.top + y + extents.bottom < h)
2210 image_h = physdev->x11dev->dc_rect.top + y + extents.bottom - image_y;
2211 else
2212 image_h = h - image_y;
2214 if(image_w <= 0 || image_h <= 0) goto no_image;
2216 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2217 image = XGetImage(gdi_display, physdev->x11dev->drawable,
2218 image_x, image_y, image_w, image_h,
2219 AllPlanes, ZPixmap);
2220 X11DRV_check_error();
2222 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2223 gdi_display, (int)physdev->x11dev->drawable, image_x, image_y,
2224 image_w, image_h, AllPlanes, ZPixmap,
2225 physdev->x11dev->depth, image);
2226 if(!image) {
2227 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2228 physdev->x11dev->depth);
2229 GC gc;
2230 XGCValues gcv;
2232 gcv.graphics_exposures = False;
2233 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2234 XCopyArea(gdi_display, physdev->x11dev->drawable, xpm, gc, image_x, image_y,
2235 image_w, image_h, 0, 0);
2236 XFreeGC(gdi_display, gc);
2237 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2238 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2239 ZPixmap);
2240 X11DRV_check_error();
2241 XFreePixmap(gdi_display, xpm);
2243 if(!image) goto no_image;
2245 image->red_mask = visual->red_mask;
2246 image->green_mask = visual->green_mask;
2247 image->blue_mask = visual->blue_mask;
2249 for(idx = 0; idx < count; idx++) {
2250 SmoothGlyphGray(image,
2251 offset.x + image_off_x - extents.left,
2252 offset.y + image_off_y - extents.top,
2253 formatEntry->bitmaps[wstr[idx]],
2254 &formatEntry->gis[wstr[idx]],
2255 physdev->x11dev->textPixel);
2256 if(lpDx)
2258 if(flags & ETO_PDY)
2260 offset.x += lpDx[idx * 2];
2261 offset.y += lpDx[idx * 2 + 1];
2263 else
2264 offset.x += lpDx[idx];
2266 else
2268 offset.x += formatEntry->gis[wstr[idx]].xOff;
2269 offset.y += formatEntry->gis[wstr[idx]].yOff;
2272 XPutImage(gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc, image, 0, 0,
2273 image_x, image_y, image_w, image_h);
2274 XDestroyImage(image);
2276 no_image:
2277 wine_tsx11_unlock();
2278 restore_clipping_region( physdev->x11dev, saved_region );
2280 LeaveCriticalSection(&xrender_cs);
2281 retv = TRUE;
2283 done_unlock:
2284 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2285 return retv;
2288 /* multiply the alpha channel of a picture */
2289 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
2290 int x, int y, int width, int height )
2292 XRenderPictureAttributes pa;
2293 Pixmap src_pixmap, mask_pixmap;
2294 Picture src_pict, mask_pict;
2295 XRenderColor color;
2297 wine_tsx11_lock();
2298 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2299 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2300 pa.repeat = RepeatNormal;
2301 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
2302 pa.component_alpha = True;
2303 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
2304 color.red = color.green = color.blue = color.alpha = 0xffff;
2305 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
2306 color.alpha = alpha;
2307 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
2308 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
2309 0, 0, 0, 0, x, y, width, height );
2310 pXRenderFreePicture( gdi_display, src_pict );
2311 pXRenderFreePicture( gdi_display, mask_pict );
2312 XFreePixmap( gdi_display, src_pixmap );
2313 XFreePixmap( gdi_display, mask_pixmap );
2314 wine_tsx11_unlock();
2317 /* Helper function for (stretched) blitting using xrender */
2318 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2319 int x_src, int y_src, int x_dst, int y_dst,
2320 double xscale, double yscale, int width, int height )
2322 int x_offset, y_offset;
2324 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2325 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2326 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2327 wine_tsx11_lock();
2328 if(xscale != 1.0 || yscale != 1.0)
2330 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2331 * in the wrong quadrant of the x-y plane.
2333 x_offset = (xscale < 0) ? -width : 0;
2334 y_offset = (yscale < 0) ? -height : 0;
2335 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2337 else
2339 x_offset = x_src;
2340 y_offset = y_src;
2341 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2343 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2344 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2345 wine_tsx11_unlock();
2348 /* Helper function for (stretched) mono->color blitting using xrender */
2349 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
2350 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
2351 int x_src, int y_src, int x_dst, int y_dst,
2352 double xscale, double yscale, int width, int height )
2354 Picture tile_pict;
2355 int x_offset, y_offset;
2356 XRenderColor color;
2358 /* When doing a mono->color blit, the source data is used as mask, and the source picture
2359 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
2360 * the tile data.
2362 EnterCriticalSection( &xrender_cs );
2363 color = *bg;
2364 color.alpha = 0xffff; /* tile pict needs 100% alpha */
2365 tile_pict = get_tile_pict( dst_format, &color );
2367 wine_tsx11_lock();
2368 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
2370 if (xscale != 1.0 || yscale != 1.0)
2372 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2373 * in the wrong quadrant of the x-y plane.
2375 x_offset = (xscale < 0) ? -width : 0;
2376 y_offset = (yscale < 0) ? -height : 0;
2377 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2379 else
2381 x_offset = x_src;
2382 y_offset = y_src;
2383 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2385 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
2386 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
2387 wine_tsx11_unlock();
2388 LeaveCriticalSection( &xrender_cs );
2390 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
2391 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
2392 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
2395 /* create a pixmap and render picture for an image */
2396 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
2397 struct bitblt_coords *src, enum wxr_format format,
2398 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
2400 DWORD ret;
2401 int width = src->visrect.right - src->visrect.left;
2402 int height = src->visrect.bottom - src->visrect.top;
2403 int depth = pict_formats[format]->depth;
2404 struct gdi_image_bits dst_bits;
2405 XRenderPictureAttributes pa;
2406 XImage *image;
2408 wine_tsx11_lock();
2409 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2410 info->bmiHeader.biWidth, height, 32, 0 );
2411 wine_tsx11_unlock();
2412 if (!image) return ERROR_OUTOFMEMORY;
2414 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2415 if (ret) return ret;
2417 image->data = dst_bits.ptr;
2418 /* hack: make sure the bits are readable if we are reading from a DIB section */
2419 /* to be removed once we get rid of DIB access protections */
2420 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2422 *use_repeat = (width == 1 && height == 1);
2423 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2425 wine_tsx11_lock();
2426 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2427 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2428 src->visrect.left, 0, 0, 0, width, height );
2429 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2430 wine_tsx11_unlock();
2432 /* make coordinates relative to the pixmap */
2433 src->x -= src->visrect.left;
2434 src->y -= src->visrect.top;
2435 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2437 image->data = NULL;
2438 wine_tsx11_lock();
2439 XDestroyImage( image );
2440 wine_tsx11_unlock();
2441 if (dst_bits.free) dst_bits.free( &dst_bits );
2442 return ret;
2445 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2446 Drawable drawable, const struct bitblt_coords *src,
2447 const struct bitblt_coords *dst )
2449 int width = abs( dst->width );
2450 int height = abs( dst->height );
2451 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2452 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2453 int x_dst, y_dst;
2454 Picture src_pict = 0, dst_pict, mask_pict = 0;
2455 BOOL use_repeat;
2456 double xscale, yscale;
2458 use_repeat = use_source_repeat( physdev_src );
2459 if (!use_repeat)
2461 xscale = src->width / (double)dst->width;
2462 yscale = src->height / (double)dst->height;
2464 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2466 if (drawable) /* using an intermediate pixmap */
2468 XRenderPictureAttributes pa;
2470 x_dst = dst->x;
2471 y_dst = dst->y;
2472 pa.repeat = RepeatNone;
2473 wine_tsx11_lock();
2474 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2475 wine_tsx11_unlock();
2477 else
2479 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2480 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2481 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2484 if (src->width < 0) x_src += src->width + 1;
2485 if (src->height < 0) y_src += src->height + 1;
2486 if (dst->width < 0) x_dst += dst->width + 1;
2487 if (dst->height < 0) y_dst += dst->height + 1;
2489 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2491 /* mono -> color */
2492 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2494 XRenderColor fg, bg;
2496 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, &fg );
2497 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, &bg );
2498 fg.alpha = bg.alpha = 0;
2500 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2501 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2503 else /* color -> color (can be at different depths) or mono -> mono */
2505 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2506 mask_pict = get_no_alpha_mask();
2508 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2509 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2512 if (drawable)
2514 wine_tsx11_lock();
2515 pXRenderFreePicture( gdi_display, dst_pict );
2516 wine_tsx11_unlock();
2521 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2522 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2523 Drawable drawable, struct bitblt_coords *src,
2524 struct bitblt_coords *dst, BOOL use_repeat )
2526 int x_src, y_src, x_dst, y_dst;
2527 Picture dst_pict;
2528 XRenderPictureAttributes pa;
2529 double xscale, yscale;
2531 if (drawable) /* using an intermediate pixmap */
2533 RGNDATA *clip_data = NULL;
2535 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2536 x_dst = dst->x;
2537 y_dst = dst->y;
2538 pa.repeat = RepeatNone;
2539 wine_tsx11_lock();
2540 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2541 if (clip_data)
2542 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2543 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2544 wine_tsx11_unlock();
2545 HeapFree( GetProcessHeap(), 0, clip_data );
2547 else
2549 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2550 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2551 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2554 if (!use_repeat)
2556 xscale = src->width / (double)dst->width;
2557 yscale = src->height / (double)dst->height;
2559 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2561 x_src = src->x;
2562 y_src = src->y;
2563 if (src->width < 0) x_src += src->width + 1;
2564 if (src->height < 0) y_src += src->height + 1;
2565 if (dst->width < 0) x_dst += dst->width + 1;
2566 if (dst->height < 0) y_dst += dst->height + 1;
2568 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2569 xscale, yscale, abs( dst->width ), abs( dst->height ));
2571 if (drawable)
2573 wine_tsx11_lock();
2574 pXRenderFreePicture( gdi_display, dst_pict );
2575 wine_tsx11_unlock();
2580 /***********************************************************************
2581 * xrenderdrv_StretchBlt
2583 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2584 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2586 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2587 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2588 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2590 if (src_dev->funcs != dst_dev->funcs)
2592 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2593 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2596 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2598 /* XRender is of no use for color -> mono */
2599 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2600 goto x11drv_fallback;
2602 /* if not stretching, we only need to handle format conversion */
2603 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2605 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2606 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2608 if (rop != SRCCOPY)
2610 GC tmpGC;
2611 Pixmap tmp_pixmap;
2612 struct bitblt_coords tmp;
2614 /* make coordinates relative to tmp pixmap */
2615 tmp = *dst;
2616 tmp.x -= tmp.visrect.left;
2617 tmp.y -= tmp.visrect.top;
2618 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2620 wine_tsx11_lock();
2621 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2622 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2623 XSetGraphicsExposures( gdi_display, tmpGC, False );
2624 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2625 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2626 wine_tsx11_unlock();
2628 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2629 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2631 wine_tsx11_lock();
2632 XFreePixmap( gdi_display, tmp_pixmap );
2633 XFreeGC( gdi_display, tmpGC );
2634 wine_tsx11_unlock();
2636 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2638 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2639 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2640 return TRUE;
2642 x11drv_fallback:
2643 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2647 /***********************************************************************
2648 * xrenderdrv_PutImage
2650 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2651 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2652 struct bitblt_coords *dst, DWORD rop )
2654 struct xrender_physdev *physdev;
2655 X_PHYSBITMAP *bitmap;
2656 DWORD ret;
2657 Pixmap tmp_pixmap;
2658 GC gc;
2659 enum wxr_format src_format, dst_format;
2660 XRenderPictFormat *pict_format;
2661 Pixmap src_pixmap;
2662 Picture src_pict, mask_pict = 0;
2663 BOOL use_repeat;
2665 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2667 if (hbitmap)
2669 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2670 physdev = NULL;
2671 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2673 else
2675 physdev = get_xrender_dev( dev );
2676 bitmap = NULL;
2677 dst_format = physdev->format;
2680 src_format = get_xrender_format_from_bitmapinfo( info );
2681 if (!(pict_format = pict_formats[src_format])) goto update_format;
2683 /* make sure we can create an image with the same bpp */
2684 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2685 goto update_format;
2687 /* mono <-> color conversions not supported */
2688 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2689 goto x11drv_fallback;
2691 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2693 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2695 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2696 if (!ret)
2698 struct bitblt_coords tmp;
2700 if (bitmap)
2702 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2703 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2705 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2707 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2708 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2710 X11DRV_DIB_Unlock( bitmap, TRUE );
2711 DeleteObject( rgn );
2713 else
2715 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2717 if (rop != SRCCOPY)
2719 RGNDATA *clip_data = NULL;
2721 /* make coordinates relative to tmp pixmap */
2722 tmp = *dst;
2723 tmp.x -= tmp.visrect.left;
2724 tmp.y -= tmp.visrect.top;
2725 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2727 if (clip) clip_data = add_extra_clipping_region( physdev->x11dev, clip );
2729 wine_tsx11_lock();
2730 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2731 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2732 XSetGraphicsExposures( gdi_display, gc, False );
2733 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2734 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2735 wine_tsx11_unlock();
2737 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2738 NULL, tmp_pixmap, src, &tmp, use_repeat );
2739 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2741 wine_tsx11_lock();
2742 XFreePixmap( gdi_display, tmp_pixmap );
2743 XFreeGC( gdi_display, gc );
2744 wine_tsx11_unlock();
2746 restore_clipping_region( physdev->x11dev, clip_data );
2748 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2749 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2751 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2754 wine_tsx11_lock();
2755 pXRenderFreePicture( gdi_display, src_pict );
2756 XFreePixmap( gdi_display, src_pixmap );
2757 wine_tsx11_unlock();
2759 return ret;
2761 update_format:
2762 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2763 set_color_info( pict_formats[dst_format], info );
2764 return ERROR_BAD_FORMAT;
2766 x11drv_fallback:
2767 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2768 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2769 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2773 /***********************************************************************
2774 * xrenderdrv_BlendImage
2776 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2777 struct bitblt_coords *src, struct bitblt_coords *dst,
2778 BLENDFUNCTION func )
2780 struct xrender_physdev *physdev = get_xrender_dev( dev );
2781 DWORD ret;
2782 enum wxr_format format;
2783 XRenderPictFormat *pict_format;
2784 Picture dst_pict, src_pict, mask_pict;
2785 Pixmap src_pixmap;
2786 BOOL use_repeat;
2788 if (!X11DRV_XRender_Installed)
2790 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2791 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2794 format = get_xrender_format_from_bitmapinfo( info );
2795 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2796 format = get_format_without_alpha( format );
2797 else if (format != WXR_FORMAT_A8R8G8B8)
2798 return ERROR_INVALID_PARAMETER;
2800 if (!(pict_format = pict_formats[format])) goto update_format;
2802 /* make sure we can create an image with the same bpp */
2803 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2804 goto update_format;
2806 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2807 goto update_format;
2809 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2811 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2812 if (!ret)
2814 double xscale, yscale;
2816 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2818 if (!use_repeat)
2820 xscale = src->width / (double)dst->width;
2821 yscale = src->height / (double)dst->height;
2823 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2825 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2827 EnterCriticalSection( &xrender_cs );
2828 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2830 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2831 physdev->x11dev->dc_rect.left + dst->x,
2832 physdev->x11dev->dc_rect.top + dst->y,
2833 xscale, yscale, dst->width, dst->height );
2835 wine_tsx11_lock();
2836 pXRenderFreePicture( gdi_display, src_pict );
2837 XFreePixmap( gdi_display, src_pixmap );
2838 wine_tsx11_unlock();
2840 LeaveCriticalSection( &xrender_cs );
2842 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2844 return ret;
2846 update_format:
2847 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2848 set_color_info( physdev->pict_format, info );
2849 return ERROR_BAD_FORMAT;
2853 /***********************************************************************
2854 * xrenderdrv_AlphaBlend
2856 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2857 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2859 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2860 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2861 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2862 XRenderPictureAttributes pa;
2863 Pixmap tmp_pixmap = 0;
2864 double xscale, yscale;
2865 BOOL use_repeat;
2867 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2869 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2870 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2873 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2875 SetLastError( ERROR_INVALID_PARAMETER );
2876 return FALSE;
2879 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2880 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->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 */