comctl32: Invalidate before item is removed.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blobca76770e516db5596775fa9b9a955119d85717e8
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 WINE_DECLARE_DEBUG_CHANNEL(winediag);
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 XGlyphInfo *gis;
146 } gsCacheEntryFormat;
148 typedef struct
150 LFANDSIZE lfsz;
151 AA_Type aa_default;
152 gsCacheEntryFormat * format[AA_MAXVALUE];
153 INT count;
154 INT next;
155 } gsCacheEntry;
157 struct xrender_physdev
159 struct gdi_physdev dev;
160 X11DRV_PDEVICE *x11dev;
161 HRGN region;
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(XRenderChangePicture)
191 MAKE_FUNCPTR(XRenderComposite)
192 MAKE_FUNCPTR(XRenderCompositeText16)
193 MAKE_FUNCPTR(XRenderCreateGlyphSet)
194 MAKE_FUNCPTR(XRenderCreatePicture)
195 MAKE_FUNCPTR(XRenderFillRectangle)
196 MAKE_FUNCPTR(XRenderFindFormat)
197 MAKE_FUNCPTR(XRenderFindVisualFormat)
198 MAKE_FUNCPTR(XRenderFreeGlyphSet)
199 MAKE_FUNCPTR(XRenderFreePicture)
200 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
201 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
202 MAKE_FUNCPTR(XRenderCreateLinearGradient)
203 #endif
204 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
205 MAKE_FUNCPTR(XRenderSetPictureTransform)
206 #endif
207 MAKE_FUNCPTR(XRenderQueryExtension)
209 #ifdef SONAME_LIBFONTCONFIG
210 #include <fontconfig/fontconfig.h>
211 MAKE_FUNCPTR(FcConfigSubstitute)
212 MAKE_FUNCPTR(FcDefaultSubstitute)
213 MAKE_FUNCPTR(FcFontMatch)
214 MAKE_FUNCPTR(FcInit)
215 MAKE_FUNCPTR(FcPatternCreate)
216 MAKE_FUNCPTR(FcPatternDestroy)
217 MAKE_FUNCPTR(FcPatternAddInteger)
218 MAKE_FUNCPTR(FcPatternAddString)
219 MAKE_FUNCPTR(FcPatternGetBool)
220 MAKE_FUNCPTR(FcPatternGetInteger)
221 MAKE_FUNCPTR(FcPatternGetString)
222 static void *fontconfig_handle;
223 static BOOL fontconfig_installed;
224 #endif
226 #undef MAKE_FUNCPTR
228 static CRITICAL_SECTION xrender_cs;
229 static CRITICAL_SECTION_DEBUG critsect_debug =
231 0, 0, &xrender_cs,
232 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
233 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
235 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
237 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
238 ( ( (ULONG)_x4 << 24 ) | \
239 ( (ULONG)_x3 << 16 ) | \
240 ( (ULONG)_x2 << 8 ) | \
241 (ULONG)_x1 )
243 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
245 #define GASP_GRIDFIT 0x01
246 #define GASP_DOGRAY 0x02
248 #ifdef WORDS_BIGENDIAN
249 #define get_be_word(x) (x)
250 #define NATIVE_BYTE_ORDER MSBFirst
251 #else
252 #define get_be_word(x) RtlUshortByteSwap(x)
253 #define NATIVE_BYTE_ORDER LSBFirst
254 #endif
256 static BOOL has_alpha( enum wxr_format format )
258 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
261 static enum wxr_format get_format_without_alpha( enum wxr_format format )
263 switch (format)
265 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
266 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
267 default: return format;
271 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
273 templ->id = 0;
274 templ->type = PictTypeDirect;
275 templ->depth = fmt->depth;
276 templ->direct.alpha = fmt->alpha;
277 templ->direct.alphaMask = fmt->alphaMask;
278 templ->direct.red = fmt->red;
279 templ->direct.redMask = fmt->redMask;
280 templ->direct.green = fmt->green;
281 templ->direct.greenMask = fmt->greenMask;
282 templ->direct.blue = fmt->blue;
283 templ->direct.blueMask = fmt->blueMask;
284 templ->colormap = 0;
286 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
288 return TRUE;
291 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
293 if(fmt->depth != screen_depth)
294 return FALSE;
295 if( (fmt->redMask << fmt->red) != visual->red_mask)
296 return FALSE;
297 if( (fmt->greenMask << fmt->green) != visual->green_mask)
298 return FALSE;
299 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
300 return FALSE;
302 /* We never select a default ARGB visual */
303 if(fmt->alphaMask)
304 return FALSE;
306 return TRUE;
309 static int load_xrender_formats(void)
311 int count = 0;
312 unsigned int i;
314 for (i = 0; i < WXR_NB_FORMATS; i++)
316 XRenderPictFormat templ;
318 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
320 wine_tsx11_lock();
321 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
322 if (!pict_formats[i])
324 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
325 if (visual->class == DirectColor)
327 XVisualInfo info;
328 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
329 screen_depth, TrueColor, &info ))
331 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
332 if (pict_formats[i]) visual = info.visual;
336 wine_tsx11_unlock();
337 if (pict_formats[i]) default_format = i;
339 else
341 unsigned long mask = 0;
342 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
344 wine_tsx11_lock();
345 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
346 wine_tsx11_unlock();
348 if (pict_formats[i])
350 count++;
351 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
354 return count;
357 /***********************************************************************
358 * X11DRV_XRender_Init
360 * Let's see if our XServer has the extension available
363 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
365 int event_base, i;
366 BOOL ok;
368 using_client_side_fonts = client_side_with_render || client_side_with_core;
370 if (!client_side_with_render) return NULL;
371 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
373 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
374 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
375 LOAD_FUNCPTR(XRenderAddGlyphs);
376 LOAD_FUNCPTR(XRenderChangePicture);
377 LOAD_FUNCPTR(XRenderComposite);
378 LOAD_FUNCPTR(XRenderCompositeText16);
379 LOAD_FUNCPTR(XRenderCreateGlyphSet);
380 LOAD_FUNCPTR(XRenderCreatePicture);
381 LOAD_FUNCPTR(XRenderFillRectangle);
382 LOAD_FUNCPTR(XRenderFindFormat);
383 LOAD_FUNCPTR(XRenderFindVisualFormat);
384 LOAD_FUNCPTR(XRenderFreeGlyphSet);
385 LOAD_FUNCPTR(XRenderFreePicture);
386 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
387 LOAD_FUNCPTR(XRenderQueryExtension);
388 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
389 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
390 #endif
391 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
392 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
393 #endif
394 #undef LOAD_OPTIONAL_FUNCPTR
395 #undef LOAD_FUNCPTR
397 wine_tsx11_lock();
398 ok = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
399 wine_tsx11_unlock();
400 if (!ok) return NULL;
402 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
403 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
405 ERR_(winediag)("Wine has detected that you probably have a buggy version "
406 "of libXrender. Because of this client side font rendering "
407 "will be disabled. Please upgrade this library.\n");
408 return NULL;
411 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask)
413 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
414 return NULL;
417 #ifdef SONAME_LIBFONTCONFIG
418 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
420 #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;}
421 LOAD_FUNCPTR(FcConfigSubstitute);
422 LOAD_FUNCPTR(FcDefaultSubstitute);
423 LOAD_FUNCPTR(FcFontMatch);
424 LOAD_FUNCPTR(FcInit);
425 LOAD_FUNCPTR(FcPatternCreate);
426 LOAD_FUNCPTR(FcPatternDestroy);
427 LOAD_FUNCPTR(FcPatternAddInteger);
428 LOAD_FUNCPTR(FcPatternAddString);
429 LOAD_FUNCPTR(FcPatternGetBool);
430 LOAD_FUNCPTR(FcPatternGetInteger);
431 LOAD_FUNCPTR(FcPatternGetString);
432 #undef LOAD_FUNCPTR
433 fontconfig_installed = pFcInit();
435 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
437 sym_not_found:
438 #endif
440 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
441 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
443 glyphsetCacheSize = INIT_CACHE_SIZE;
444 lastfree = 0;
445 for(i = 0; i < INIT_CACHE_SIZE; i++) {
446 glyphsetCache[i].next = i + 1;
447 glyphsetCache[i].count = -1;
449 glyphsetCache[i-1].next = -1;
451 if(screen_depth <= 8 || !client_side_antialias_with_render) antialias = 0;
453 return &xrender_funcs;
456 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
457 static void get_xrender_color( struct xrender_physdev *physdev, COLORREF src_color, XRenderColor *dst_color )
459 if (src_color & (1 << 24)) /* PALETTEINDEX */
461 HPALETTE pal = GetCurrentObject( physdev->dev.hdc, OBJ_PAL );
462 PALETTEENTRY pal_ent;
464 if (!GetPaletteEntries( pal, LOWORD(src_color), 1, &pal_ent ))
465 GetPaletteEntries( pal, 0, 1, &pal_ent );
466 dst_color->red = pal_ent.peRed * 257;
467 dst_color->green = pal_ent.peGreen * 257;
468 dst_color->blue = pal_ent.peBlue * 257;
470 else
472 if (src_color >> 16 == 0x10ff) src_color = 0; /* DIBINDEX */
474 dst_color->red = GetRValue( src_color ) * 257;
475 dst_color->green = GetGValue( src_color ) * 257;
476 dst_color->blue = GetBValue( src_color ) * 257;
479 if (physdev->format == WXR_FORMAT_MONO && !dst_color->red && !dst_color->green && !dst_color->blue)
480 dst_color->alpha = 0;
481 else
482 dst_color->alpha = 0xffff;
485 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
487 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
489 switch (info->bmiHeader.biBitCount)
491 case 1:
492 return WXR_FORMAT_MONO;
493 case 4:
494 case 8:
495 break;
496 case 24:
497 if (info->bmiHeader.biCompression != BI_RGB) break;
498 return WXR_FORMAT_R8G8B8;
499 case 16:
500 case 32:
501 if (info->bmiHeader.biCompression == BI_BITFIELDS)
503 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
504 unsigned int i;
506 for (i = 0; i < WXR_NB_FORMATS; i++)
508 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
509 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
510 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
511 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
512 return i;
514 break;
516 if (info->bmiHeader.biCompression != BI_RGB) break;
517 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
519 return WXR_INVALID_FORMAT;
522 static enum wxr_format get_bitmap_format( int bpp )
524 enum wxr_format format = WXR_INVALID_FORMAT;
526 if (bpp == screen_bpp)
528 switch (bpp)
530 case 16: format = WXR_FORMAT_R5G6B5; break;
531 case 24: format = WXR_FORMAT_R8G8B8; break;
532 case 32: format = WXR_FORMAT_A8R8G8B8; break;
535 return format;
538 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
539 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
541 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
542 XTransform xform = {{
543 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
544 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
545 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
548 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
549 #endif
552 /* check if we can use repeating instead of scaling for the specified source DC */
553 static BOOL use_source_repeat( struct xrender_physdev *dev )
555 return (dev->x11dev->bitmap &&
556 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
557 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
560 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
562 XRenderPictureAttributes pa;
563 RGNDATA *data;
565 if (!rgn)
567 wine_tsx11_lock();
568 pa.clip_mask = None;
569 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
570 wine_tsx11_unlock();
572 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
574 wine_tsx11_lock();
575 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
576 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
577 (XRectangle *)data->Buffer, data->rdh.nCount );
578 wine_tsx11_unlock();
579 HeapFree( GetProcessHeap(), 0, data );
584 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
586 if (!dev->pict && dev->pict_format)
588 XRenderPictureAttributes pa;
590 wine_tsx11_lock();
591 pa.subwindow_mode = IncludeInferiors;
592 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
593 dev->pict_format, CPSubwindowMode, &pa );
594 wine_tsx11_unlock();
595 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
596 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
597 dev->update_clip = (dev->region != 0);
600 if (clip_rect)
602 HRGN rgn = CreateRectRgnIndirect( clip_rect );
603 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
604 if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
605 update_xrender_clipping( dev, rgn );
606 DeleteObject( rgn );
608 else if (clip_rgn)
610 if (dev->region)
612 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
613 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
614 update_xrender_clipping( dev, rgn );
615 DeleteObject( rgn );
617 else update_xrender_clipping( dev, clip_rgn );
619 else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
621 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
622 return dev->pict;
625 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
627 if (!dev->pict_src && dev->pict_format)
629 XRenderPictureAttributes pa;
631 wine_tsx11_lock();
632 pa.subwindow_mode = IncludeInferiors;
633 pa.repeat = repeat ? RepeatNormal : RepeatNone;
634 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
635 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
636 wine_tsx11_unlock();
638 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
639 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
642 return dev->pict_src;
645 static void free_xrender_picture( struct xrender_physdev *dev )
647 if (dev->pict || dev->pict_src)
649 wine_tsx11_lock();
650 XFlush( gdi_display );
651 if (dev->pict)
653 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
654 pXRenderFreePicture(gdi_display, dev->pict);
655 dev->pict = 0;
657 if(dev->pict_src)
659 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
660 pXRenderFreePicture(gdi_display, dev->pict_src);
661 dev->pict_src = 0;
663 wine_tsx11_unlock();
667 /* return a mask picture used to force alpha to 0 */
668 static Picture get_no_alpha_mask(void)
670 static Pixmap pixmap;
671 static Picture pict;
673 wine_tsx11_lock();
674 if (!pict)
676 XRenderPictureAttributes pa;
677 XRenderColor col;
679 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
680 pa.repeat = RepeatNormal;
681 pa.component_alpha = True;
682 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
683 CPRepeat|CPComponentAlpha, &pa );
684 col.red = col.green = col.blue = 0xffff;
685 col.alpha = 0;
686 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
688 wine_tsx11_unlock();
689 return pict;
692 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
694 if(p1->hash != p2->hash) return TRUE;
695 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
696 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
697 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
698 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
701 #if 0
702 static void walk_cache(void)
704 int i;
706 EnterCriticalSection(&xrender_cs);
707 for(i=mru; i >= 0; i = glyphsetCache[i].next)
708 TRACE("item %d\n", i);
709 LeaveCriticalSection(&xrender_cs);
711 #endif
713 static int LookupEntry(LFANDSIZE *plfsz)
715 int i, prev_i = -1;
717 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
718 TRACE("%d\n", i);
719 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
721 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
722 glyphsetCache[i].count++;
723 if(prev_i >= 0) {
724 glyphsetCache[prev_i].next = glyphsetCache[i].next;
725 glyphsetCache[i].next = mru;
726 mru = i;
728 TRACE("found font in cache %d\n", i);
729 return i;
731 prev_i = i;
733 TRACE("font not in cache\n");
734 return -1;
737 static void FreeEntry(int entry)
739 int format;
741 for(format = 0; format < AA_MAXVALUE; format++) {
742 gsCacheEntryFormat * formatEntry;
744 if( !glyphsetCache[entry].format[format] )
745 continue;
747 formatEntry = glyphsetCache[entry].format[format];
749 if(formatEntry->glyphset) {
750 wine_tsx11_lock();
751 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
752 wine_tsx11_unlock();
753 formatEntry->glyphset = 0;
755 if(formatEntry->nrealized) {
756 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
757 formatEntry->realized = NULL;
758 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
759 formatEntry->gis = NULL;
760 formatEntry->nrealized = 0;
763 HeapFree(GetProcessHeap(), 0, formatEntry);
764 glyphsetCache[entry].format[format] = NULL;
768 static int AllocEntry(void)
770 int best = -1, prev_best = -1, i, prev_i = -1;
772 if(lastfree >= 0) {
773 assert(glyphsetCache[lastfree].count == -1);
774 glyphsetCache[lastfree].count = 1;
775 best = lastfree;
776 lastfree = glyphsetCache[lastfree].next;
777 assert(best != mru);
778 glyphsetCache[best].next = mru;
779 mru = best;
781 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
782 return mru;
785 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
786 if(glyphsetCache[i].count == 0) {
787 best = i;
788 prev_best = prev_i;
790 prev_i = i;
793 if(best >= 0) {
794 TRACE("freeing unused glyphset at cache %d\n", best);
795 FreeEntry(best);
796 glyphsetCache[best].count = 1;
797 if(prev_best >= 0) {
798 glyphsetCache[prev_best].next = glyphsetCache[best].next;
799 glyphsetCache[best].next = mru;
800 mru = best;
801 } else {
802 assert(mru == best);
804 return mru;
807 TRACE("Growing cache\n");
809 if (glyphsetCache)
810 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
811 glyphsetCache,
812 (glyphsetCacheSize + INIT_CACHE_SIZE)
813 * sizeof(*glyphsetCache));
814 else
815 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
816 (glyphsetCacheSize + INIT_CACHE_SIZE)
817 * sizeof(*glyphsetCache));
819 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
820 i++) {
821 glyphsetCache[i].next = i + 1;
822 glyphsetCache[i].count = -1;
824 glyphsetCache[i-1].next = -1;
825 glyphsetCacheSize += INIT_CACHE_SIZE;
827 lastfree = glyphsetCache[best].next;
828 glyphsetCache[best].count = 1;
829 glyphsetCache[best].next = mru;
830 mru = best;
831 TRACE("new free cache slot at %d\n", mru);
832 return mru;
835 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
837 DWORD size;
838 WORD *gasp, *buffer;
839 WORD num_recs;
840 DWORD ppem;
841 TEXTMETRICW tm;
843 *flags = 0;
845 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
846 if(size == GDI_ERROR)
847 return FALSE;
849 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
850 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
852 GetTextMetricsW(hdc, &tm);
853 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
855 gasp++;
856 num_recs = get_be_word(*gasp);
857 gasp++;
858 while(num_recs--)
860 *flags = get_be_word(*(gasp + 1));
861 if(ppem <= get_be_word(*gasp))
862 break;
863 gasp += 2;
865 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
867 HeapFree(GetProcessHeap(), 0, buffer);
868 return TRUE;
871 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
873 AA_Type ret;
874 WORD flags;
875 UINT font_smoothing_type, font_smoothing_orientation;
877 if (subpixel &&
878 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
879 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
881 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
882 &font_smoothing_orientation, 0) &&
883 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
885 ret = AA_BGR;
887 else
888 ret = AA_RGB;
889 /*FIXME
890 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
891 But, Wine's subpixel rendering can support the portrait mode.
894 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
895 ret = AA_Grey;
896 else
897 ret = AA_None;
899 return ret;
902 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
904 int ret;
905 int format;
906 gsCacheEntry *entry;
907 static int hinter = -1;
908 static int subpixel = -1;
909 BOOL font_smoothing;
911 if((ret = LookupEntry(plfsz)) != -1) return ret;
913 ret = AllocEntry();
914 entry = glyphsetCache + ret;
915 entry->lfsz = *plfsz;
916 for( format = 0; format < AA_MAXVALUE; format++ ) {
917 assert( !entry->format[format] );
920 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
922 if(hinter == -1 || subpixel == -1)
924 RASTERIZER_STATUS status;
925 GetRasterizerCaps(&status, sizeof(status));
926 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
927 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
930 switch (plfsz->lf.lfQuality)
932 case ANTIALIASED_QUALITY:
933 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
934 return ret; /* ignore further configuration */
935 case CLEARTYPE_QUALITY:
936 case CLEARTYPE_NATURAL_QUALITY:
937 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
938 break;
939 case DEFAULT_QUALITY:
940 case DRAFT_QUALITY:
941 case PROOF_QUALITY:
942 default:
943 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
944 font_smoothing)
946 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
948 else
949 entry->aa_default = AA_None;
950 break;
953 font_smoothing = TRUE; /* default to enabled */
954 #ifdef SONAME_LIBFONTCONFIG
955 if (fontconfig_installed)
957 FcPattern *match, *pattern;
958 FcResult result;
959 char family[LF_FACESIZE * 4];
961 #if defined(__i386__) && defined(__GNUC__)
962 /* fontconfig generates floating point exceptions, mask them */
963 WORD cw, default_cw = 0x37f;
964 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
965 #endif
967 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
968 pattern = pFcPatternCreate();
969 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
970 if (plfsz->lf.lfWeight != FW_DONTCARE)
972 int weight;
973 switch (plfsz->lf.lfWeight)
975 case FW_THIN: weight = FC_WEIGHT_THIN; break;
976 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
977 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
978 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
979 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
980 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
981 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
982 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
983 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
984 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
986 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
988 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
989 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
990 pFcDefaultSubstitute( pattern );
991 if ((match = pFcFontMatch( NULL, pattern, &result )))
993 int rgba;
994 FcBool antialias;
996 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
997 antialias = TRUE;
998 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
1000 FcChar8 *file;
1001 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
1003 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
1004 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
1006 switch (rgba)
1008 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1009 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1010 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1011 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1012 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1015 if (!antialias) font_smoothing = FALSE;
1016 pFcPatternDestroy( match );
1018 pFcPatternDestroy( pattern );
1020 #if defined(__i386__) && defined(__GNUC__)
1021 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
1022 #endif
1024 #endif /* SONAME_LIBFONTCONFIG */
1026 /* now check Xft resources */
1028 char *value;
1029 BOOL antialias = TRUE;
1031 wine_tsx11_lock();
1032 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1034 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1035 value[0] == '0' || !strcasecmp( value, "off" ))
1036 antialias = FALSE;
1038 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1040 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1041 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1042 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1043 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1044 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1045 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1047 wine_tsx11_unlock();
1048 if (!antialias) font_smoothing = FALSE;
1051 if (!font_smoothing) entry->aa_default = AA_None;
1053 else
1054 entry->aa_default = AA_None;
1056 return ret;
1059 static void dec_ref_cache(int index)
1061 assert(index >= 0);
1062 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1063 assert(glyphsetCache[index].count > 0);
1064 glyphsetCache[index].count--;
1067 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1069 DWORD hash = 0, *ptr, two_chars;
1070 WORD *pwc;
1071 int i;
1073 hash ^= plfsz->devsize.cx;
1074 hash ^= plfsz->devsize.cy;
1075 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1076 hash ^= *ptr;
1077 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1078 hash ^= *ptr;
1079 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1080 two_chars = *ptr;
1081 pwc = (WCHAR *)&two_chars;
1082 if(!*pwc) break;
1083 *pwc = toupperW(*pwc);
1084 pwc++;
1085 *pwc = toupperW(*pwc);
1086 hash ^= two_chars;
1087 if(!*pwc) break;
1089 plfsz->hash = hash;
1090 return;
1093 /***********************************************************************
1094 * X11DRV_XRender_Finalize
1096 void X11DRV_XRender_Finalize(void)
1098 int i;
1100 EnterCriticalSection(&xrender_cs);
1101 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1102 FreeEntry(i);
1103 LeaveCriticalSection(&xrender_cs);
1104 DeleteCriticalSection(&xrender_cs);
1107 /**********************************************************************
1108 * xrenderdrv_SelectFont
1110 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1112 struct xrender_physdev *physdev = get_xrender_dev( dev );
1113 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1114 HFONT ret = next->funcs->pSelectFont( next, hfont );
1116 if (!ret) return 0;
1118 if (physdev->x11dev->has_gdi_font)
1120 LFANDSIZE lfsz;
1122 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1124 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1125 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1126 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1127 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1128 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1129 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1131 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1132 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1133 lfsz.xform.eM21, lfsz.xform.eM22);
1135 /* Not used fields, would break hashing */
1136 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1138 lfsz_calc_hash(&lfsz);
1140 EnterCriticalSection(&xrender_cs);
1141 if (physdev->cache_index != -1)
1142 dec_ref_cache( physdev->cache_index );
1143 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1144 LeaveCriticalSection(&xrender_cs);
1146 else
1148 EnterCriticalSection( &xrender_cs );
1149 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1150 physdev->cache_index = -1;
1151 LeaveCriticalSection( &xrender_cs );
1153 return ret;
1156 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1158 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1159 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1161 if (!physdev) return FALSE;
1162 physdev->x11dev = x11dev;
1163 physdev->cache_index = -1;
1164 physdev->format = format;
1165 physdev->pict_format = pict_formats[format];
1166 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1167 return TRUE;
1170 /* store the color mask data in the bitmap info structure */
1171 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1173 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1175 info->bmiHeader.biPlanes = 1;
1176 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1177 info->bmiHeader.biCompression = BI_RGB;
1178 info->bmiHeader.biClrUsed = 0;
1180 switch (info->bmiHeader.biBitCount)
1182 case 16:
1183 colors[0] = format->direct.redMask << format->direct.red;
1184 colors[1] = format->direct.greenMask << format->direct.green;
1185 colors[2] = format->direct.blueMask << format->direct.blue;
1186 info->bmiHeader.biCompression = BI_BITFIELDS;
1187 break;
1188 case 32:
1189 colors[0] = format->direct.redMask << format->direct.red;
1190 colors[1] = format->direct.greenMask << format->direct.green;
1191 colors[2] = format->direct.blueMask << format->direct.blue;
1192 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1193 info->bmiHeader.biCompression = BI_BITFIELDS;
1194 break;
1199 /**********************************************************************
1200 * xrenderdrv_CreateDC
1202 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1203 LPCWSTR output, const DEVMODEW* initData )
1205 return create_xrender_dc( pdev, default_format );
1208 /**********************************************************************
1209 * xrenderdrv_CreateCompatibleDC
1211 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1213 if (orig) /* chain to x11drv first */
1215 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1216 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1218 /* otherwise we have been called by x11drv */
1220 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1223 /**********************************************************************
1224 * xrenderdrv_DeleteDC
1226 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1228 struct xrender_physdev *physdev = get_xrender_dev( dev );
1230 free_xrender_picture( physdev );
1232 EnterCriticalSection( &xrender_cs );
1233 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1234 LeaveCriticalSection( &xrender_cs );
1236 HeapFree( GetProcessHeap(), 0, physdev );
1237 return TRUE;
1240 /**********************************************************************
1241 * xrenderdrv_ExtEscape
1243 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1244 INT out_count, LPVOID out_data )
1246 struct xrender_physdev *physdev = get_xrender_dev( dev );
1248 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1250 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1252 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1254 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1255 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1256 return ret;
1259 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1262 /****************************************************************************
1263 * xrenderdrv_CopyBitmap
1265 static BOOL xrenderdrv_CopyBitmap( HBITMAP src, HBITMAP dst )
1267 return X11DRV_CopyBitmap( src, dst );
1270 /****************************************************************************
1271 * xrenderdrv_CreateBitmap
1273 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1275 enum wxr_format format = WXR_INVALID_FORMAT;
1276 X_PHYSBITMAP *phys_bitmap;
1277 BITMAP bitmap;
1279 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1281 if (bitmap.bmBitsPixel == 1)
1283 if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, 1 ))) return FALSE;
1284 phys_bitmap->format = WXR_FORMAT_MONO;
1285 phys_bitmap->trueColor = FALSE;
1287 else
1289 format = get_bitmap_format( bitmap.bmBitsPixel );
1291 if (pict_formats[format])
1293 if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth )))
1294 return FALSE;
1295 phys_bitmap->format = format;
1296 phys_bitmap->trueColor = TRUE;
1297 phys_bitmap->color_shifts = wxr_color_shifts[format];
1299 else
1301 if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, screen_depth )))
1302 return FALSE;
1303 phys_bitmap->format = WXR_INVALID_FORMAT;
1304 phys_bitmap->trueColor = (visual->class == TrueColor || visual->class == DirectColor);
1305 phys_bitmap->color_shifts = X11DRV_PALETTE_default_shifts;
1308 return TRUE;
1311 /****************************************************************************
1312 * xrenderdrv_DeleteBitmap
1314 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1316 return X11DRV_DeleteBitmap( hbitmap );
1319 /***********************************************************************
1320 * xrenderdrv_SelectBitmap
1322 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1324 HBITMAP ret;
1325 struct xrender_physdev *physdev = get_xrender_dev( dev );
1327 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1328 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1329 if (ret)
1331 free_xrender_picture( physdev );
1332 if (hbitmap == BITMAP_stock_phys_bitmap.hbitmap) physdev->format = WXR_FORMAT_MONO;
1333 else physdev->format = X11DRV_get_phys_bitmap(hbitmap)->format;
1334 physdev->pict_format = pict_formats[physdev->format];
1336 return ret;
1339 /***********************************************************************
1340 * xrenderdrv_GetImage
1342 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1343 struct gdi_image_bits *bits, struct bitblt_coords *src )
1345 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1346 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1347 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1350 /***********************************************************************
1351 * xrenderdrv_SetDeviceClipping
1353 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1355 struct xrender_physdev *physdev = get_xrender_dev( dev );
1357 physdev->region = rgn;
1358 physdev->update_clip = TRUE;
1360 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1361 dev->funcs->pSetDeviceClipping( dev, rgn );
1365 /************************************************************************
1366 * UploadGlyph
1368 * Helper to ExtTextOut. Must be called inside xrender_cs
1370 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1372 unsigned int buflen;
1373 char *buf;
1374 Glyph gid;
1375 GLYPHMETRICS gm;
1376 XGlyphInfo gi;
1377 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1378 gsCacheEntryFormat *formatEntry;
1379 UINT ggo_format = GGO_GLYPH_INDEX;
1380 enum wxr_format wxr_format;
1381 static const char zero[4];
1382 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1384 switch(format) {
1385 case AA_Grey:
1386 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1387 break;
1388 case AA_RGB:
1389 ggo_format |= WINE_GGO_HRGB_BITMAP;
1390 break;
1391 case AA_BGR:
1392 ggo_format |= WINE_GGO_HBGR_BITMAP;
1393 break;
1394 case AA_VRGB:
1395 ggo_format |= WINE_GGO_VRGB_BITMAP;
1396 break;
1397 case AA_VBGR:
1398 ggo_format |= WINE_GGO_VBGR_BITMAP;
1399 break;
1401 default:
1402 ERR("aa = %d - not implemented\n", format);
1403 case AA_None:
1404 ggo_format |= GGO_BITMAP;
1405 break;
1408 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1409 if(buflen == GDI_ERROR) {
1410 if(format != AA_None) {
1411 format = AA_None;
1412 entry->aa_default = AA_None;
1413 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1414 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1416 if(buflen == GDI_ERROR) {
1417 WARN("GetGlyphOutlineW failed using default glyph\n");
1418 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1419 if(buflen == GDI_ERROR) {
1420 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1421 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1422 if(buflen == GDI_ERROR) {
1423 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1424 return;
1428 TRACE("Turning off antialiasing for this monochrome font\n");
1431 /* If there is nothing for the current type, we create the entry. */
1432 if( !entry->format[format] ) {
1433 entry->format[format] = HeapAlloc(GetProcessHeap(),
1434 HEAP_ZERO_MEMORY,
1435 sizeof(gsCacheEntryFormat));
1437 formatEntry = entry->format[format];
1439 if(formatEntry->nrealized <= glyph) {
1440 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1442 if (formatEntry->realized)
1443 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1444 HEAP_ZERO_MEMORY,
1445 formatEntry->realized,
1446 formatEntry->nrealized * sizeof(BOOL));
1447 else
1448 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1449 HEAP_ZERO_MEMORY,
1450 formatEntry->nrealized * sizeof(BOOL));
1452 if (formatEntry->gis)
1453 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1454 HEAP_ZERO_MEMORY,
1455 formatEntry->gis,
1456 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1457 else
1458 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1459 HEAP_ZERO_MEMORY,
1460 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1464 if(formatEntry->glyphset == 0) {
1465 switch(format) {
1466 case AA_Grey:
1467 wxr_format = WXR_FORMAT_GRAY;
1468 break;
1470 case AA_RGB:
1471 case AA_BGR:
1472 case AA_VRGB:
1473 case AA_VBGR:
1474 wxr_format = WXR_FORMAT_A8R8G8B8;
1475 break;
1477 default:
1478 ERR("aa = %d - not implemented\n", format);
1479 case AA_None:
1480 wxr_format = WXR_FORMAT_MONO;
1481 break;
1484 wine_tsx11_lock();
1485 formatEntry->font_format = pict_formats[wxr_format];
1486 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1487 wine_tsx11_unlock();
1491 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1492 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1493 formatEntry->realized[glyph] = TRUE;
1495 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1496 buflen,
1497 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1498 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1500 gi.width = gm.gmBlackBoxX;
1501 gi.height = gm.gmBlackBoxY;
1502 gi.x = -gm.gmptGlyphOrigin.x;
1503 gi.y = gm.gmptGlyphOrigin.y;
1504 gi.xOff = gm.gmCellIncX;
1505 gi.yOff = gm.gmCellIncY;
1507 if(TRACE_ON(xrender)) {
1508 int pitch, i, j;
1509 char output[300];
1510 unsigned char *line;
1512 if(format == AA_None) {
1513 pitch = ((gi.width + 31) / 32) * 4;
1514 for(i = 0; i < gi.height; i++) {
1515 line = (unsigned char*) buf + i * pitch;
1516 output[0] = '\0';
1517 for(j = 0; j < pitch * 8; j++) {
1518 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1520 TRACE("%s\n", output);
1522 } else {
1523 static const char blks[] = " .:;!o*#";
1524 char str[2];
1526 str[1] = '\0';
1527 pitch = ((gi.width + 3) / 4) * 4;
1528 for(i = 0; i < gi.height; i++) {
1529 line = (unsigned char*) buf + i * pitch;
1530 output[0] = '\0';
1531 for(j = 0; j < pitch; j++) {
1532 str[0] = blks[line[j] >> 5];
1533 strcat(output, str);
1535 TRACE("%s\n", output);
1541 if(formatEntry->glyphset) {
1542 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1543 unsigned char *byte = (unsigned char*) buf, c;
1544 int i = buflen;
1546 while(i--) {
1547 c = *byte;
1549 /* magic to flip bit order */
1550 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1551 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1552 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1554 *byte++ = c;
1557 else if ( format != AA_Grey &&
1558 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1560 unsigned int i, *data = (unsigned int *)buf;
1561 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1563 gid = glyph;
1566 XRenderCompositeText seems to ignore 0x0 glyphs when
1567 AA_None, which means we lose the advance width of glyphs
1568 like the space. We'll pretend that such glyphs are 1x1
1569 bitmaps.
1572 if(buflen == 0)
1573 gi.width = gi.height = 1;
1575 wine_tsx11_lock();
1576 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1577 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1578 wine_tsx11_unlock();
1579 HeapFree(GetProcessHeap(), 0, buf);
1582 formatEntry->gis[glyph] = gi;
1585 /*************************************************************
1586 * get_tile_pict
1588 * Returns an appropriate Picture for tiling the text colour.
1589 * Call and use result within the xrender_cs
1591 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1593 static struct
1595 Pixmap xpm;
1596 Picture pict;
1597 XRenderColor current_color;
1598 } tiles[WXR_NB_FORMATS], *tile;
1600 tile = &tiles[wxr_format];
1602 if(!tile->xpm)
1604 XRenderPictureAttributes pa;
1605 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1607 wine_tsx11_lock();
1608 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1610 pa.repeat = RepeatNormal;
1611 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1612 wine_tsx11_unlock();
1614 /* init current_color to something different from text_pixel */
1615 tile->current_color = *color;
1616 tile->current_color.red ^= 0xffff;
1618 if (wxr_format == WXR_FORMAT_MONO)
1620 /* for a 1bpp bitmap we always need a 1 in the tile */
1621 XRenderColor col;
1622 col.red = col.green = col.blue = 0;
1623 col.alpha = 0xffff;
1624 wine_tsx11_lock();
1625 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1626 wine_tsx11_unlock();
1630 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1632 wine_tsx11_lock();
1633 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1634 wine_tsx11_unlock();
1635 tile->current_color = *color;
1637 return tile->pict;
1640 /*************************************************************
1641 * get_mask_pict
1643 * Returns an appropriate Picture for masking with the specified alpha.
1644 * Call and use result within the xrender_cs
1646 static Picture get_mask_pict( int alpha )
1648 static Pixmap pixmap;
1649 static Picture pict;
1650 static int current_alpha;
1652 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1654 if (!pixmap)
1656 XRenderPictureAttributes pa;
1658 wine_tsx11_lock();
1659 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1660 pa.repeat = RepeatNormal;
1661 pict = pXRenderCreatePicture( gdi_display, pixmap,
1662 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1663 wine_tsx11_unlock();
1664 current_alpha = -1;
1667 if (alpha != current_alpha)
1669 XRenderColor col;
1670 col.red = col.green = col.blue = 0;
1671 col.alpha = current_alpha = alpha;
1672 wine_tsx11_lock();
1673 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1674 wine_tsx11_unlock();
1676 return pict;
1679 /***********************************************************************
1680 * xrenderdrv_ExtTextOut
1682 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1683 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1685 struct xrender_physdev *physdev = get_xrender_dev( dev );
1686 gsCacheEntry *entry;
1687 gsCacheEntryFormat *formatEntry;
1688 AA_Type aa_type = AA_None;
1689 unsigned int idx;
1690 Picture pict, tile_pict = 0;
1691 XGlyphElt16 *elts;
1692 POINT offset, desired, current;
1693 int render_op = PictOpOver;
1694 XRenderColor col;
1696 if (!physdev->x11dev->has_gdi_font)
1698 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1699 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1702 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1703 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1705 if(flags & ETO_OPAQUE)
1707 XRenderColor bg;
1709 if (physdev->format == WXR_FORMAT_MONO)
1710 /* use the inverse of the text color */
1711 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1712 else
1713 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1715 wine_tsx11_lock();
1716 set_xrender_transformation( pict, 1, 1, 0, 0 );
1717 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1718 physdev->x11dev->dc_rect.left + lprect->left,
1719 physdev->x11dev->dc_rect.top + lprect->top,
1720 lprect->right - lprect->left,
1721 lprect->bottom - lprect->top );
1722 wine_tsx11_unlock();
1725 if(count == 0) return TRUE;
1727 EnterCriticalSection(&xrender_cs);
1729 entry = glyphsetCache + physdev->cache_index;
1730 aa_type = entry->aa_default;
1731 formatEntry = entry->format[aa_type];
1733 for(idx = 0; idx < count; idx++) {
1734 if( !formatEntry ) {
1735 UploadGlyph(physdev, wstr[idx], aa_type);
1736 /* re-evaluate antialias since aa_default may have changed */
1737 aa_type = entry->aa_default;
1738 formatEntry = entry->format[aa_type];
1739 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1740 UploadGlyph(physdev, wstr[idx], aa_type);
1743 if (!formatEntry)
1745 WARN("could not upload requested glyphs\n");
1746 LeaveCriticalSection(&xrender_cs);
1747 return FALSE;
1750 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1751 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1753 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1755 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1756 So we pass zeros to the function and move to our starting position using the first
1757 element of the elts array. */
1759 desired.x = physdev->x11dev->dc_rect.left + x;
1760 desired.y = physdev->x11dev->dc_rect.top + y;
1761 offset.x = offset.y = 0;
1762 current.x = current.y = 0;
1764 tile_pict = get_tile_pict(physdev->format, &col);
1766 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1768 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1769 render_op = PictOpOutReverse; /* This gives us 'black' text */
1771 for(idx = 0; idx < count; idx++)
1773 elts[idx].glyphset = formatEntry->glyphset;
1774 elts[idx].chars = wstr + idx;
1775 elts[idx].nchars = 1;
1776 elts[idx].xOff = desired.x - current.x;
1777 elts[idx].yOff = desired.y - current.y;
1779 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1780 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1782 if(!lpDx)
1784 desired.x += formatEntry->gis[wstr[idx]].xOff;
1785 desired.y += formatEntry->gis[wstr[idx]].yOff;
1787 else
1789 if(flags & ETO_PDY)
1791 offset.x += lpDx[idx * 2];
1792 offset.y += lpDx[idx * 2 + 1];
1794 else
1795 offset.x += lpDx[idx];
1796 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1797 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1801 wine_tsx11_lock();
1802 /* Make sure we don't have any transforms set from a previous call */
1803 set_xrender_transformation(pict, 1, 1, 0, 0);
1804 pXRenderCompositeText16(gdi_display, render_op,
1805 tile_pict,
1806 pict,
1807 formatEntry->font_format,
1808 0, 0, 0, 0, elts, count);
1809 wine_tsx11_unlock();
1810 HeapFree(GetProcessHeap(), 0, elts);
1812 LeaveCriticalSection(&xrender_cs);
1813 return TRUE;
1816 /* multiply the alpha channel of a picture */
1817 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1818 int x, int y, int width, int height )
1820 XRenderPictureAttributes pa;
1821 Pixmap src_pixmap, mask_pixmap;
1822 Picture src_pict, mask_pict;
1823 XRenderColor color;
1825 wine_tsx11_lock();
1826 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1827 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1828 pa.repeat = RepeatNormal;
1829 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1830 pa.component_alpha = True;
1831 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1832 color.red = color.green = color.blue = color.alpha = 0xffff;
1833 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1834 color.alpha = alpha;
1835 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1836 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1837 0, 0, 0, 0, x, y, width, height );
1838 pXRenderFreePicture( gdi_display, src_pict );
1839 pXRenderFreePicture( gdi_display, mask_pict );
1840 XFreePixmap( gdi_display, src_pixmap );
1841 XFreePixmap( gdi_display, mask_pixmap );
1842 wine_tsx11_unlock();
1845 /* Helper function for (stretched) blitting using xrender */
1846 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1847 int x_src, int y_src, int width_src, int height_src,
1848 int x_dst, int y_dst, int width_dst, int height_dst,
1849 double xscale, double yscale )
1851 int x_offset, y_offset;
1853 if (width_src < 0)
1855 x_src += width_src + 1;
1856 width_src = -width_src;
1858 if (height_src < 0)
1860 y_src += height_src + 1;
1861 height_src = -height_src;
1863 if (width_dst < 0)
1865 x_dst += width_dst + 1;
1866 width_dst = -width_dst;
1868 if (height_dst < 0)
1870 y_dst += height_dst + 1;
1871 height_dst = -height_dst;
1874 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1875 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1876 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1877 wine_tsx11_lock();
1878 if(xscale != 1.0 || yscale != 1.0)
1880 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1881 * in the wrong quadrant of the x-y plane.
1883 x_offset = (xscale < 0) ? -width_dst : 0;
1884 y_offset = (yscale < 0) ? -height_dst : 0;
1885 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1887 else
1889 x_offset = x_src;
1890 y_offset = y_src;
1891 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1893 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1894 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1895 wine_tsx11_unlock();
1898 /* Helper function for (stretched) mono->color blitting using xrender */
1899 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1900 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1901 int x_src, int y_src, int width_src, int height_src,
1902 int x_dst, int y_dst, int width_dst, int height_dst,
1903 double xscale, double yscale )
1905 Picture tile_pict;
1906 int x_offset, y_offset;
1907 XRenderColor color;
1909 if (width_src < 0)
1911 x_src += width_src + 1;
1912 width_src = -width_src;
1914 if (height_src < 0)
1916 y_src += height_src + 1;
1917 height_src = -height_src;
1919 if (width_dst < 0)
1921 x_dst += width_dst + 1;
1922 width_dst = -width_dst;
1924 if (height_dst < 0)
1926 y_dst += height_dst + 1;
1927 height_dst = -height_dst;
1930 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1931 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1932 * the tile data.
1934 EnterCriticalSection( &xrender_cs );
1935 color = *bg;
1936 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1937 tile_pict = get_tile_pict( dst_format, &color );
1939 wine_tsx11_lock();
1940 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1942 if (xscale != 1.0 || yscale != 1.0)
1944 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1945 * in the wrong quadrant of the x-y plane.
1947 x_offset = (xscale < 0) ? -width_dst : 0;
1948 y_offset = (yscale < 0) ? -height_dst : 0;
1949 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1951 else
1953 x_offset = x_src;
1954 y_offset = y_src;
1955 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1957 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1958 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1959 wine_tsx11_unlock();
1960 LeaveCriticalSection( &xrender_cs );
1962 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1963 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1964 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1965 x_dst, y_dst, width_dst, height_dst );
1968 /* create a pixmap and render picture for an image */
1969 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1970 struct bitblt_coords *src, enum wxr_format format,
1971 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1973 DWORD ret;
1974 int width = src->visrect.right - src->visrect.left;
1975 int height = src->visrect.bottom - src->visrect.top;
1976 int depth = pict_formats[format]->depth;
1977 struct gdi_image_bits dst_bits;
1978 XRenderPictureAttributes pa;
1979 XImage *image;
1981 wine_tsx11_lock();
1982 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1983 info->bmiHeader.biWidth, height, 32, 0 );
1984 wine_tsx11_unlock();
1985 if (!image) return ERROR_OUTOFMEMORY;
1987 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1988 if (ret) return ret;
1990 image->data = dst_bits.ptr;
1992 *use_repeat = (width == 1 && height == 1);
1993 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1995 wine_tsx11_lock();
1996 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1997 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
1998 src->visrect.left, 0, 0, 0, width, height );
1999 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2000 wine_tsx11_unlock();
2002 /* make coordinates relative to the pixmap */
2003 src->x -= src->visrect.left;
2004 src->y -= src->visrect.top;
2005 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2007 image->data = NULL;
2008 wine_tsx11_lock();
2009 XDestroyImage( image );
2010 wine_tsx11_unlock();
2011 if (dst_bits.free) dst_bits.free( &dst_bits );
2012 return ret;
2015 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2016 Drawable drawable, const struct bitblt_coords *src,
2017 const struct bitblt_coords *dst )
2019 int x_dst, y_dst;
2020 Picture src_pict = 0, dst_pict, mask_pict = 0;
2021 BOOL use_repeat;
2022 double xscale, yscale;
2024 use_repeat = use_source_repeat( physdev_src );
2025 if (!use_repeat)
2027 xscale = src->width / (double)dst->width;
2028 yscale = src->height / (double)dst->height;
2030 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2032 if (drawable) /* using an intermediate pixmap */
2034 XRenderPictureAttributes pa;
2036 x_dst = dst->x;
2037 y_dst = dst->y;
2038 pa.repeat = RepeatNone;
2039 wine_tsx11_lock();
2040 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2041 wine_tsx11_unlock();
2043 else
2045 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2046 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2047 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2050 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2052 /* mono -> color */
2053 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2055 XRenderColor fg, bg;
2057 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
2058 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
2059 fg.alpha = bg.alpha = 0;
2061 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2062 physdev_src->x11dev->dc_rect.left + src->x,
2063 physdev_src->x11dev->dc_rect.top + src->y,
2064 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2066 else /* color -> color (can be at different depths) or mono -> mono */
2068 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
2069 mask_pict = get_no_alpha_mask();
2071 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2072 physdev_src->x11dev->dc_rect.left + src->x,
2073 physdev_src->x11dev->dc_rect.top + src->y,
2074 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2077 if (drawable)
2079 wine_tsx11_lock();
2080 pXRenderFreePicture( gdi_display, dst_pict );
2081 wine_tsx11_unlock();
2086 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2087 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2088 Drawable drawable, struct bitblt_coords *src,
2089 struct bitblt_coords *dst, BOOL use_repeat )
2091 int x_dst, y_dst;
2092 Picture dst_pict;
2093 XRenderPictureAttributes pa;
2094 double xscale, yscale;
2096 if (drawable) /* using an intermediate pixmap */
2098 RGNDATA *clip_data = NULL;
2100 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2101 x_dst = dst->x;
2102 y_dst = dst->y;
2103 pa.repeat = RepeatNone;
2104 wine_tsx11_lock();
2105 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2106 if (clip_data)
2107 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2108 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2109 wine_tsx11_unlock();
2110 HeapFree( GetProcessHeap(), 0, clip_data );
2112 else
2114 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2115 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2116 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2119 if (!use_repeat)
2121 xscale = src->width / (double)dst->width;
2122 yscale = src->height / (double)dst->height;
2124 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2126 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
2127 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2129 if (drawable)
2131 wine_tsx11_lock();
2132 pXRenderFreePicture( gdi_display, dst_pict );
2133 wine_tsx11_unlock();
2138 /***********************************************************************
2139 * xrenderdrv_StretchBlt
2141 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2142 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2144 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2145 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2146 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2148 if (src_dev->funcs != dst_dev->funcs)
2150 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2151 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2154 /* XRender is of no use for color -> mono */
2155 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2156 goto x11drv_fallback;
2158 /* if not stretching, we only need to handle format conversion */
2159 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2161 if (rop != SRCCOPY)
2163 GC tmpGC;
2164 Pixmap tmp_pixmap;
2165 struct bitblt_coords tmp;
2167 /* make coordinates relative to tmp pixmap */
2168 tmp = *dst;
2169 tmp.x -= tmp.visrect.left;
2170 tmp.y -= tmp.visrect.top;
2171 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2173 wine_tsx11_lock();
2174 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2175 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2176 XSetGraphicsExposures( gdi_display, tmpGC, False );
2177 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2178 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
2179 wine_tsx11_unlock();
2181 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2182 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2184 wine_tsx11_lock();
2185 XFreePixmap( gdi_display, tmp_pixmap );
2186 XFreeGC( gdi_display, tmpGC );
2187 wine_tsx11_unlock();
2189 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2191 return TRUE;
2193 x11drv_fallback:
2194 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2198 /***********************************************************************
2199 * xrenderdrv_PutImage
2201 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2202 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2203 struct bitblt_coords *dst, DWORD rop )
2205 struct xrender_physdev *physdev;
2206 X_PHYSBITMAP *bitmap;
2207 DWORD ret;
2208 Pixmap tmp_pixmap;
2209 GC gc;
2210 enum wxr_format src_format, dst_format;
2211 XRenderPictFormat *pict_format;
2212 Pixmap src_pixmap;
2213 Picture src_pict, mask_pict = 0;
2214 BOOL use_repeat;
2216 if (hbitmap)
2218 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2219 physdev = NULL;
2220 dst_format = bitmap->format;
2222 else
2224 physdev = get_xrender_dev( dev );
2225 bitmap = NULL;
2226 dst_format = physdev->format;
2229 src_format = get_xrender_format_from_bitmapinfo( info );
2230 if (!(pict_format = pict_formats[src_format])) goto update_format;
2232 /* make sure we can create an image with the same bpp */
2233 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2234 goto update_format;
2236 /* mono <-> color conversions not supported */
2237 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2238 goto x11drv_fallback;
2240 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2242 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2244 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2245 if (!ret)
2247 struct bitblt_coords tmp;
2249 if (bitmap)
2251 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2252 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2254 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2255 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2256 DeleteObject( rgn );
2258 else
2260 if (rop != SRCCOPY)
2262 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2264 /* make coordinates relative to tmp pixmap */
2265 tmp = *dst;
2266 tmp.x -= tmp.visrect.left;
2267 tmp.y -= tmp.visrect.top;
2268 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2270 wine_tsx11_lock();
2271 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2272 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2273 XSetGraphicsExposures( gdi_display, gc, False );
2274 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2275 tmp.visrect.right - tmp.visrect.left,
2276 tmp.visrect.bottom - tmp.visrect.top,
2277 physdev->pict_format->depth );
2278 wine_tsx11_unlock();
2280 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2281 NULL, tmp_pixmap, src, &tmp, use_repeat );
2282 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2284 wine_tsx11_lock();
2285 XFreePixmap( gdi_display, tmp_pixmap );
2286 XFreeGC( gdi_display, gc );
2287 wine_tsx11_unlock();
2289 if (restore_region) restore_clipping_region( physdev->x11dev );
2291 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2292 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2295 wine_tsx11_lock();
2296 pXRenderFreePicture( gdi_display, src_pict );
2297 XFreePixmap( gdi_display, src_pixmap );
2298 wine_tsx11_unlock();
2300 return ret;
2302 update_format:
2303 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2304 set_color_info( pict_formats[dst_format], info );
2305 return ERROR_BAD_FORMAT;
2307 x11drv_fallback:
2308 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2309 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2310 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2314 /***********************************************************************
2315 * xrenderdrv_BlendImage
2317 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2318 struct bitblt_coords *src, struct bitblt_coords *dst,
2319 BLENDFUNCTION func )
2321 struct xrender_physdev *physdev = get_xrender_dev( dev );
2322 DWORD ret;
2323 enum wxr_format format;
2324 XRenderPictFormat *pict_format;
2325 Picture dst_pict, src_pict, mask_pict;
2326 Pixmap src_pixmap;
2327 BOOL use_repeat;
2329 format = get_xrender_format_from_bitmapinfo( info );
2330 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2331 format = get_format_without_alpha( format );
2332 else if (format != WXR_FORMAT_A8R8G8B8)
2333 return ERROR_INVALID_PARAMETER;
2335 if (!(pict_format = pict_formats[format])) goto update_format;
2337 /* make sure we can create an image with the same bpp */
2338 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2339 goto update_format;
2341 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2342 goto update_format;
2344 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2346 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2347 if (!ret)
2349 double xscale, yscale;
2351 if (!use_repeat)
2353 xscale = src->width / (double)dst->width;
2354 yscale = src->height / (double)dst->height;
2356 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2358 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2360 EnterCriticalSection( &xrender_cs );
2361 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2363 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2364 src->x, src->y, src->width, src->height,
2365 physdev->x11dev->dc_rect.left + dst->x,
2366 physdev->x11dev->dc_rect.top + dst->y,
2367 dst->width, dst->height, xscale, yscale );
2369 wine_tsx11_lock();
2370 pXRenderFreePicture( gdi_display, src_pict );
2371 XFreePixmap( gdi_display, src_pixmap );
2372 wine_tsx11_unlock();
2374 LeaveCriticalSection( &xrender_cs );
2376 return ret;
2378 update_format:
2379 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2380 set_color_info( physdev->pict_format, info );
2381 return ERROR_BAD_FORMAT;
2385 /***********************************************************************
2386 * xrenderdrv_AlphaBlend
2388 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2389 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2391 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2392 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2393 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2394 XRenderPictureAttributes pa;
2395 Pixmap tmp_pixmap = 0;
2396 double xscale, yscale;
2397 BOOL use_repeat;
2399 if (src_dev->funcs != dst_dev->funcs)
2401 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2402 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2405 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2407 SetLastError( ERROR_INVALID_PARAMETER );
2408 return FALSE;
2411 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2413 use_repeat = use_source_repeat( physdev_src );
2414 if (!use_repeat)
2416 xscale = src->width / (double)dst->width;
2417 yscale = src->height / (double)dst->height;
2419 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2421 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2423 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2425 /* mono -> color blending needs an intermediate color pixmap */
2426 XRenderColor fg, bg;
2427 int width = src->visrect.right - src->visrect.left;
2428 int height = src->visrect.bottom - src->visrect.top;
2430 /* blending doesn't use the destination DC colors */
2431 fg.red = fg.green = fg.blue = 0;
2432 bg.red = bg.green = bg.blue = 0xffff;
2433 fg.alpha = bg.alpha = 0xffff;
2435 wine_tsx11_lock();
2436 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2437 physdev_dst->pict_format->depth );
2438 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2439 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2440 CPRepeat, &pa );
2441 wine_tsx11_unlock();
2443 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2444 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
2446 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2448 /* we need a source picture with no alpha */
2449 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2450 if (format != physdev_src->format)
2452 wine_tsx11_lock();
2453 pa.subwindow_mode = IncludeInferiors;
2454 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2455 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2456 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2457 wine_tsx11_unlock();
2461 if (tmp_pict) src_pict = tmp_pict;
2463 EnterCriticalSection( &xrender_cs );
2464 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2466 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2467 physdev_src->x11dev->dc_rect.left + src->x,
2468 physdev_src->x11dev->dc_rect.top + src->y,
2469 src->width, src->height,
2470 physdev_dst->x11dev->dc_rect.left + dst->x,
2471 physdev_dst->x11dev->dc_rect.top + dst->y,
2472 dst->width, dst->height, xscale, yscale );
2474 wine_tsx11_lock();
2475 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2476 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2477 wine_tsx11_unlock();
2479 LeaveCriticalSection( &xrender_cs );
2480 return TRUE;
2483 /***********************************************************************
2484 * xrenderdrv_GradientFill
2486 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2487 void * grad_array, ULONG ngrad, ULONG mode )
2489 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2490 static const XFixed stops[2] = { 0, 1 << 16 };
2491 struct xrender_physdev *physdev = get_xrender_dev( dev );
2492 XLinearGradient gradient;
2493 XRenderColor colors[2];
2494 Picture src_pict, dst_pict;
2495 unsigned int i;
2496 const GRADIENT_RECT *rect = grad_array;
2497 POINT pt[2];
2499 if (!pXRenderCreateLinearGradient) goto fallback;
2501 /* <= 16-bpp uses dithering */
2502 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2504 switch (mode)
2506 case GRADIENT_FILL_RECT_H:
2507 case GRADIENT_FILL_RECT_V:
2508 for (i = 0; i < ngrad; i++, rect++)
2510 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2511 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2513 colors[0].red = v1->Red * 257 / 256;
2514 colors[0].green = v1->Green * 257 / 256;
2515 colors[0].blue = v1->Blue * 257 / 256;
2516 colors[1].red = v2->Red * 257 / 256;
2517 colors[1].green = v2->Green * 257 / 256;
2518 colors[1].blue = v2->Blue * 257 / 256;
2519 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2520 colors[0].alpha = colors[1].alpha = 65535;
2522 pt[0].x = v1->x;
2523 pt[0].y = v1->y;
2524 pt[1].x = v2->x;
2525 pt[1].y = v2->y;
2526 LPtoDP( dev->hdc, pt, 2 );
2527 if (mode == GRADIENT_FILL_RECT_H)
2529 gradient.p1.y = gradient.p2.y = 0;
2530 if (pt[1].x > pt[0].x)
2532 gradient.p1.x = 0;
2533 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2535 else
2537 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2538 gradient.p2.x = 0;
2541 else
2543 gradient.p1.x = gradient.p2.x = 0;
2544 if (pt[1].y > pt[0].y)
2546 gradient.p1.y = 0;
2547 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2549 else
2551 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2552 gradient.p2.y = 0;
2556 TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2557 mode, pt[0].x, pt[0].y, pt[1].x, pt[1].y,
2558 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2559 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2561 dst_pict = get_xrender_picture( physdev, 0, NULL );
2563 wine_tsx11_lock();
2564 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2565 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2566 0, 0, abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y),
2567 physdev->x11dev->dc_rect.left + min( pt[0].x, pt[1].x ),
2568 physdev->x11dev->dc_rect.top + min( pt[0].y, pt[1].y ),
2569 abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y), 1, 1 );
2570 pXRenderFreePicture( gdi_display, src_pict );
2571 wine_tsx11_unlock();
2573 return TRUE;
2576 fallback:
2577 #endif
2578 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2579 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2582 /***********************************************************************
2583 * xrenderdrv_SelectBrush
2585 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2587 struct xrender_physdev *physdev = get_xrender_dev( dev );
2588 X_PHYSBITMAP *physbitmap;
2589 BOOL delete_bitmap = FALSE;
2590 BITMAP bm;
2591 HBITMAP bitmap;
2592 Pixmap pixmap;
2593 XRenderPictFormat *pict_format;
2594 Picture src_pict, dst_pict;
2595 XRenderPictureAttributes pa;
2597 if (!pattern) goto x11drv_fallback;
2598 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2600 bitmap = pattern->bitmap;
2601 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2603 if (!(bitmap = create_brush_bitmap( physdev->x11dev, pattern ))) return 0;
2604 physbitmap = X11DRV_get_phys_bitmap( bitmap );
2605 delete_bitmap = TRUE;
2608 if (physbitmap->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2609 if (!(pict_format = pict_formats[physbitmap->format])) goto x11drv_fallback;
2611 GetObjectW( bitmap, sizeof(bm), &bm );
2613 wine_tsx11_lock();
2614 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2615 physdev->pict_format->depth );
2617 pa.repeat = RepeatNone;
2618 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_format, CPRepeat, &pa);
2619 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2621 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, bm.bmWidth, bm.bmHeight,
2622 0, 0, bm.bmWidth, bm.bmHeight, 1.0, 1.0 );
2623 pXRenderFreePicture( gdi_display, src_pict );
2624 pXRenderFreePicture( gdi_display, dst_pict );
2626 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2627 physdev->x11dev->brush.pixmap = pixmap;
2628 physdev->x11dev->brush.fillStyle = FillTiled;
2629 physdev->x11dev->brush.pixel = 0; /* ignored */
2630 physdev->x11dev->brush.style = BS_PATTERN;
2631 wine_tsx11_unlock();
2633 if (delete_bitmap) DeleteObject( bitmap );
2634 return hbrush;
2636 x11drv_fallback:
2637 if (delete_bitmap) DeleteObject( bitmap );
2638 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2639 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2643 static const struct gdi_dc_funcs xrender_funcs =
2645 NULL, /* pAbortDoc */
2646 NULL, /* pAbortPath */
2647 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2648 NULL, /* pAngleArc */
2649 NULL, /* pArc */
2650 NULL, /* pArcTo */
2651 NULL, /* pBeginPath */
2652 xrenderdrv_BlendImage, /* pBlendImage */
2653 NULL, /* pChoosePixelFormat */
2654 NULL, /* pChord */
2655 NULL, /* pCloseFigure */
2656 xrenderdrv_CopyBitmap, /* pCopyBitmap */
2657 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2658 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2659 xrenderdrv_CreateDC, /* pCreateDC */
2660 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2661 xrenderdrv_DeleteDC, /* pDeleteDC */
2662 NULL, /* pDeleteObject */
2663 NULL, /* pDescribePixelFormat */
2664 NULL, /* pDeviceCapabilities */
2665 NULL, /* pEllipse */
2666 NULL, /* pEndDoc */
2667 NULL, /* pEndPage */
2668 NULL, /* pEndPath */
2669 NULL, /* pEnumFonts */
2670 NULL, /* pEnumICMProfiles */
2671 NULL, /* pExcludeClipRect */
2672 NULL, /* pExtDeviceMode */
2673 xrenderdrv_ExtEscape, /* pExtEscape */
2674 NULL, /* pExtFloodFill */
2675 NULL, /* pExtSelectClipRgn */
2676 xrenderdrv_ExtTextOut, /* pExtTextOut */
2677 NULL, /* pFillPath */
2678 NULL, /* pFillRgn */
2679 NULL, /* pFlattenPath */
2680 NULL, /* pFontIsLinked */
2681 NULL, /* pFrameRgn */
2682 NULL, /* pGdiComment */
2683 NULL, /* pGdiRealizationInfo */
2684 NULL, /* pGetCharABCWidths */
2685 NULL, /* pGetCharABCWidthsI */
2686 NULL, /* pGetCharWidth */
2687 NULL, /* pGetDeviceCaps */
2688 NULL, /* pGetDeviceGammaRamp */
2689 NULL, /* pGetFontData */
2690 NULL, /* pGetFontUnicodeRanges */
2691 NULL, /* pGetGlyphIndices */
2692 NULL, /* pGetGlyphOutline */
2693 NULL, /* pGetICMProfile */
2694 xrenderdrv_GetImage, /* pGetImage */
2695 NULL, /* pGetKerningPairs */
2696 NULL, /* pGetNearestColor */
2697 NULL, /* pGetOutlineTextMetrics */
2698 NULL, /* pGetPixel */
2699 NULL, /* pGetPixelFormat */
2700 NULL, /* pGetSystemPaletteEntries */
2701 NULL, /* pGetTextCharsetInfo */
2702 NULL, /* pGetTextExtentExPoint */
2703 NULL, /* pGetTextExtentExPointI */
2704 NULL, /* pGetTextFace */
2705 NULL, /* pGetTextMetrics */
2706 xrenderdrv_GradientFill, /* pGradientFill */
2707 NULL, /* pIntersectClipRect */
2708 NULL, /* pInvertRgn */
2709 NULL, /* pLineTo */
2710 NULL, /* pModifyWorldTransform */
2711 NULL, /* pMoveTo */
2712 NULL, /* pOffsetClipRgn */
2713 NULL, /* pOffsetViewportOrg */
2714 NULL, /* pOffsetWindowOrg */
2715 NULL, /* pPaintRgn */
2716 NULL, /* pPatBlt */
2717 NULL, /* pPie */
2718 NULL, /* pPolyBezier */
2719 NULL, /* pPolyBezierTo */
2720 NULL, /* pPolyDraw */
2721 NULL, /* pPolyPolygon */
2722 NULL, /* pPolyPolyline */
2723 NULL, /* pPolygon */
2724 NULL, /* pPolyline */
2725 NULL, /* pPolylineTo */
2726 xrenderdrv_PutImage, /* pPutImage */
2727 NULL, /* pRealizeDefaultPalette */
2728 NULL, /* pRealizePalette */
2729 NULL, /* pRectangle */
2730 NULL, /* pResetDC */
2731 NULL, /* pRestoreDC */
2732 NULL, /* pRoundRect */
2733 NULL, /* pSaveDC */
2734 NULL, /* pScaleViewportExt */
2735 NULL, /* pScaleWindowExt */
2736 xrenderdrv_SelectBitmap, /* pSelectBitmap */
2737 xrenderdrv_SelectBrush, /* pSelectBrush */
2738 NULL, /* pSelectClipPath */
2739 xrenderdrv_SelectFont, /* pSelectFont */
2740 NULL, /* pSelectPalette */
2741 NULL, /* pSelectPen */
2742 NULL, /* pSetArcDirection */
2743 NULL, /* pSetBkColor */
2744 NULL, /* pSetBkMode */
2745 NULL, /* pSetDCBrushColor */
2746 NULL, /* pSetDCPenColor */
2747 NULL, /* pSetDIBitsToDevice */
2748 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2749 NULL, /* pSetDeviceGammaRamp */
2750 NULL, /* pSetLayout */
2751 NULL, /* pSetMapMode */
2752 NULL, /* pSetMapperFlags */
2753 NULL, /* pSetPixel */
2754 NULL, /* pSetPixelFormat */
2755 NULL, /* pSetPolyFillMode */
2756 NULL, /* pSetROP2 */
2757 NULL, /* pSetRelAbs */
2758 NULL, /* pSetStretchBltMode */
2759 NULL, /* pSetTextAlign */
2760 NULL, /* pSetTextCharacterExtra */
2761 NULL, /* pSetTextColor */
2762 NULL, /* pSetTextJustification */
2763 NULL, /* pSetViewportExt */
2764 NULL, /* pSetViewportOrg */
2765 NULL, /* pSetWindowExt */
2766 NULL, /* pSetWindowOrg */
2767 NULL, /* pSetWorldTransform */
2768 NULL, /* pStartDoc */
2769 NULL, /* pStartPage */
2770 xrenderdrv_StretchBlt, /* pStretchBlt */
2771 NULL, /* pStretchDIBits */
2772 NULL, /* pStrokeAndFillPath */
2773 NULL, /* pStrokePath */
2774 NULL, /* pSwapBuffers */
2775 NULL, /* pUnrealizePalette */
2776 NULL, /* pWidenPath */
2777 /* OpenGL not supported */
2780 #else /* SONAME_LIBXRENDER */
2782 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2784 TRACE("XRender support not compiled in.\n");
2785 return NULL;
2788 void X11DRV_XRender_Finalize(void)
2792 #endif /* SONAME_LIBXRENDER */