winex11: Remove X11 locking around simple X calls.
[wine.git] / dlls / winex11.drv / xrender.c
blob460b1b579a0a380c2f9ffbc749177c03a1866026
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 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
43 #ifdef SONAME_LIBXRENDER
45 WINE_DECLARE_DEBUG_CHANNEL(winediag);
47 #include <X11/Xlib.h>
48 #include <X11/extensions/Xrender.h>
50 #ifndef RepeatNone /* added in 0.10 */
51 #define RepeatNone 0
52 #define RepeatNormal 1
53 #define RepeatPad 2
54 #define RepeatReflect 3
55 #endif
57 enum wxr_format
59 WXR_FORMAT_MONO,
60 WXR_FORMAT_GRAY,
61 WXR_FORMAT_X1R5G5B5,
62 WXR_FORMAT_X1B5G5R5,
63 WXR_FORMAT_R5G6B5,
64 WXR_FORMAT_B5G6R5,
65 WXR_FORMAT_R8G8B8,
66 WXR_FORMAT_B8G8R8,
67 WXR_FORMAT_A8R8G8B8,
68 WXR_FORMAT_B8G8R8A8,
69 WXR_FORMAT_X8R8G8B8,
70 WXR_FORMAT_B8G8R8X8,
71 WXR_NB_FORMATS,
72 WXR_INVALID_FORMAT = WXR_NB_FORMATS
75 typedef struct wine_xrender_format_template
77 unsigned int depth;
78 unsigned int alpha;
79 unsigned int alphaMask;
80 unsigned int red;
81 unsigned int redMask;
82 unsigned int green;
83 unsigned int greenMask;
84 unsigned int blue;
85 unsigned int blueMask;
86 } WineXRenderFormatTemplate;
88 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
90 /* Format depth alpha mask red mask green mask blue mask*/
91 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
92 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
93 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
94 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
95 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
96 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
97 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
98 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
99 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
101 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
105 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
107 /* format phys red phys green phys blue log red log green log blue */
108 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
109 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
110 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
111 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
112 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
113 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
114 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
115 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
116 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
118 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
122 static enum wxr_format default_format = WXR_INVALID_FORMAT;
123 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
125 typedef struct
127 LOGFONTW lf;
128 XFORM xform;
129 SIZE devsize; /* size in device coords */
130 DWORD hash;
131 } LFANDSIZE;
133 #define INITIAL_REALIZED_BUF_SIZE 128
135 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
137 typedef struct
139 GlyphSet glyphset;
140 XRenderPictFormat *font_format;
141 int nrealized;
142 BOOL *realized;
143 XGlyphInfo *gis;
144 } gsCacheEntryFormat;
146 typedef struct
148 LFANDSIZE lfsz;
149 AA_Type aa_default;
150 gsCacheEntryFormat * format[AA_MAXVALUE];
151 INT count;
152 INT next;
153 } gsCacheEntry;
155 struct xrender_physdev
157 struct gdi_physdev dev;
158 X11DRV_PDEVICE *x11dev;
159 HRGN region;
160 enum wxr_format format;
161 int cache_index;
162 BOOL update_clip;
163 Picture pict;
164 Picture pict_src;
165 XRenderPictFormat *pict_format;
168 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
170 return (struct xrender_physdev *)dev;
173 static const struct gdi_dc_funcs xrender_funcs;
175 static gsCacheEntry *glyphsetCache = NULL;
176 static DWORD glyphsetCacheSize = 0;
177 static INT lastfree = -1;
178 static INT mru = -1;
180 #define INIT_CACHE_SIZE 10
182 static int antialias = 1;
184 static void *xrender_handle;
186 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
187 MAKE_FUNCPTR(XRenderAddGlyphs)
188 MAKE_FUNCPTR(XRenderChangePicture)
189 MAKE_FUNCPTR(XRenderComposite)
190 MAKE_FUNCPTR(XRenderCompositeText16)
191 MAKE_FUNCPTR(XRenderCreateGlyphSet)
192 MAKE_FUNCPTR(XRenderCreatePicture)
193 MAKE_FUNCPTR(XRenderFillRectangle)
194 MAKE_FUNCPTR(XRenderFindFormat)
195 MAKE_FUNCPTR(XRenderFindVisualFormat)
196 MAKE_FUNCPTR(XRenderFreeGlyphSet)
197 MAKE_FUNCPTR(XRenderFreePicture)
198 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
199 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
200 MAKE_FUNCPTR(XRenderCreateLinearGradient)
201 #endif
202 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
203 MAKE_FUNCPTR(XRenderSetPictureTransform)
204 #endif
205 MAKE_FUNCPTR(XRenderQueryExtension)
207 #ifdef SONAME_LIBFONTCONFIG
208 #include <fontconfig/fontconfig.h>
209 MAKE_FUNCPTR(FcConfigSubstitute)
210 MAKE_FUNCPTR(FcDefaultSubstitute)
211 MAKE_FUNCPTR(FcFontMatch)
212 MAKE_FUNCPTR(FcInit)
213 MAKE_FUNCPTR(FcPatternCreate)
214 MAKE_FUNCPTR(FcPatternDestroy)
215 MAKE_FUNCPTR(FcPatternAddInteger)
216 MAKE_FUNCPTR(FcPatternAddString)
217 MAKE_FUNCPTR(FcPatternGetBool)
218 MAKE_FUNCPTR(FcPatternGetInteger)
219 MAKE_FUNCPTR(FcPatternGetString)
220 static void *fontconfig_handle;
221 static BOOL fontconfig_installed;
222 #endif
224 #undef MAKE_FUNCPTR
226 static CRITICAL_SECTION xrender_cs;
227 static CRITICAL_SECTION_DEBUG critsect_debug =
229 0, 0, &xrender_cs,
230 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
231 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
233 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
235 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
236 ( ( (ULONG)_x4 << 24 ) | \
237 ( (ULONG)_x3 << 16 ) | \
238 ( (ULONG)_x2 << 8 ) | \
239 (ULONG)_x1 )
241 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
243 #define GASP_GRIDFIT 0x01
244 #define GASP_DOGRAY 0x02
246 #ifdef WORDS_BIGENDIAN
247 #define get_be_word(x) (x)
248 #define NATIVE_BYTE_ORDER MSBFirst
249 #else
250 #define get_be_word(x) RtlUshortByteSwap(x)
251 #define NATIVE_BYTE_ORDER LSBFirst
252 #endif
254 static BOOL has_alpha( enum wxr_format format )
256 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
259 static enum wxr_format get_format_without_alpha( enum wxr_format format )
261 switch (format)
263 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
264 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
265 default: return format;
269 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
271 templ->id = 0;
272 templ->type = PictTypeDirect;
273 templ->depth = fmt->depth;
274 templ->direct.alpha = fmt->alpha;
275 templ->direct.alphaMask = fmt->alphaMask;
276 templ->direct.red = fmt->red;
277 templ->direct.redMask = fmt->redMask;
278 templ->direct.green = fmt->green;
279 templ->direct.greenMask = fmt->greenMask;
280 templ->direct.blue = fmt->blue;
281 templ->direct.blueMask = fmt->blueMask;
282 templ->colormap = 0;
284 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
286 return TRUE;
289 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
291 if(fmt->depth != screen_depth)
292 return FALSE;
293 if( (fmt->redMask << fmt->red) != visual->red_mask)
294 return FALSE;
295 if( (fmt->greenMask << fmt->green) != visual->green_mask)
296 return FALSE;
297 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
298 return FALSE;
300 /* We never select a default ARGB visual */
301 if(fmt->alphaMask)
302 return FALSE;
304 return TRUE;
307 static int load_xrender_formats(void)
309 int count = 0;
310 unsigned int i;
312 for (i = 0; i < WXR_NB_FORMATS; i++)
314 XRenderPictFormat templ;
316 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
318 wine_tsx11_lock();
319 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
320 if (!pict_formats[i])
322 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
323 if (visual->class == DirectColor)
325 XVisualInfo info;
326 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
327 screen_depth, TrueColor, &info ))
329 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
330 if (pict_formats[i]) visual = info.visual;
334 wine_tsx11_unlock();
335 if (pict_formats[i]) default_format = i;
337 else
339 unsigned long mask = 0;
340 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
341 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
343 if (pict_formats[i])
345 count++;
346 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
349 return count;
352 /***********************************************************************
353 * X11DRV_XRender_Init
355 * Let's see if our XServer has the extension available
358 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
360 int event_base, i;
362 if (!client_side_with_render) return NULL;
363 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
365 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
366 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
367 LOAD_FUNCPTR(XRenderAddGlyphs);
368 LOAD_FUNCPTR(XRenderChangePicture);
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 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
381 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
382 #endif
383 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
384 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
385 #endif
386 #undef LOAD_OPTIONAL_FUNCPTR
387 #undef LOAD_FUNCPTR
389 if (!pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) return NULL;
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 ERR_(winediag)("Wine has detected that you probably have a buggy version "
395 "of libXrender. Because of this client side font rendering "
396 "will be disabled. Please upgrade this library.\n");
397 return NULL;
400 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask)
402 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
403 return NULL;
406 #ifdef SONAME_LIBFONTCONFIG
407 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
409 #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;}
410 LOAD_FUNCPTR(FcConfigSubstitute);
411 LOAD_FUNCPTR(FcDefaultSubstitute);
412 LOAD_FUNCPTR(FcFontMatch);
413 LOAD_FUNCPTR(FcInit);
414 LOAD_FUNCPTR(FcPatternCreate);
415 LOAD_FUNCPTR(FcPatternDestroy);
416 LOAD_FUNCPTR(FcPatternAddInteger);
417 LOAD_FUNCPTR(FcPatternAddString);
418 LOAD_FUNCPTR(FcPatternGetBool);
419 LOAD_FUNCPTR(FcPatternGetInteger);
420 LOAD_FUNCPTR(FcPatternGetString);
421 #undef LOAD_FUNCPTR
422 fontconfig_installed = pFcInit();
424 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
426 sym_not_found:
427 #endif
429 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
430 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
432 glyphsetCacheSize = INIT_CACHE_SIZE;
433 lastfree = 0;
434 for(i = 0; i < INIT_CACHE_SIZE; i++) {
435 glyphsetCache[i].next = i + 1;
436 glyphsetCache[i].count = -1;
438 glyphsetCache[i-1].next = -1;
440 if(screen_depth <= 8 || !client_side_antialias_with_render) antialias = 0;
442 return &xrender_funcs;
445 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
446 static void get_xrender_color( struct xrender_physdev *physdev, COLORREF src_color, XRenderColor *dst_color )
448 if (src_color & (1 << 24)) /* PALETTEINDEX */
450 HPALETTE pal = GetCurrentObject( physdev->dev.hdc, OBJ_PAL );
451 PALETTEENTRY pal_ent;
453 if (!GetPaletteEntries( pal, LOWORD(src_color), 1, &pal_ent ))
454 GetPaletteEntries( pal, 0, 1, &pal_ent );
455 dst_color->red = pal_ent.peRed * 257;
456 dst_color->green = pal_ent.peGreen * 257;
457 dst_color->blue = pal_ent.peBlue * 257;
459 else
461 if (src_color >> 16 == 0x10ff) src_color = 0; /* DIBINDEX */
463 dst_color->red = GetRValue( src_color ) * 257;
464 dst_color->green = GetGValue( src_color ) * 257;
465 dst_color->blue = GetBValue( src_color ) * 257;
468 if (physdev->format == WXR_FORMAT_MONO && !dst_color->red && !dst_color->green && !dst_color->blue)
469 dst_color->alpha = 0;
470 else
471 dst_color->alpha = 0xffff;
474 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
476 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
478 switch (info->bmiHeader.biBitCount)
480 case 1:
481 return WXR_FORMAT_MONO;
482 case 4:
483 case 8:
484 break;
485 case 24:
486 if (info->bmiHeader.biCompression != BI_RGB) break;
487 return WXR_FORMAT_R8G8B8;
488 case 16:
489 case 32:
490 if (info->bmiHeader.biCompression == BI_BITFIELDS)
492 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
493 unsigned int i;
495 for (i = 0; i < WXR_NB_FORMATS; i++)
497 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
498 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
499 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
500 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
501 return i;
503 break;
505 if (info->bmiHeader.biCompression != BI_RGB) break;
506 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
508 return WXR_INVALID_FORMAT;
511 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
512 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
514 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
515 XTransform xform = {{
516 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
517 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
518 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
521 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
522 #endif
525 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
527 XRenderPictureAttributes pa;
528 RGNDATA *data;
530 if (!rgn)
532 pa.clip_mask = None;
533 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
535 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
537 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
538 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
539 (XRectangle *)data->Buffer, data->rdh.nCount );
540 HeapFree( GetProcessHeap(), 0, data );
545 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
547 if (!dev->pict && dev->pict_format)
549 XRenderPictureAttributes pa;
551 pa.subwindow_mode = IncludeInferiors;
552 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
553 dev->pict_format, CPSubwindowMode, &pa );
554 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
555 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
556 dev->update_clip = (dev->region != 0);
559 if (clip_rect)
561 HRGN rgn = CreateRectRgnIndirect( clip_rect );
562 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
563 if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
564 update_xrender_clipping( dev, rgn );
565 DeleteObject( rgn );
567 else if (clip_rgn)
569 if (dev->region)
571 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
572 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
573 update_xrender_clipping( dev, rgn );
574 DeleteObject( rgn );
576 else update_xrender_clipping( dev, clip_rgn );
578 else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
580 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
581 return dev->pict;
584 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
586 if (!dev->pict_src && dev->pict_format)
588 XRenderPictureAttributes pa;
590 pa.subwindow_mode = IncludeInferiors;
591 pa.repeat = repeat ? RepeatNormal : RepeatNone;
592 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
593 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
595 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
596 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
599 return dev->pict_src;
602 static void free_xrender_picture( struct xrender_physdev *dev )
604 if (dev->pict || dev->pict_src)
606 wine_tsx11_lock();
607 XFlush( gdi_display );
608 if (dev->pict)
610 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
611 pXRenderFreePicture(gdi_display, dev->pict);
612 dev->pict = 0;
614 if(dev->pict_src)
616 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
617 pXRenderFreePicture(gdi_display, dev->pict_src);
618 dev->pict_src = 0;
620 wine_tsx11_unlock();
624 /* return a mask picture used to force alpha to 0 */
625 static Picture get_no_alpha_mask(void)
627 static Pixmap pixmap;
628 static Picture pict;
630 wine_tsx11_lock();
631 if (!pict)
633 XRenderPictureAttributes pa;
634 XRenderColor col;
636 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
637 pa.repeat = RepeatNormal;
638 pa.component_alpha = True;
639 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
640 CPRepeat|CPComponentAlpha, &pa );
641 col.red = col.green = col.blue = 0xffff;
642 col.alpha = 0;
643 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
645 wine_tsx11_unlock();
646 return pict;
649 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
651 if(p1->hash != p2->hash) return TRUE;
652 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
653 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
654 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
655 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
658 #if 0
659 static void walk_cache(void)
661 int i;
663 EnterCriticalSection(&xrender_cs);
664 for(i=mru; i >= 0; i = glyphsetCache[i].next)
665 TRACE("item %d\n", i);
666 LeaveCriticalSection(&xrender_cs);
668 #endif
670 static int LookupEntry(LFANDSIZE *plfsz)
672 int i, prev_i = -1;
674 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
675 TRACE("%d\n", i);
676 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
678 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
679 glyphsetCache[i].count++;
680 if(prev_i >= 0) {
681 glyphsetCache[prev_i].next = glyphsetCache[i].next;
682 glyphsetCache[i].next = mru;
683 mru = i;
685 TRACE("found font in cache %d\n", i);
686 return i;
688 prev_i = i;
690 TRACE("font not in cache\n");
691 return -1;
694 static void FreeEntry(int entry)
696 int format;
698 for(format = 0; format < AA_MAXVALUE; format++) {
699 gsCacheEntryFormat * formatEntry;
701 if( !glyphsetCache[entry].format[format] )
702 continue;
704 formatEntry = glyphsetCache[entry].format[format];
706 if(formatEntry->glyphset) {
707 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
708 formatEntry->glyphset = 0;
710 if(formatEntry->nrealized) {
711 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
712 formatEntry->realized = NULL;
713 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
714 formatEntry->gis = NULL;
715 formatEntry->nrealized = 0;
718 HeapFree(GetProcessHeap(), 0, formatEntry);
719 glyphsetCache[entry].format[format] = NULL;
723 static int AllocEntry(void)
725 int best = -1, prev_best = -1, i, prev_i = -1;
727 if(lastfree >= 0) {
728 assert(glyphsetCache[lastfree].count == -1);
729 glyphsetCache[lastfree].count = 1;
730 best = lastfree;
731 lastfree = glyphsetCache[lastfree].next;
732 assert(best != mru);
733 glyphsetCache[best].next = mru;
734 mru = best;
736 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
737 return mru;
740 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
741 if(glyphsetCache[i].count == 0) {
742 best = i;
743 prev_best = prev_i;
745 prev_i = i;
748 if(best >= 0) {
749 TRACE("freeing unused glyphset at cache %d\n", best);
750 FreeEntry(best);
751 glyphsetCache[best].count = 1;
752 if(prev_best >= 0) {
753 glyphsetCache[prev_best].next = glyphsetCache[best].next;
754 glyphsetCache[best].next = mru;
755 mru = best;
756 } else {
757 assert(mru == best);
759 return mru;
762 TRACE("Growing cache\n");
764 if (glyphsetCache)
765 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
766 glyphsetCache,
767 (glyphsetCacheSize + INIT_CACHE_SIZE)
768 * sizeof(*glyphsetCache));
769 else
770 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
771 (glyphsetCacheSize + INIT_CACHE_SIZE)
772 * sizeof(*glyphsetCache));
774 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
775 i++) {
776 glyphsetCache[i].next = i + 1;
777 glyphsetCache[i].count = -1;
779 glyphsetCache[i-1].next = -1;
780 glyphsetCacheSize += INIT_CACHE_SIZE;
782 lastfree = glyphsetCache[best].next;
783 glyphsetCache[best].count = 1;
784 glyphsetCache[best].next = mru;
785 mru = best;
786 TRACE("new free cache slot at %d\n", mru);
787 return mru;
790 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
792 DWORD size;
793 WORD *gasp, *buffer;
794 WORD num_recs;
795 DWORD ppem;
796 TEXTMETRICW tm;
798 *flags = 0;
800 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
801 if(size == GDI_ERROR)
802 return FALSE;
804 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
805 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
807 GetTextMetricsW(hdc, &tm);
808 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
810 gasp++;
811 num_recs = get_be_word(*gasp);
812 gasp++;
813 while(num_recs--)
815 *flags = get_be_word(*(gasp + 1));
816 if(ppem <= get_be_word(*gasp))
817 break;
818 gasp += 2;
820 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
822 HeapFree(GetProcessHeap(), 0, buffer);
823 return TRUE;
826 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
828 AA_Type ret;
829 WORD flags;
830 UINT font_smoothing_type, font_smoothing_orientation;
832 if (subpixel &&
833 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
834 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
836 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
837 &font_smoothing_orientation, 0) &&
838 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
840 ret = AA_BGR;
842 else
843 ret = AA_RGB;
844 /*FIXME
845 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
846 But, Wine's subpixel rendering can support the portrait mode.
849 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
850 ret = AA_Grey;
851 else
852 ret = AA_None;
854 return ret;
857 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
859 int ret;
860 int format;
861 gsCacheEntry *entry;
862 static int hinter = -1;
863 static int subpixel = -1;
864 BOOL font_smoothing;
866 if((ret = LookupEntry(plfsz)) != -1) return ret;
868 ret = AllocEntry();
869 entry = glyphsetCache + ret;
870 entry->lfsz = *plfsz;
871 for( format = 0; format < AA_MAXVALUE; format++ ) {
872 assert( !entry->format[format] );
875 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
877 if(hinter == -1 || subpixel == -1)
879 RASTERIZER_STATUS status;
880 GetRasterizerCaps(&status, sizeof(status));
881 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
882 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
885 switch (plfsz->lf.lfQuality)
887 case ANTIALIASED_QUALITY:
888 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
889 return ret; /* ignore further configuration */
890 case CLEARTYPE_QUALITY:
891 case CLEARTYPE_NATURAL_QUALITY:
892 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
893 break;
894 case DEFAULT_QUALITY:
895 case DRAFT_QUALITY:
896 case PROOF_QUALITY:
897 default:
898 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
899 font_smoothing)
901 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
903 else
904 entry->aa_default = AA_None;
905 break;
908 font_smoothing = TRUE; /* default to enabled */
909 #ifdef SONAME_LIBFONTCONFIG
910 if (fontconfig_installed)
912 FcPattern *match, *pattern;
913 FcResult result;
914 char family[LF_FACESIZE * 4];
916 #if defined(__i386__) && defined(__GNUC__)
917 /* fontconfig generates floating point exceptions, mask them */
918 WORD cw, default_cw = 0x37f;
919 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
920 #endif
922 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
923 pattern = pFcPatternCreate();
924 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
925 if (plfsz->lf.lfWeight != FW_DONTCARE)
927 int weight;
928 switch (plfsz->lf.lfWeight)
930 case FW_THIN: weight = FC_WEIGHT_THIN; break;
931 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
932 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
933 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
934 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
935 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
936 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
937 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
938 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
939 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
941 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
943 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
944 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
945 pFcDefaultSubstitute( pattern );
946 if ((match = pFcFontMatch( NULL, pattern, &result )))
948 int rgba;
949 FcBool antialias;
951 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
952 antialias = TRUE;
953 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
955 FcChar8 *file;
956 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
958 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
959 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
961 switch (rgba)
963 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
964 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
965 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
966 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
967 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
970 if (!antialias) font_smoothing = FALSE;
971 pFcPatternDestroy( match );
973 pFcPatternDestroy( pattern );
975 #if defined(__i386__) && defined(__GNUC__)
976 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
977 #endif
979 #endif /* SONAME_LIBFONTCONFIG */
981 /* now check Xft resources */
983 char *value;
984 BOOL antialias = TRUE;
986 wine_tsx11_lock();
987 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
989 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
990 value[0] == '0' || !strcasecmp( value, "off" ))
991 antialias = FALSE;
993 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
995 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
996 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
997 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
998 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
999 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1000 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1002 wine_tsx11_unlock();
1003 if (!antialias) font_smoothing = FALSE;
1006 if (!font_smoothing) entry->aa_default = AA_None;
1008 else
1009 entry->aa_default = AA_None;
1011 return ret;
1014 static void dec_ref_cache(int index)
1016 assert(index >= 0);
1017 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1018 assert(glyphsetCache[index].count > 0);
1019 glyphsetCache[index].count--;
1022 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1024 DWORD hash = 0, *ptr, two_chars;
1025 WORD *pwc;
1026 int i;
1028 hash ^= plfsz->devsize.cx;
1029 hash ^= plfsz->devsize.cy;
1030 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1031 hash ^= *ptr;
1032 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1033 hash ^= *ptr;
1034 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1035 two_chars = *ptr;
1036 pwc = (WCHAR *)&two_chars;
1037 if(!*pwc) break;
1038 *pwc = toupperW(*pwc);
1039 pwc++;
1040 *pwc = toupperW(*pwc);
1041 hash ^= two_chars;
1042 if(!*pwc) break;
1044 plfsz->hash = hash;
1045 return;
1048 /***********************************************************************
1049 * X11DRV_XRender_Finalize
1051 void X11DRV_XRender_Finalize(void)
1053 int i;
1055 EnterCriticalSection(&xrender_cs);
1056 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1057 FreeEntry(i);
1058 LeaveCriticalSection(&xrender_cs);
1059 DeleteCriticalSection(&xrender_cs);
1062 /**********************************************************************
1063 * xrenderdrv_SelectFont
1065 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1067 LFANDSIZE lfsz;
1068 struct xrender_physdev *physdev = get_xrender_dev( dev );
1069 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1070 HFONT ret = next->funcs->pSelectFont( next, hfont );
1072 if (!ret) return 0;
1074 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1076 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1077 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1078 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1079 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1080 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1081 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1083 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1084 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1085 lfsz.xform.eM21, lfsz.xform.eM22);
1087 if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE && lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
1088 lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
1090 /* Not used fields, would break hashing */
1091 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1093 lfsz_calc_hash(&lfsz);
1095 EnterCriticalSection(&xrender_cs);
1096 if (physdev->cache_index != -1)
1097 dec_ref_cache( physdev->cache_index );
1098 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1099 LeaveCriticalSection(&xrender_cs);
1100 return ret;
1103 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1105 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1106 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1108 if (!physdev) return FALSE;
1109 physdev->x11dev = x11dev;
1110 physdev->cache_index = -1;
1111 physdev->format = format;
1112 physdev->pict_format = pict_formats[format];
1113 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1114 return TRUE;
1117 /* store the color mask data in the bitmap info structure */
1118 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1120 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1122 info->bmiHeader.biPlanes = 1;
1123 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1124 info->bmiHeader.biCompression = BI_RGB;
1125 info->bmiHeader.biClrUsed = 0;
1127 switch (info->bmiHeader.biBitCount)
1129 case 16:
1130 colors[0] = format->direct.redMask << format->direct.red;
1131 colors[1] = format->direct.greenMask << format->direct.green;
1132 colors[2] = format->direct.blueMask << format->direct.blue;
1133 info->bmiHeader.biCompression = BI_BITFIELDS;
1134 break;
1135 case 32:
1136 colors[0] = format->direct.redMask << format->direct.red;
1137 colors[1] = format->direct.greenMask << format->direct.green;
1138 colors[2] = format->direct.blueMask << format->direct.blue;
1139 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1140 info->bmiHeader.biCompression = BI_BITFIELDS;
1141 break;
1146 /**********************************************************************
1147 * xrenderdrv_CreateDC
1149 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1150 LPCWSTR output, const DEVMODEW* initData )
1152 return create_xrender_dc( pdev, default_format );
1155 /**********************************************************************
1156 * xrenderdrv_CreateCompatibleDC
1158 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1160 if (orig) /* chain to x11drv first */
1162 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1163 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1165 /* otherwise we have been called by x11drv */
1167 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1170 /**********************************************************************
1171 * xrenderdrv_DeleteDC
1173 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1175 struct xrender_physdev *physdev = get_xrender_dev( dev );
1177 free_xrender_picture( physdev );
1179 EnterCriticalSection( &xrender_cs );
1180 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1181 LeaveCriticalSection( &xrender_cs );
1183 HeapFree( GetProcessHeap(), 0, physdev );
1184 return TRUE;
1187 /**********************************************************************
1188 * xrenderdrv_ExtEscape
1190 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1191 INT out_count, LPVOID out_data )
1193 struct xrender_physdev *physdev = get_xrender_dev( dev );
1195 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1197 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1199 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1201 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1202 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1203 return ret;
1206 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1209 /***********************************************************************
1210 * xrenderdrv_SetDeviceClipping
1212 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1214 struct xrender_physdev *physdev = get_xrender_dev( dev );
1216 physdev->region = rgn;
1217 physdev->update_clip = TRUE;
1219 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1220 dev->funcs->pSetDeviceClipping( dev, rgn );
1224 /************************************************************************
1225 * UploadGlyph
1227 * Helper to ExtTextOut. Must be called inside xrender_cs
1229 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1231 unsigned int buflen;
1232 char *buf;
1233 Glyph gid;
1234 GLYPHMETRICS gm;
1235 XGlyphInfo gi;
1236 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1237 gsCacheEntryFormat *formatEntry;
1238 UINT ggo_format = GGO_GLYPH_INDEX;
1239 enum wxr_format wxr_format;
1240 static const char zero[4];
1241 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1243 switch(format) {
1244 case AA_Grey:
1245 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1246 break;
1247 case AA_RGB:
1248 ggo_format |= WINE_GGO_HRGB_BITMAP;
1249 break;
1250 case AA_BGR:
1251 ggo_format |= WINE_GGO_HBGR_BITMAP;
1252 break;
1253 case AA_VRGB:
1254 ggo_format |= WINE_GGO_VRGB_BITMAP;
1255 break;
1256 case AA_VBGR:
1257 ggo_format |= WINE_GGO_VBGR_BITMAP;
1258 break;
1260 default:
1261 ERR("aa = %d - not implemented\n", format);
1262 case AA_None:
1263 ggo_format |= GGO_BITMAP;
1264 break;
1267 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1268 if(buflen == GDI_ERROR) {
1269 if(format != AA_None) {
1270 format = AA_None;
1271 entry->aa_default = AA_None;
1272 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1273 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1275 if(buflen == GDI_ERROR) {
1276 WARN("GetGlyphOutlineW failed using default glyph\n");
1277 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1278 if(buflen == GDI_ERROR) {
1279 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1280 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1281 if(buflen == GDI_ERROR) {
1282 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1283 return;
1287 TRACE("Turning off antialiasing for this monochrome font\n");
1290 /* If there is nothing for the current type, we create the entry. */
1291 if( !entry->format[format] ) {
1292 entry->format[format] = HeapAlloc(GetProcessHeap(),
1293 HEAP_ZERO_MEMORY,
1294 sizeof(gsCacheEntryFormat));
1296 formatEntry = entry->format[format];
1298 if(formatEntry->nrealized <= glyph) {
1299 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1301 if (formatEntry->realized)
1302 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1303 HEAP_ZERO_MEMORY,
1304 formatEntry->realized,
1305 formatEntry->nrealized * sizeof(BOOL));
1306 else
1307 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1308 HEAP_ZERO_MEMORY,
1309 formatEntry->nrealized * sizeof(BOOL));
1311 if (formatEntry->gis)
1312 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1313 HEAP_ZERO_MEMORY,
1314 formatEntry->gis,
1315 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1316 else
1317 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1318 HEAP_ZERO_MEMORY,
1319 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1323 if(formatEntry->glyphset == 0) {
1324 switch(format) {
1325 case AA_Grey:
1326 wxr_format = WXR_FORMAT_GRAY;
1327 break;
1329 case AA_RGB:
1330 case AA_BGR:
1331 case AA_VRGB:
1332 case AA_VBGR:
1333 wxr_format = WXR_FORMAT_A8R8G8B8;
1334 break;
1336 default:
1337 ERR("aa = %d - not implemented\n", format);
1338 case AA_None:
1339 wxr_format = WXR_FORMAT_MONO;
1340 break;
1343 formatEntry->font_format = pict_formats[wxr_format];
1344 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1348 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1349 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1350 formatEntry->realized[glyph] = TRUE;
1352 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1353 buflen,
1354 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1355 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1357 gi.width = gm.gmBlackBoxX;
1358 gi.height = gm.gmBlackBoxY;
1359 gi.x = -gm.gmptGlyphOrigin.x;
1360 gi.y = gm.gmptGlyphOrigin.y;
1361 gi.xOff = gm.gmCellIncX;
1362 gi.yOff = gm.gmCellIncY;
1364 if(TRACE_ON(xrender)) {
1365 int pitch, i, j;
1366 char output[300];
1367 unsigned char *line;
1369 if(format == AA_None) {
1370 pitch = ((gi.width + 31) / 32) * 4;
1371 for(i = 0; i < gi.height; i++) {
1372 line = (unsigned char*) buf + i * pitch;
1373 output[0] = '\0';
1374 for(j = 0; j < pitch * 8; j++) {
1375 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1377 TRACE("%s\n", output);
1379 } else {
1380 static const char blks[] = " .:;!o*#";
1381 char str[2];
1383 str[1] = '\0';
1384 pitch = ((gi.width + 3) / 4) * 4;
1385 for(i = 0; i < gi.height; i++) {
1386 line = (unsigned char*) buf + i * pitch;
1387 output[0] = '\0';
1388 for(j = 0; j < pitch; j++) {
1389 str[0] = blks[line[j] >> 5];
1390 strcat(output, str);
1392 TRACE("%s\n", output);
1398 if(formatEntry->glyphset) {
1399 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1400 unsigned char *byte = (unsigned char*) buf, c;
1401 int i = buflen;
1403 while(i--) {
1404 c = *byte;
1406 /* magic to flip bit order */
1407 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1408 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1409 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1411 *byte++ = c;
1414 else if ( format != AA_Grey &&
1415 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1417 unsigned int i, *data = (unsigned int *)buf;
1418 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1420 gid = glyph;
1423 XRenderCompositeText seems to ignore 0x0 glyphs when
1424 AA_None, which means we lose the advance width of glyphs
1425 like the space. We'll pretend that such glyphs are 1x1
1426 bitmaps.
1429 if(buflen == 0)
1430 gi.width = gi.height = 1;
1432 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1433 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1434 HeapFree(GetProcessHeap(), 0, buf);
1437 formatEntry->gis[glyph] = gi;
1440 /*************************************************************
1441 * get_tile_pict
1443 * Returns an appropriate Picture for tiling the text colour.
1444 * Call and use result within the xrender_cs
1446 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1448 static struct
1450 Pixmap xpm;
1451 Picture pict;
1452 XRenderColor current_color;
1453 } tiles[WXR_NB_FORMATS], *tile;
1455 tile = &tiles[wxr_format];
1457 if(!tile->xpm)
1459 XRenderPictureAttributes pa;
1460 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1462 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1464 pa.repeat = RepeatNormal;
1465 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1467 /* init current_color to something different from text_pixel */
1468 tile->current_color = *color;
1469 tile->current_color.red ^= 0xffff;
1471 if (wxr_format == WXR_FORMAT_MONO)
1473 /* for a 1bpp bitmap we always need a 1 in the tile */
1474 XRenderColor col;
1475 col.red = col.green = col.blue = 0;
1476 col.alpha = 0xffff;
1477 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1481 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1483 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1484 tile->current_color = *color;
1486 return tile->pict;
1489 /*************************************************************
1490 * get_mask_pict
1492 * Returns an appropriate Picture for masking with the specified alpha.
1493 * Call and use result within the xrender_cs
1495 static Picture get_mask_pict( int alpha )
1497 static Pixmap pixmap;
1498 static Picture pict;
1499 static int current_alpha;
1501 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1503 if (!pixmap)
1505 XRenderPictureAttributes pa;
1507 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1508 pa.repeat = RepeatNormal;
1509 pict = pXRenderCreatePicture( gdi_display, pixmap,
1510 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1511 current_alpha = -1;
1514 if (alpha != current_alpha)
1516 XRenderColor col;
1517 col.red = col.green = col.blue = 0;
1518 col.alpha = current_alpha = alpha;
1519 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1521 return pict;
1524 /***********************************************************************
1525 * xrenderdrv_ExtTextOut
1527 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1528 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1530 struct xrender_physdev *physdev = get_xrender_dev( dev );
1531 gsCacheEntry *entry;
1532 gsCacheEntryFormat *formatEntry;
1533 AA_Type aa_type = AA_None;
1534 unsigned int idx;
1535 Picture pict, tile_pict = 0;
1536 XGlyphElt16 *elts;
1537 POINT offset, desired, current;
1538 int render_op = PictOpOver;
1539 XRenderColor col;
1540 RECT rect, bounds;
1542 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1543 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1545 if(flags & ETO_OPAQUE)
1547 XRenderColor bg;
1549 if (physdev->format == WXR_FORMAT_MONO)
1550 /* use the inverse of the text color */
1551 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1552 else
1553 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1555 set_xrender_transformation( pict, 1, 1, 0, 0 );
1556 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1557 physdev->x11dev->dc_rect.left + lprect->left,
1558 physdev->x11dev->dc_rect.top + lprect->top,
1559 lprect->right - lprect->left,
1560 lprect->bottom - lprect->top );
1561 add_device_bounds( physdev->x11dev, lprect );
1564 if(count == 0) return TRUE;
1566 EnterCriticalSection(&xrender_cs);
1568 entry = glyphsetCache + physdev->cache_index;
1569 aa_type = entry->aa_default;
1570 formatEntry = entry->format[aa_type];
1572 for(idx = 0; idx < count; idx++) {
1573 if( !formatEntry ) {
1574 UploadGlyph(physdev, wstr[idx], aa_type);
1575 /* re-evaluate antialias since aa_default may have changed */
1576 aa_type = entry->aa_default;
1577 formatEntry = entry->format[aa_type];
1578 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1579 UploadGlyph(physdev, wstr[idx], aa_type);
1582 if (!formatEntry)
1584 WARN("could not upload requested glyphs\n");
1585 LeaveCriticalSection(&xrender_cs);
1586 return FALSE;
1589 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1590 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1592 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1594 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1595 So we pass zeros to the function and move to our starting position using the first
1596 element of the elts array. */
1598 desired.x = physdev->x11dev->dc_rect.left + x;
1599 desired.y = physdev->x11dev->dc_rect.top + y;
1600 offset.x = offset.y = 0;
1601 current.x = current.y = 0;
1603 tile_pict = get_tile_pict(physdev->format, &col);
1605 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1607 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1608 render_op = PictOpOutReverse; /* This gives us 'black' text */
1610 reset_bounds( &bounds );
1611 for(idx = 0; idx < count; idx++)
1613 elts[idx].glyphset = formatEntry->glyphset;
1614 elts[idx].chars = wstr + idx;
1615 elts[idx].nchars = 1;
1616 elts[idx].xOff = desired.x - current.x;
1617 elts[idx].yOff = desired.y - current.y;
1619 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1620 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1622 rect.left = desired.x - physdev->x11dev->dc_rect.left - formatEntry->gis[wstr[idx]].x;
1623 rect.top = desired.y - physdev->x11dev->dc_rect.top - formatEntry->gis[wstr[idx]].y;
1624 rect.right = rect.left + formatEntry->gis[wstr[idx]].width;
1625 rect.bottom = rect.top + formatEntry->gis[wstr[idx]].height;
1626 add_bounds_rect( &bounds, &rect );
1628 if(!lpDx)
1630 desired.x += formatEntry->gis[wstr[idx]].xOff;
1631 desired.y += formatEntry->gis[wstr[idx]].yOff;
1633 else
1635 if(flags & ETO_PDY)
1637 offset.x += lpDx[idx * 2];
1638 offset.y += lpDx[idx * 2 + 1];
1640 else
1641 offset.x += lpDx[idx];
1642 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1643 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1647 wine_tsx11_lock();
1648 /* Make sure we don't have any transforms set from a previous call */
1649 set_xrender_transformation(pict, 1, 1, 0, 0);
1650 pXRenderCompositeText16(gdi_display, render_op,
1651 tile_pict,
1652 pict,
1653 formatEntry->font_format,
1654 0, 0, 0, 0, elts, count);
1655 wine_tsx11_unlock();
1656 HeapFree(GetProcessHeap(), 0, elts);
1658 LeaveCriticalSection(&xrender_cs);
1659 add_device_bounds( physdev->x11dev, &bounds );
1660 return TRUE;
1663 /* multiply the alpha channel of a picture */
1664 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1665 int x, int y, int width, int height )
1667 XRenderPictureAttributes pa;
1668 Pixmap src_pixmap, mask_pixmap;
1669 Picture src_pict, mask_pict;
1670 XRenderColor color;
1672 wine_tsx11_lock();
1673 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1674 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1675 pa.repeat = RepeatNormal;
1676 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1677 pa.component_alpha = True;
1678 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1679 color.red = color.green = color.blue = color.alpha = 0xffff;
1680 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1681 color.alpha = alpha;
1682 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1683 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1684 0, 0, 0, 0, x, y, width, height );
1685 pXRenderFreePicture( gdi_display, src_pict );
1686 pXRenderFreePicture( gdi_display, mask_pict );
1687 XFreePixmap( gdi_display, src_pixmap );
1688 XFreePixmap( gdi_display, mask_pixmap );
1689 wine_tsx11_unlock();
1692 /* Helper function for (stretched) blitting using xrender */
1693 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1694 int x_src, int y_src, int width_src, int height_src,
1695 int x_dst, int y_dst, int width_dst, int height_dst,
1696 double xscale, double yscale )
1698 int x_offset, y_offset;
1700 if (width_src < 0)
1702 x_src += width_src + 1;
1703 width_src = -width_src;
1705 if (height_src < 0)
1707 y_src += height_src + 1;
1708 height_src = -height_src;
1710 if (width_dst < 0)
1712 x_dst += width_dst + 1;
1713 width_dst = -width_dst;
1715 if (height_dst < 0)
1717 y_dst += height_dst + 1;
1718 height_dst = -height_dst;
1721 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1722 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1723 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1724 wine_tsx11_lock();
1725 if(xscale != 1.0 || yscale != 1.0)
1727 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1728 * in the wrong quadrant of the x-y plane.
1730 x_offset = (xscale < 0) ? -width_dst : 0;
1731 y_offset = (yscale < 0) ? -height_dst : 0;
1732 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1734 else
1736 x_offset = x_src;
1737 y_offset = y_src;
1738 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1740 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1741 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1742 wine_tsx11_unlock();
1745 /* Helper function for (stretched) mono->color blitting using xrender */
1746 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1747 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1748 int x_src, int y_src, int width_src, int height_src,
1749 int x_dst, int y_dst, int width_dst, int height_dst,
1750 double xscale, double yscale )
1752 Picture tile_pict;
1753 int x_offset, y_offset;
1754 XRenderColor color;
1756 if (width_src < 0)
1758 x_src += width_src + 1;
1759 width_src = -width_src;
1761 if (height_src < 0)
1763 y_src += height_src + 1;
1764 height_src = -height_src;
1766 if (width_dst < 0)
1768 x_dst += width_dst + 1;
1769 width_dst = -width_dst;
1771 if (height_dst < 0)
1773 y_dst += height_dst + 1;
1774 height_dst = -height_dst;
1777 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1778 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1779 * the tile data.
1781 EnterCriticalSection( &xrender_cs );
1782 color = *bg;
1783 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1784 tile_pict = get_tile_pict( dst_format, &color );
1786 wine_tsx11_lock();
1787 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1789 if (xscale != 1.0 || yscale != 1.0)
1791 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1792 * in the wrong quadrant of the x-y plane.
1794 x_offset = (xscale < 0) ? -width_dst : 0;
1795 y_offset = (yscale < 0) ? -height_dst : 0;
1796 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1798 else
1800 x_offset = x_src;
1801 y_offset = y_src;
1802 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1804 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1805 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1806 wine_tsx11_unlock();
1807 LeaveCriticalSection( &xrender_cs );
1809 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1810 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1811 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1812 x_dst, y_dst, width_dst, height_dst );
1815 /* create a pixmap and render picture for an image */
1816 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1817 struct bitblt_coords *src, enum wxr_format format,
1818 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1820 DWORD ret;
1821 int width = src->visrect.right - src->visrect.left;
1822 int height = src->visrect.bottom - src->visrect.top;
1823 int depth = pict_formats[format]->depth;
1824 struct gdi_image_bits dst_bits;
1825 XRenderPictureAttributes pa;
1826 GC gc;
1827 XImage *image;
1829 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1830 info->bmiHeader.biWidth, height, 32, 0 );
1831 if (!image) return ERROR_OUTOFMEMORY;
1833 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1834 if (ret) return ret;
1836 image->data = dst_bits.ptr;
1838 *use_repeat = (width == 1 && height == 1);
1839 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1841 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1842 gc = XCreateGC( gdi_display, *pixmap, 0, NULL );
1843 XPutImage( gdi_display, *pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1844 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1845 XFreeGC( gdi_display, gc );
1847 /* make coordinates relative to the pixmap */
1848 src->x -= src->visrect.left;
1849 src->y -= src->visrect.top;
1850 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1852 image->data = NULL;
1853 XDestroyImage( image );
1854 if (dst_bits.free) dst_bits.free( &dst_bits );
1855 return ret;
1858 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1859 Drawable drawable, const struct bitblt_coords *src,
1860 const struct bitblt_coords *dst )
1862 int x_dst, y_dst;
1863 Picture src_pict = 0, dst_pict, mask_pict = 0;
1864 double xscale = src->width / (double)dst->width;
1865 double yscale = src->height / (double)dst->height;
1867 if (drawable) /* using an intermediate pixmap */
1869 x_dst = dst->x;
1870 y_dst = dst->y;
1871 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, 0, NULL );
1873 else
1875 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
1876 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
1877 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1880 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1882 /* mono -> color */
1883 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1885 XRenderColor fg, bg;
1887 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
1888 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
1889 fg.alpha = bg.alpha = 0;
1891 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
1892 physdev_src->x11dev->dc_rect.left + src->x,
1893 physdev_src->x11dev->dc_rect.top + src->y,
1894 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1896 else /* color -> color (can be at different depths) or mono -> mono */
1898 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
1899 mask_pict = get_no_alpha_mask();
1901 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
1902 physdev_src->x11dev->dc_rect.left + src->x,
1903 physdev_src->x11dev->dc_rect.top + src->y,
1904 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1907 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1911 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
1912 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
1913 Drawable drawable, struct bitblt_coords *src,
1914 struct bitblt_coords *dst, BOOL use_repeat )
1916 int x_dst, y_dst;
1917 Picture dst_pict;
1918 double xscale, yscale;
1920 if (drawable) /* using an intermediate pixmap */
1922 RGNDATA *clip_data = NULL;
1924 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1925 x_dst = dst->x;
1926 y_dst = dst->y;
1927 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL );
1928 if (clip_data)
1929 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
1930 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
1931 HeapFree( GetProcessHeap(), 0, clip_data );
1933 else
1935 x_dst = physdev->x11dev->dc_rect.left + dst->x;
1936 y_dst = physdev->x11dev->dc_rect.top + dst->y;
1937 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
1940 if (!use_repeat)
1942 xscale = src->width / (double)dst->width;
1943 yscale = src->height / (double)dst->height;
1945 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1947 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
1948 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1950 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1954 /***********************************************************************
1955 * xrenderdrv_StretchBlt
1957 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1958 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1960 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1961 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1962 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
1964 if (src_dev->funcs != dst_dev->funcs)
1966 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
1967 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
1970 /* XRender is of no use for color -> mono */
1971 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
1972 goto x11drv_fallback;
1974 /* if not stretching, we only need to handle format conversion */
1975 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
1977 if (rop != SRCCOPY)
1979 GC tmpGC;
1980 Pixmap tmp_pixmap;
1981 struct bitblt_coords tmp;
1983 /* make coordinates relative to tmp pixmap */
1984 tmp = *dst;
1985 tmp.x -= tmp.visrect.left;
1986 tmp.y -= tmp.visrect.top;
1987 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1989 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
1990 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1991 XSetGraphicsExposures( gdi_display, tmpGC, False );
1992 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
1993 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
1995 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
1996 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
1998 XFreePixmap( gdi_display, tmp_pixmap );
1999 XFreeGC( gdi_display, tmpGC );
2001 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2003 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2004 return TRUE;
2006 x11drv_fallback:
2007 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2011 /***********************************************************************
2012 * xrenderdrv_PutImage
2014 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
2015 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2016 struct bitblt_coords *dst, DWORD rop )
2018 struct xrender_physdev *physdev = get_xrender_dev( dev );
2019 DWORD ret;
2020 Pixmap tmp_pixmap;
2021 GC gc;
2022 enum wxr_format src_format, dst_format;
2023 XRenderPictFormat *pict_format;
2024 Pixmap src_pixmap;
2025 Picture src_pict, mask_pict = 0;
2026 BOOL use_repeat;
2028 dst_format = physdev->format;
2029 src_format = get_xrender_format_from_bitmapinfo( info );
2030 if (!(pict_format = pict_formats[src_format])) goto update_format;
2032 /* make sure we can create an image with the same bpp */
2033 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2034 goto update_format;
2036 /* mono <-> color conversions not supported */
2037 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2038 goto x11drv_fallback;
2040 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2042 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2044 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2045 if (!ret)
2047 struct bitblt_coords tmp;
2049 if (rop != SRCCOPY)
2051 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2053 /* make coordinates relative to tmp pixmap */
2054 tmp = *dst;
2055 tmp.x -= tmp.visrect.left;
2056 tmp.y -= tmp.visrect.top;
2057 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2059 wine_tsx11_lock();
2060 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2061 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2062 XSetGraphicsExposures( gdi_display, gc, False );
2063 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2064 tmp.visrect.right - tmp.visrect.left,
2065 tmp.visrect.bottom - tmp.visrect.top,
2066 physdev->pict_format->depth );
2067 wine_tsx11_unlock();
2069 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2070 NULL, tmp_pixmap, src, &tmp, use_repeat );
2071 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2073 XFreePixmap( gdi_display, tmp_pixmap );
2074 XFreeGC( gdi_display, gc );
2075 if (restore_region) restore_clipping_region( physdev->x11dev );
2077 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2078 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2080 add_device_bounds( physdev->x11dev, &dst->visrect );
2082 pXRenderFreePicture( gdi_display, src_pict );
2083 XFreePixmap( gdi_display, src_pixmap );
2085 return ret;
2087 update_format:
2088 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2089 set_color_info( pict_formats[dst_format], info );
2090 return ERROR_BAD_FORMAT;
2092 x11drv_fallback:
2093 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2094 return dev->funcs->pPutImage( dev, clip, info, bits, src, dst, rop );
2098 /***********************************************************************
2099 * xrenderdrv_BlendImage
2101 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2102 struct bitblt_coords *src, struct bitblt_coords *dst,
2103 BLENDFUNCTION func )
2105 struct xrender_physdev *physdev = get_xrender_dev( dev );
2106 DWORD ret;
2107 enum wxr_format format;
2108 XRenderPictFormat *pict_format;
2109 Picture dst_pict, src_pict, mask_pict;
2110 Pixmap src_pixmap;
2111 BOOL use_repeat;
2113 format = get_xrender_format_from_bitmapinfo( info );
2114 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2115 format = get_format_without_alpha( format );
2116 else if (format != WXR_FORMAT_A8R8G8B8)
2117 return ERROR_INVALID_PARAMETER;
2119 if (!(pict_format = pict_formats[format])) goto update_format;
2121 /* make sure we can create an image with the same bpp */
2122 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2123 goto update_format;
2125 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2126 goto update_format;
2128 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2130 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2131 if (!ret)
2133 double xscale, yscale;
2135 if (!use_repeat)
2137 xscale = src->width / (double)dst->width;
2138 yscale = src->height / (double)dst->height;
2140 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2142 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2144 EnterCriticalSection( &xrender_cs );
2145 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2147 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2148 src->x, src->y, src->width, src->height,
2149 physdev->x11dev->dc_rect.left + dst->x,
2150 physdev->x11dev->dc_rect.top + dst->y,
2151 dst->width, dst->height, xscale, yscale );
2153 pXRenderFreePicture( gdi_display, src_pict );
2154 XFreePixmap( gdi_display, src_pixmap );
2156 LeaveCriticalSection( &xrender_cs );
2157 add_device_bounds( physdev->x11dev, &dst->visrect );
2159 return ret;
2161 update_format:
2162 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2163 set_color_info( physdev->pict_format, info );
2164 return ERROR_BAD_FORMAT;
2168 /***********************************************************************
2169 * xrenderdrv_AlphaBlend
2171 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2172 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2174 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2175 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2176 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2177 XRenderPictureAttributes pa;
2178 Pixmap tmp_pixmap = 0;
2179 double xscale, yscale;
2181 if (src_dev->funcs != dst_dev->funcs)
2183 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2184 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2187 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2189 SetLastError( ERROR_INVALID_PARAMETER );
2190 return FALSE;
2193 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2195 xscale = src->width / (double)dst->width;
2196 yscale = src->height / (double)dst->height;
2198 src_pict = get_xrender_picture_source( physdev_src, FALSE );
2200 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2202 /* mono -> color blending needs an intermediate color pixmap */
2203 XRenderColor fg, bg;
2204 int width = src->visrect.right - src->visrect.left;
2205 int height = src->visrect.bottom - src->visrect.top;
2207 /* blending doesn't use the destination DC colors */
2208 fg.red = fg.green = fg.blue = 0;
2209 bg.red = bg.green = bg.blue = 0xffff;
2210 fg.alpha = bg.alpha = 0xffff;
2212 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2213 physdev_dst->pict_format->depth );
2214 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format, 0, NULL );
2216 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2217 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
2219 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2221 /* we need a source picture with no alpha */
2222 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2223 if (format != physdev_src->format)
2225 pa.subwindow_mode = IncludeInferiors;
2226 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2227 pict_formats[format], CPSubwindowMode, &pa );
2231 if (tmp_pict) src_pict = tmp_pict;
2233 EnterCriticalSection( &xrender_cs );
2234 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2236 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2237 physdev_src->x11dev->dc_rect.left + src->x,
2238 physdev_src->x11dev->dc_rect.top + src->y,
2239 src->width, src->height,
2240 physdev_dst->x11dev->dc_rect.left + dst->x,
2241 physdev_dst->x11dev->dc_rect.top + dst->y,
2242 dst->width, dst->height, xscale, yscale );
2244 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2245 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2247 LeaveCriticalSection( &xrender_cs );
2248 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2249 return TRUE;
2252 /***********************************************************************
2253 * xrenderdrv_GradientFill
2255 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2256 void * grad_array, ULONG ngrad, ULONG mode )
2258 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2259 static const XFixed stops[2] = { 0, 1 << 16 };
2260 struct xrender_physdev *physdev = get_xrender_dev( dev );
2261 XLinearGradient gradient;
2262 XRenderColor colors[2];
2263 Picture src_pict, dst_pict;
2264 unsigned int i;
2265 const GRADIENT_RECT *rect = grad_array;
2266 RECT rc;
2267 POINT pt[2];
2269 if (!pXRenderCreateLinearGradient) goto fallback;
2271 /* <= 16-bpp uses dithering */
2272 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2274 switch (mode)
2276 case GRADIENT_FILL_RECT_H:
2277 case GRADIENT_FILL_RECT_V:
2278 for (i = 0; i < ngrad; i++, rect++)
2280 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2281 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2283 colors[0].red = v1->Red * 257 / 256;
2284 colors[0].green = v1->Green * 257 / 256;
2285 colors[0].blue = v1->Blue * 257 / 256;
2286 colors[1].red = v2->Red * 257 / 256;
2287 colors[1].green = v2->Green * 257 / 256;
2288 colors[1].blue = v2->Blue * 257 / 256;
2289 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2290 colors[0].alpha = colors[1].alpha = 65535;
2292 pt[0].x = v1->x;
2293 pt[0].y = v1->y;
2294 pt[1].x = v2->x;
2295 pt[1].y = v2->y;
2296 LPtoDP( dev->hdc, pt, 2 );
2297 if (mode == GRADIENT_FILL_RECT_H)
2299 gradient.p1.y = gradient.p2.y = 0;
2300 if (pt[1].x > pt[0].x)
2302 gradient.p1.x = 0;
2303 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2305 else
2307 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2308 gradient.p2.x = 0;
2311 else
2313 gradient.p1.x = gradient.p2.x = 0;
2314 if (pt[1].y > pt[0].y)
2316 gradient.p1.y = 0;
2317 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2319 else
2321 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2322 gradient.p2.y = 0;
2326 rc.left = min( pt[0].x, pt[1].x );
2327 rc.top = min( pt[0].y, pt[1].y );
2328 rc.right = max( pt[0].x, pt[1].x );
2329 rc.bottom = max( pt[0].y, pt[1].y );
2331 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2332 mode, wine_dbgstr_rect( &rc ),
2333 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2334 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2336 dst_pict = get_xrender_picture( physdev, 0, NULL );
2338 wine_tsx11_lock();
2339 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2340 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2341 0, 0, rc.right - rc.left, rc.bottom - rc.top,
2342 physdev->x11dev->dc_rect.left + rc.left,
2343 physdev->x11dev->dc_rect.top + rc.top,
2344 rc.right - rc.left, rc.bottom - rc.top, 1, 1 );
2345 pXRenderFreePicture( gdi_display, src_pict );
2346 wine_tsx11_unlock();
2347 add_device_bounds( physdev->x11dev, &rc );
2349 return TRUE;
2352 fallback:
2353 #endif
2354 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2355 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2358 /***********************************************************************
2359 * xrenderdrv_SelectBrush
2361 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2363 struct xrender_physdev *physdev = get_xrender_dev( dev );
2364 Pixmap pixmap;
2365 XVisualInfo vis;
2366 XRenderPictFormat *format = physdev->pict_format;
2368 if (!pattern) goto x11drv_fallback;
2369 if (pattern->info->bmiHeader.biBitCount == 1) goto x11drv_fallback;
2370 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2372 memset( &vis, 0, sizeof(vis) );
2373 vis.depth = format->depth;
2374 vis.red_mask = format->direct.redMask << format->direct.red;
2375 vis.green_mask = format->direct.greenMask << format->direct.green;
2376 vis.blue_mask = format->direct.blueMask << format->direct.blue;
2378 pixmap = create_pixmap_from_image( physdev->dev.hdc, &vis, pattern->info,
2379 &pattern->bits, pattern->usage );
2380 if (!pixmap) return 0;
2382 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2383 physdev->x11dev->brush.pixmap = pixmap;
2384 physdev->x11dev->brush.fillStyle = FillTiled;
2385 physdev->x11dev->brush.pixel = 0; /* ignored */
2386 physdev->x11dev->brush.style = BS_PATTERN;
2387 return hbrush;
2389 x11drv_fallback:
2390 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2391 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2395 static const struct gdi_dc_funcs xrender_funcs =
2397 NULL, /* pAbortDoc */
2398 NULL, /* pAbortPath */
2399 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2400 NULL, /* pAngleArc */
2401 NULL, /* pArc */
2402 NULL, /* pArcTo */
2403 NULL, /* pBeginPath */
2404 xrenderdrv_BlendImage, /* pBlendImage */
2405 NULL, /* pChord */
2406 NULL, /* pCloseFigure */
2407 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2408 xrenderdrv_CreateDC, /* pCreateDC */
2409 xrenderdrv_DeleteDC, /* pDeleteDC */
2410 NULL, /* pDeleteObject */
2411 NULL, /* pDeviceCapabilities */
2412 NULL, /* pEllipse */
2413 NULL, /* pEndDoc */
2414 NULL, /* pEndPage */
2415 NULL, /* pEndPath */
2416 NULL, /* pEnumFonts */
2417 NULL, /* pEnumICMProfiles */
2418 NULL, /* pExcludeClipRect */
2419 NULL, /* pExtDeviceMode */
2420 xrenderdrv_ExtEscape, /* pExtEscape */
2421 NULL, /* pExtFloodFill */
2422 NULL, /* pExtSelectClipRgn */
2423 xrenderdrv_ExtTextOut, /* pExtTextOut */
2424 NULL, /* pFillPath */
2425 NULL, /* pFillRgn */
2426 NULL, /* pFlattenPath */
2427 NULL, /* pFontIsLinked */
2428 NULL, /* pFrameRgn */
2429 NULL, /* pGdiComment */
2430 NULL, /* pGdiRealizationInfo */
2431 NULL, /* pGetBoundsRect */
2432 NULL, /* pGetCharABCWidths */
2433 NULL, /* pGetCharABCWidthsI */
2434 NULL, /* pGetCharWidth */
2435 NULL, /* pGetDeviceCaps */
2436 NULL, /* pGetDeviceGammaRamp */
2437 NULL, /* pGetFontData */
2438 NULL, /* pGetFontUnicodeRanges */
2439 NULL, /* pGetGlyphIndices */
2440 NULL, /* pGetGlyphOutline */
2441 NULL, /* pGetICMProfile */
2442 NULL, /* pGetImage */
2443 NULL, /* pGetKerningPairs */
2444 NULL, /* pGetNearestColor */
2445 NULL, /* pGetOutlineTextMetrics */
2446 NULL, /* pGetPixel */
2447 NULL, /* pGetSystemPaletteEntries */
2448 NULL, /* pGetTextCharsetInfo */
2449 NULL, /* pGetTextExtentExPoint */
2450 NULL, /* pGetTextExtentExPointI */
2451 NULL, /* pGetTextFace */
2452 NULL, /* pGetTextMetrics */
2453 xrenderdrv_GradientFill, /* pGradientFill */
2454 NULL, /* pIntersectClipRect */
2455 NULL, /* pInvertRgn */
2456 NULL, /* pLineTo */
2457 NULL, /* pModifyWorldTransform */
2458 NULL, /* pMoveTo */
2459 NULL, /* pOffsetClipRgn */
2460 NULL, /* pOffsetViewportOrg */
2461 NULL, /* pOffsetWindowOrg */
2462 NULL, /* pPaintRgn */
2463 NULL, /* pPatBlt */
2464 NULL, /* pPie */
2465 NULL, /* pPolyBezier */
2466 NULL, /* pPolyBezierTo */
2467 NULL, /* pPolyDraw */
2468 NULL, /* pPolyPolygon */
2469 NULL, /* pPolyPolyline */
2470 NULL, /* pPolygon */
2471 NULL, /* pPolyline */
2472 NULL, /* pPolylineTo */
2473 xrenderdrv_PutImage, /* pPutImage */
2474 NULL, /* pRealizeDefaultPalette */
2475 NULL, /* pRealizePalette */
2476 NULL, /* pRectangle */
2477 NULL, /* pResetDC */
2478 NULL, /* pRestoreDC */
2479 NULL, /* pRoundRect */
2480 NULL, /* pSaveDC */
2481 NULL, /* pScaleViewportExt */
2482 NULL, /* pScaleWindowExt */
2483 NULL, /* pSelectBitmap */
2484 xrenderdrv_SelectBrush, /* pSelectBrush */
2485 NULL, /* pSelectClipPath */
2486 xrenderdrv_SelectFont, /* pSelectFont */
2487 NULL, /* pSelectPalette */
2488 NULL, /* pSelectPen */
2489 NULL, /* pSetArcDirection */
2490 NULL, /* pSetBkColor */
2491 NULL, /* pSetBkMode */
2492 NULL, /* pSetBoundsRect */
2493 NULL, /* pSetDCBrushColor */
2494 NULL, /* pSetDCPenColor */
2495 NULL, /* pSetDIBitsToDevice */
2496 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2497 NULL, /* pSetDeviceGammaRamp */
2498 NULL, /* pSetLayout */
2499 NULL, /* pSetMapMode */
2500 NULL, /* pSetMapperFlags */
2501 NULL, /* pSetPixel */
2502 NULL, /* pSetPolyFillMode */
2503 NULL, /* pSetROP2 */
2504 NULL, /* pSetRelAbs */
2505 NULL, /* pSetStretchBltMode */
2506 NULL, /* pSetTextAlign */
2507 NULL, /* pSetTextCharacterExtra */
2508 NULL, /* pSetTextColor */
2509 NULL, /* pSetTextJustification */
2510 NULL, /* pSetViewportExt */
2511 NULL, /* pSetViewportOrg */
2512 NULL, /* pSetWindowExt */
2513 NULL, /* pSetWindowOrg */
2514 NULL, /* pSetWorldTransform */
2515 NULL, /* pStartDoc */
2516 NULL, /* pStartPage */
2517 xrenderdrv_StretchBlt, /* pStretchBlt */
2518 NULL, /* pStretchDIBits */
2519 NULL, /* pStrokeAndFillPath */
2520 NULL, /* pStrokePath */
2521 NULL, /* pSwapBuffers */
2522 NULL, /* pUnrealizePalette */
2523 NULL, /* pWidenPath */
2524 NULL, /* wine_get_wgl_driver */
2525 GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
2528 #else /* SONAME_LIBXRENDER */
2530 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2532 TRACE("XRender support not compiled in.\n");
2533 return NULL;
2536 void X11DRV_XRender_Finalize(void)
2540 #endif /* SONAME_LIBXRENDER */