wineconsole: Fixed a wrong word in message.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blob7c763fca6fcf52dd36d895c22cd06b135c5d2b36
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 if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE && lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
1136 lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
1138 /* Not used fields, would break hashing */
1139 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1141 lfsz_calc_hash(&lfsz);
1143 EnterCriticalSection(&xrender_cs);
1144 if (physdev->cache_index != -1)
1145 dec_ref_cache( physdev->cache_index );
1146 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1147 LeaveCriticalSection(&xrender_cs);
1149 else
1151 EnterCriticalSection( &xrender_cs );
1152 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1153 physdev->cache_index = -1;
1154 LeaveCriticalSection( &xrender_cs );
1156 return ret;
1159 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1161 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1162 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1164 if (!physdev) return FALSE;
1165 physdev->x11dev = x11dev;
1166 physdev->cache_index = -1;
1167 physdev->format = format;
1168 physdev->pict_format = pict_formats[format];
1169 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1170 return TRUE;
1173 /* store the color mask data in the bitmap info structure */
1174 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1176 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1178 info->bmiHeader.biPlanes = 1;
1179 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1180 info->bmiHeader.biCompression = BI_RGB;
1181 info->bmiHeader.biClrUsed = 0;
1183 switch (info->bmiHeader.biBitCount)
1185 case 16:
1186 colors[0] = format->direct.redMask << format->direct.red;
1187 colors[1] = format->direct.greenMask << format->direct.green;
1188 colors[2] = format->direct.blueMask << format->direct.blue;
1189 info->bmiHeader.biCompression = BI_BITFIELDS;
1190 break;
1191 case 32:
1192 colors[0] = format->direct.redMask << format->direct.red;
1193 colors[1] = format->direct.greenMask << format->direct.green;
1194 colors[2] = format->direct.blueMask << format->direct.blue;
1195 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1196 info->bmiHeader.biCompression = BI_BITFIELDS;
1197 break;
1202 /**********************************************************************
1203 * xrenderdrv_CreateDC
1205 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1206 LPCWSTR output, const DEVMODEW* initData )
1208 return create_xrender_dc( pdev, default_format );
1211 /**********************************************************************
1212 * xrenderdrv_CreateCompatibleDC
1214 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1216 if (orig) /* chain to x11drv first */
1218 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1219 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1221 /* otherwise we have been called by x11drv */
1223 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1226 /**********************************************************************
1227 * xrenderdrv_DeleteDC
1229 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1231 struct xrender_physdev *physdev = get_xrender_dev( dev );
1233 free_xrender_picture( physdev );
1235 EnterCriticalSection( &xrender_cs );
1236 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1237 LeaveCriticalSection( &xrender_cs );
1239 HeapFree( GetProcessHeap(), 0, physdev );
1240 return TRUE;
1243 /**********************************************************************
1244 * xrenderdrv_ExtEscape
1246 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1247 INT out_count, LPVOID out_data )
1249 struct xrender_physdev *physdev = get_xrender_dev( dev );
1251 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1253 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1255 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1257 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1258 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1259 return ret;
1262 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1265 /****************************************************************************
1266 * xrenderdrv_CopyBitmap
1268 static BOOL xrenderdrv_CopyBitmap( HBITMAP src, HBITMAP dst )
1270 return X11DRV_CopyBitmap( src, dst );
1273 /****************************************************************************
1274 * xrenderdrv_CreateBitmap
1276 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1278 enum wxr_format format = WXR_INVALID_FORMAT;
1279 X_PHYSBITMAP *phys_bitmap;
1280 BITMAP bitmap;
1282 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1284 if (bitmap.bmBitsPixel == 1)
1286 if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, 1 ))) return FALSE;
1287 phys_bitmap->format = WXR_FORMAT_MONO;
1288 phys_bitmap->trueColor = FALSE;
1290 else
1292 format = get_bitmap_format( bitmap.bmBitsPixel );
1294 if (pict_formats[format])
1296 if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth )))
1297 return FALSE;
1298 phys_bitmap->format = format;
1299 phys_bitmap->trueColor = TRUE;
1300 phys_bitmap->color_shifts = wxr_color_shifts[format];
1302 else
1304 if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, screen_depth )))
1305 return FALSE;
1306 phys_bitmap->format = WXR_INVALID_FORMAT;
1307 phys_bitmap->trueColor = (visual->class == TrueColor || visual->class == DirectColor);
1308 phys_bitmap->color_shifts = X11DRV_PALETTE_default_shifts;
1311 return TRUE;
1314 /****************************************************************************
1315 * xrenderdrv_DeleteBitmap
1317 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1319 return X11DRV_DeleteBitmap( hbitmap );
1322 /***********************************************************************
1323 * xrenderdrv_SelectBitmap
1325 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1327 HBITMAP ret;
1328 struct xrender_physdev *physdev = get_xrender_dev( dev );
1330 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1331 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1332 if (ret)
1334 free_xrender_picture( physdev );
1335 if (hbitmap == BITMAP_stock_phys_bitmap.hbitmap) physdev->format = WXR_FORMAT_MONO;
1336 else physdev->format = X11DRV_get_phys_bitmap(hbitmap)->format;
1337 physdev->pict_format = pict_formats[physdev->format];
1339 return ret;
1342 /***********************************************************************
1343 * xrenderdrv_GetImage
1345 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1346 struct gdi_image_bits *bits, struct bitblt_coords *src )
1348 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1349 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1350 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1353 /***********************************************************************
1354 * xrenderdrv_SetDeviceClipping
1356 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1358 struct xrender_physdev *physdev = get_xrender_dev( dev );
1360 physdev->region = rgn;
1361 physdev->update_clip = TRUE;
1363 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1364 dev->funcs->pSetDeviceClipping( dev, rgn );
1368 /************************************************************************
1369 * UploadGlyph
1371 * Helper to ExtTextOut. Must be called inside xrender_cs
1373 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1375 unsigned int buflen;
1376 char *buf;
1377 Glyph gid;
1378 GLYPHMETRICS gm;
1379 XGlyphInfo gi;
1380 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1381 gsCacheEntryFormat *formatEntry;
1382 UINT ggo_format = GGO_GLYPH_INDEX;
1383 enum wxr_format wxr_format;
1384 static const char zero[4];
1385 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1387 switch(format) {
1388 case AA_Grey:
1389 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1390 break;
1391 case AA_RGB:
1392 ggo_format |= WINE_GGO_HRGB_BITMAP;
1393 break;
1394 case AA_BGR:
1395 ggo_format |= WINE_GGO_HBGR_BITMAP;
1396 break;
1397 case AA_VRGB:
1398 ggo_format |= WINE_GGO_VRGB_BITMAP;
1399 break;
1400 case AA_VBGR:
1401 ggo_format |= WINE_GGO_VBGR_BITMAP;
1402 break;
1404 default:
1405 ERR("aa = %d - not implemented\n", format);
1406 case AA_None:
1407 ggo_format |= GGO_BITMAP;
1408 break;
1411 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1412 if(buflen == GDI_ERROR) {
1413 if(format != AA_None) {
1414 format = AA_None;
1415 entry->aa_default = AA_None;
1416 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1417 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1419 if(buflen == GDI_ERROR) {
1420 WARN("GetGlyphOutlineW failed using default glyph\n");
1421 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1422 if(buflen == GDI_ERROR) {
1423 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1424 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1425 if(buflen == GDI_ERROR) {
1426 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1427 return;
1431 TRACE("Turning off antialiasing for this monochrome font\n");
1434 /* If there is nothing for the current type, we create the entry. */
1435 if( !entry->format[format] ) {
1436 entry->format[format] = HeapAlloc(GetProcessHeap(),
1437 HEAP_ZERO_MEMORY,
1438 sizeof(gsCacheEntryFormat));
1440 formatEntry = entry->format[format];
1442 if(formatEntry->nrealized <= glyph) {
1443 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1445 if (formatEntry->realized)
1446 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1447 HEAP_ZERO_MEMORY,
1448 formatEntry->realized,
1449 formatEntry->nrealized * sizeof(BOOL));
1450 else
1451 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1452 HEAP_ZERO_MEMORY,
1453 formatEntry->nrealized * sizeof(BOOL));
1455 if (formatEntry->gis)
1456 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1457 HEAP_ZERO_MEMORY,
1458 formatEntry->gis,
1459 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1460 else
1461 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1462 HEAP_ZERO_MEMORY,
1463 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1467 if(formatEntry->glyphset == 0) {
1468 switch(format) {
1469 case AA_Grey:
1470 wxr_format = WXR_FORMAT_GRAY;
1471 break;
1473 case AA_RGB:
1474 case AA_BGR:
1475 case AA_VRGB:
1476 case AA_VBGR:
1477 wxr_format = WXR_FORMAT_A8R8G8B8;
1478 break;
1480 default:
1481 ERR("aa = %d - not implemented\n", format);
1482 case AA_None:
1483 wxr_format = WXR_FORMAT_MONO;
1484 break;
1487 wine_tsx11_lock();
1488 formatEntry->font_format = pict_formats[wxr_format];
1489 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1490 wine_tsx11_unlock();
1494 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1495 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1496 formatEntry->realized[glyph] = TRUE;
1498 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1499 buflen,
1500 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1501 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1503 gi.width = gm.gmBlackBoxX;
1504 gi.height = gm.gmBlackBoxY;
1505 gi.x = -gm.gmptGlyphOrigin.x;
1506 gi.y = gm.gmptGlyphOrigin.y;
1507 gi.xOff = gm.gmCellIncX;
1508 gi.yOff = gm.gmCellIncY;
1510 if(TRACE_ON(xrender)) {
1511 int pitch, i, j;
1512 char output[300];
1513 unsigned char *line;
1515 if(format == AA_None) {
1516 pitch = ((gi.width + 31) / 32) * 4;
1517 for(i = 0; i < gi.height; i++) {
1518 line = (unsigned char*) buf + i * pitch;
1519 output[0] = '\0';
1520 for(j = 0; j < pitch * 8; j++) {
1521 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1523 TRACE("%s\n", output);
1525 } else {
1526 static const char blks[] = " .:;!o*#";
1527 char str[2];
1529 str[1] = '\0';
1530 pitch = ((gi.width + 3) / 4) * 4;
1531 for(i = 0; i < gi.height; i++) {
1532 line = (unsigned char*) buf + i * pitch;
1533 output[0] = '\0';
1534 for(j = 0; j < pitch; j++) {
1535 str[0] = blks[line[j] >> 5];
1536 strcat(output, str);
1538 TRACE("%s\n", output);
1544 if(formatEntry->glyphset) {
1545 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1546 unsigned char *byte = (unsigned char*) buf, c;
1547 int i = buflen;
1549 while(i--) {
1550 c = *byte;
1552 /* magic to flip bit order */
1553 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1554 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1555 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1557 *byte++ = c;
1560 else if ( format != AA_Grey &&
1561 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1563 unsigned int i, *data = (unsigned int *)buf;
1564 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1566 gid = glyph;
1569 XRenderCompositeText seems to ignore 0x0 glyphs when
1570 AA_None, which means we lose the advance width of glyphs
1571 like the space. We'll pretend that such glyphs are 1x1
1572 bitmaps.
1575 if(buflen == 0)
1576 gi.width = gi.height = 1;
1578 wine_tsx11_lock();
1579 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1580 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1581 wine_tsx11_unlock();
1582 HeapFree(GetProcessHeap(), 0, buf);
1585 formatEntry->gis[glyph] = gi;
1588 /*************************************************************
1589 * get_tile_pict
1591 * Returns an appropriate Picture for tiling the text colour.
1592 * Call and use result within the xrender_cs
1594 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1596 static struct
1598 Pixmap xpm;
1599 Picture pict;
1600 XRenderColor current_color;
1601 } tiles[WXR_NB_FORMATS], *tile;
1603 tile = &tiles[wxr_format];
1605 if(!tile->xpm)
1607 XRenderPictureAttributes pa;
1608 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1610 wine_tsx11_lock();
1611 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1613 pa.repeat = RepeatNormal;
1614 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1615 wine_tsx11_unlock();
1617 /* init current_color to something different from text_pixel */
1618 tile->current_color = *color;
1619 tile->current_color.red ^= 0xffff;
1621 if (wxr_format == WXR_FORMAT_MONO)
1623 /* for a 1bpp bitmap we always need a 1 in the tile */
1624 XRenderColor col;
1625 col.red = col.green = col.blue = 0;
1626 col.alpha = 0xffff;
1627 wine_tsx11_lock();
1628 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1629 wine_tsx11_unlock();
1633 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1635 wine_tsx11_lock();
1636 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1637 wine_tsx11_unlock();
1638 tile->current_color = *color;
1640 return tile->pict;
1643 /*************************************************************
1644 * get_mask_pict
1646 * Returns an appropriate Picture for masking with the specified alpha.
1647 * Call and use result within the xrender_cs
1649 static Picture get_mask_pict( int alpha )
1651 static Pixmap pixmap;
1652 static Picture pict;
1653 static int current_alpha;
1655 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1657 if (!pixmap)
1659 XRenderPictureAttributes pa;
1661 wine_tsx11_lock();
1662 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1663 pa.repeat = RepeatNormal;
1664 pict = pXRenderCreatePicture( gdi_display, pixmap,
1665 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1666 wine_tsx11_unlock();
1667 current_alpha = -1;
1670 if (alpha != current_alpha)
1672 XRenderColor col;
1673 col.red = col.green = col.blue = 0;
1674 col.alpha = current_alpha = alpha;
1675 wine_tsx11_lock();
1676 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1677 wine_tsx11_unlock();
1679 return pict;
1682 /***********************************************************************
1683 * xrenderdrv_ExtTextOut
1685 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1686 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1688 struct xrender_physdev *physdev = get_xrender_dev( dev );
1689 gsCacheEntry *entry;
1690 gsCacheEntryFormat *formatEntry;
1691 AA_Type aa_type = AA_None;
1692 unsigned int idx;
1693 Picture pict, tile_pict = 0;
1694 XGlyphElt16 *elts;
1695 POINT offset, desired, current;
1696 int render_op = PictOpOver;
1697 XRenderColor col;
1699 if (!physdev->x11dev->has_gdi_font)
1701 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1702 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1705 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1706 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1708 if(flags & ETO_OPAQUE)
1710 XRenderColor bg;
1712 if (physdev->format == WXR_FORMAT_MONO)
1713 /* use the inverse of the text color */
1714 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1715 else
1716 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1718 wine_tsx11_lock();
1719 set_xrender_transformation( pict, 1, 1, 0, 0 );
1720 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1721 physdev->x11dev->dc_rect.left + lprect->left,
1722 physdev->x11dev->dc_rect.top + lprect->top,
1723 lprect->right - lprect->left,
1724 lprect->bottom - lprect->top );
1725 wine_tsx11_unlock();
1728 if(count == 0) return TRUE;
1730 EnterCriticalSection(&xrender_cs);
1732 entry = glyphsetCache + physdev->cache_index;
1733 aa_type = entry->aa_default;
1734 formatEntry = entry->format[aa_type];
1736 for(idx = 0; idx < count; idx++) {
1737 if( !formatEntry ) {
1738 UploadGlyph(physdev, wstr[idx], aa_type);
1739 /* re-evaluate antialias since aa_default may have changed */
1740 aa_type = entry->aa_default;
1741 formatEntry = entry->format[aa_type];
1742 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1743 UploadGlyph(physdev, wstr[idx], aa_type);
1746 if (!formatEntry)
1748 WARN("could not upload requested glyphs\n");
1749 LeaveCriticalSection(&xrender_cs);
1750 return FALSE;
1753 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1754 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1756 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1758 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1759 So we pass zeros to the function and move to our starting position using the first
1760 element of the elts array. */
1762 desired.x = physdev->x11dev->dc_rect.left + x;
1763 desired.y = physdev->x11dev->dc_rect.top + y;
1764 offset.x = offset.y = 0;
1765 current.x = current.y = 0;
1767 tile_pict = get_tile_pict(physdev->format, &col);
1769 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1771 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1772 render_op = PictOpOutReverse; /* This gives us 'black' text */
1774 for(idx = 0; idx < count; idx++)
1776 elts[idx].glyphset = formatEntry->glyphset;
1777 elts[idx].chars = wstr + idx;
1778 elts[idx].nchars = 1;
1779 elts[idx].xOff = desired.x - current.x;
1780 elts[idx].yOff = desired.y - current.y;
1782 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1783 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1785 if(!lpDx)
1787 desired.x += formatEntry->gis[wstr[idx]].xOff;
1788 desired.y += formatEntry->gis[wstr[idx]].yOff;
1790 else
1792 if(flags & ETO_PDY)
1794 offset.x += lpDx[idx * 2];
1795 offset.y += lpDx[idx * 2 + 1];
1797 else
1798 offset.x += lpDx[idx];
1799 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1800 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1804 wine_tsx11_lock();
1805 /* Make sure we don't have any transforms set from a previous call */
1806 set_xrender_transformation(pict, 1, 1, 0, 0);
1807 pXRenderCompositeText16(gdi_display, render_op,
1808 tile_pict,
1809 pict,
1810 formatEntry->font_format,
1811 0, 0, 0, 0, elts, count);
1812 wine_tsx11_unlock();
1813 HeapFree(GetProcessHeap(), 0, elts);
1815 LeaveCriticalSection(&xrender_cs);
1816 return TRUE;
1819 /* multiply the alpha channel of a picture */
1820 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1821 int x, int y, int width, int height )
1823 XRenderPictureAttributes pa;
1824 Pixmap src_pixmap, mask_pixmap;
1825 Picture src_pict, mask_pict;
1826 XRenderColor color;
1828 wine_tsx11_lock();
1829 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1830 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1831 pa.repeat = RepeatNormal;
1832 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1833 pa.component_alpha = True;
1834 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1835 color.red = color.green = color.blue = color.alpha = 0xffff;
1836 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1837 color.alpha = alpha;
1838 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1839 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1840 0, 0, 0, 0, x, y, width, height );
1841 pXRenderFreePicture( gdi_display, src_pict );
1842 pXRenderFreePicture( gdi_display, mask_pict );
1843 XFreePixmap( gdi_display, src_pixmap );
1844 XFreePixmap( gdi_display, mask_pixmap );
1845 wine_tsx11_unlock();
1848 /* Helper function for (stretched) blitting using xrender */
1849 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1850 int x_src, int y_src, int width_src, int height_src,
1851 int x_dst, int y_dst, int width_dst, int height_dst,
1852 double xscale, double yscale )
1854 int x_offset, y_offset;
1856 if (width_src < 0)
1858 x_src += width_src + 1;
1859 width_src = -width_src;
1861 if (height_src < 0)
1863 y_src += height_src + 1;
1864 height_src = -height_src;
1866 if (width_dst < 0)
1868 x_dst += width_dst + 1;
1869 width_dst = -width_dst;
1871 if (height_dst < 0)
1873 y_dst += height_dst + 1;
1874 height_dst = -height_dst;
1877 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1878 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1879 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1880 wine_tsx11_lock();
1881 if(xscale != 1.0 || yscale != 1.0)
1883 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1884 * in the wrong quadrant of the x-y plane.
1886 x_offset = (xscale < 0) ? -width_dst : 0;
1887 y_offset = (yscale < 0) ? -height_dst : 0;
1888 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1890 else
1892 x_offset = x_src;
1893 y_offset = y_src;
1894 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1896 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1897 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1898 wine_tsx11_unlock();
1901 /* Helper function for (stretched) mono->color blitting using xrender */
1902 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1903 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1904 int x_src, int y_src, int width_src, int height_src,
1905 int x_dst, int y_dst, int width_dst, int height_dst,
1906 double xscale, double yscale )
1908 Picture tile_pict;
1909 int x_offset, y_offset;
1910 XRenderColor color;
1912 if (width_src < 0)
1914 x_src += width_src + 1;
1915 width_src = -width_src;
1917 if (height_src < 0)
1919 y_src += height_src + 1;
1920 height_src = -height_src;
1922 if (width_dst < 0)
1924 x_dst += width_dst + 1;
1925 width_dst = -width_dst;
1927 if (height_dst < 0)
1929 y_dst += height_dst + 1;
1930 height_dst = -height_dst;
1933 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1934 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1935 * the tile data.
1937 EnterCriticalSection( &xrender_cs );
1938 color = *bg;
1939 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1940 tile_pict = get_tile_pict( dst_format, &color );
1942 wine_tsx11_lock();
1943 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1945 if (xscale != 1.0 || yscale != 1.0)
1947 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1948 * in the wrong quadrant of the x-y plane.
1950 x_offset = (xscale < 0) ? -width_dst : 0;
1951 y_offset = (yscale < 0) ? -height_dst : 0;
1952 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1954 else
1956 x_offset = x_src;
1957 y_offset = y_src;
1958 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1960 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1961 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1962 wine_tsx11_unlock();
1963 LeaveCriticalSection( &xrender_cs );
1965 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1966 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1967 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1968 x_dst, y_dst, width_dst, height_dst );
1971 /* create a pixmap and render picture for an image */
1972 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1973 struct bitblt_coords *src, enum wxr_format format,
1974 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1976 DWORD ret;
1977 int width = src->visrect.right - src->visrect.left;
1978 int height = src->visrect.bottom - src->visrect.top;
1979 int depth = pict_formats[format]->depth;
1980 struct gdi_image_bits dst_bits;
1981 XRenderPictureAttributes pa;
1982 XImage *image;
1984 wine_tsx11_lock();
1985 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1986 info->bmiHeader.biWidth, height, 32, 0 );
1987 wine_tsx11_unlock();
1988 if (!image) return ERROR_OUTOFMEMORY;
1990 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1991 if (ret) return ret;
1993 image->data = dst_bits.ptr;
1995 *use_repeat = (width == 1 && height == 1);
1996 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1998 wine_tsx11_lock();
1999 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2000 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2001 src->visrect.left, 0, 0, 0, width, height );
2002 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2003 wine_tsx11_unlock();
2005 /* make coordinates relative to the pixmap */
2006 src->x -= src->visrect.left;
2007 src->y -= src->visrect.top;
2008 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2010 image->data = NULL;
2011 wine_tsx11_lock();
2012 XDestroyImage( image );
2013 wine_tsx11_unlock();
2014 if (dst_bits.free) dst_bits.free( &dst_bits );
2015 return ret;
2018 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2019 Drawable drawable, const struct bitblt_coords *src,
2020 const struct bitblt_coords *dst )
2022 int x_dst, y_dst;
2023 Picture src_pict = 0, dst_pict, mask_pict = 0;
2024 BOOL use_repeat;
2025 double xscale, yscale;
2027 use_repeat = use_source_repeat( physdev_src );
2028 if (!use_repeat)
2030 xscale = src->width / (double)dst->width;
2031 yscale = src->height / (double)dst->height;
2033 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2035 if (drawable) /* using an intermediate pixmap */
2037 XRenderPictureAttributes pa;
2039 x_dst = dst->x;
2040 y_dst = dst->y;
2041 pa.repeat = RepeatNone;
2042 wine_tsx11_lock();
2043 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2044 wine_tsx11_unlock();
2046 else
2048 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2049 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2050 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2053 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2055 /* mono -> color */
2056 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2058 XRenderColor fg, bg;
2060 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
2061 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
2062 fg.alpha = bg.alpha = 0;
2064 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2065 physdev_src->x11dev->dc_rect.left + src->x,
2066 physdev_src->x11dev->dc_rect.top + src->y,
2067 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2069 else /* color -> color (can be at different depths) or mono -> mono */
2071 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
2072 mask_pict = get_no_alpha_mask();
2074 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2075 physdev_src->x11dev->dc_rect.left + src->x,
2076 physdev_src->x11dev->dc_rect.top + src->y,
2077 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2080 if (drawable)
2082 wine_tsx11_lock();
2083 pXRenderFreePicture( gdi_display, dst_pict );
2084 wine_tsx11_unlock();
2089 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2090 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2091 Drawable drawable, struct bitblt_coords *src,
2092 struct bitblt_coords *dst, BOOL use_repeat )
2094 int x_dst, y_dst;
2095 Picture dst_pict;
2096 XRenderPictureAttributes pa;
2097 double xscale, yscale;
2099 if (drawable) /* using an intermediate pixmap */
2101 RGNDATA *clip_data = NULL;
2103 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2104 x_dst = dst->x;
2105 y_dst = dst->y;
2106 pa.repeat = RepeatNone;
2107 wine_tsx11_lock();
2108 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2109 if (clip_data)
2110 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2111 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2112 wine_tsx11_unlock();
2113 HeapFree( GetProcessHeap(), 0, clip_data );
2115 else
2117 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2118 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2119 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2122 if (!use_repeat)
2124 xscale = src->width / (double)dst->width;
2125 yscale = src->height / (double)dst->height;
2127 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2129 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
2130 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2132 if (drawable)
2134 wine_tsx11_lock();
2135 pXRenderFreePicture( gdi_display, dst_pict );
2136 wine_tsx11_unlock();
2141 /***********************************************************************
2142 * xrenderdrv_StretchBlt
2144 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2145 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2147 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2148 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2149 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2151 if (src_dev->funcs != dst_dev->funcs)
2153 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2154 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2157 /* XRender is of no use for color -> mono */
2158 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2159 goto x11drv_fallback;
2161 /* if not stretching, we only need to handle format conversion */
2162 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2164 if (rop != SRCCOPY)
2166 GC tmpGC;
2167 Pixmap tmp_pixmap;
2168 struct bitblt_coords tmp;
2170 /* make coordinates relative to tmp pixmap */
2171 tmp = *dst;
2172 tmp.x -= tmp.visrect.left;
2173 tmp.y -= tmp.visrect.top;
2174 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2176 wine_tsx11_lock();
2177 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2178 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2179 XSetGraphicsExposures( gdi_display, tmpGC, False );
2180 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2181 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
2182 wine_tsx11_unlock();
2184 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2185 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2187 wine_tsx11_lock();
2188 XFreePixmap( gdi_display, tmp_pixmap );
2189 XFreeGC( gdi_display, tmpGC );
2190 wine_tsx11_unlock();
2192 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2194 return TRUE;
2196 x11drv_fallback:
2197 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2201 /***********************************************************************
2202 * xrenderdrv_PutImage
2204 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2205 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2206 struct bitblt_coords *dst, DWORD rop )
2208 struct xrender_physdev *physdev;
2209 X_PHYSBITMAP *bitmap;
2210 DWORD ret;
2211 Pixmap tmp_pixmap;
2212 GC gc;
2213 enum wxr_format src_format, dst_format;
2214 XRenderPictFormat *pict_format;
2215 Pixmap src_pixmap;
2216 Picture src_pict, mask_pict = 0;
2217 BOOL use_repeat;
2219 if (hbitmap)
2221 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2222 physdev = NULL;
2223 dst_format = bitmap->format;
2225 else
2227 physdev = get_xrender_dev( dev );
2228 bitmap = NULL;
2229 dst_format = physdev->format;
2232 src_format = get_xrender_format_from_bitmapinfo( info );
2233 if (!(pict_format = pict_formats[src_format])) goto update_format;
2235 /* make sure we can create an image with the same bpp */
2236 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2237 goto update_format;
2239 /* mono <-> color conversions not supported */
2240 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2241 goto x11drv_fallback;
2243 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2245 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2247 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2248 if (!ret)
2250 struct bitblt_coords tmp;
2252 if (bitmap)
2254 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2255 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2257 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2258 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2259 DeleteObject( rgn );
2261 else
2263 if (rop != SRCCOPY)
2265 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2267 /* make coordinates relative to tmp pixmap */
2268 tmp = *dst;
2269 tmp.x -= tmp.visrect.left;
2270 tmp.y -= tmp.visrect.top;
2271 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2273 wine_tsx11_lock();
2274 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2275 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2276 XSetGraphicsExposures( gdi_display, gc, False );
2277 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2278 tmp.visrect.right - tmp.visrect.left,
2279 tmp.visrect.bottom - tmp.visrect.top,
2280 physdev->pict_format->depth );
2281 wine_tsx11_unlock();
2283 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2284 NULL, tmp_pixmap, src, &tmp, use_repeat );
2285 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2287 wine_tsx11_lock();
2288 XFreePixmap( gdi_display, tmp_pixmap );
2289 XFreeGC( gdi_display, gc );
2290 wine_tsx11_unlock();
2292 if (restore_region) restore_clipping_region( physdev->x11dev );
2294 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2295 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2298 wine_tsx11_lock();
2299 pXRenderFreePicture( gdi_display, src_pict );
2300 XFreePixmap( gdi_display, src_pixmap );
2301 wine_tsx11_unlock();
2303 return ret;
2305 update_format:
2306 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2307 set_color_info( pict_formats[dst_format], info );
2308 return ERROR_BAD_FORMAT;
2310 x11drv_fallback:
2311 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2312 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2313 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2317 /***********************************************************************
2318 * xrenderdrv_BlendImage
2320 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2321 struct bitblt_coords *src, struct bitblt_coords *dst,
2322 BLENDFUNCTION func )
2324 struct xrender_physdev *physdev = get_xrender_dev( dev );
2325 DWORD ret;
2326 enum wxr_format format;
2327 XRenderPictFormat *pict_format;
2328 Picture dst_pict, src_pict, mask_pict;
2329 Pixmap src_pixmap;
2330 BOOL use_repeat;
2332 format = get_xrender_format_from_bitmapinfo( info );
2333 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2334 format = get_format_without_alpha( format );
2335 else if (format != WXR_FORMAT_A8R8G8B8)
2336 return ERROR_INVALID_PARAMETER;
2338 if (!(pict_format = pict_formats[format])) goto update_format;
2340 /* make sure we can create an image with the same bpp */
2341 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2342 goto update_format;
2344 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2345 goto update_format;
2347 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2349 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2350 if (!ret)
2352 double xscale, yscale;
2354 if (!use_repeat)
2356 xscale = src->width / (double)dst->width;
2357 yscale = src->height / (double)dst->height;
2359 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2361 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2363 EnterCriticalSection( &xrender_cs );
2364 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2366 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2367 src->x, src->y, src->width, src->height,
2368 physdev->x11dev->dc_rect.left + dst->x,
2369 physdev->x11dev->dc_rect.top + dst->y,
2370 dst->width, dst->height, xscale, yscale );
2372 wine_tsx11_lock();
2373 pXRenderFreePicture( gdi_display, src_pict );
2374 XFreePixmap( gdi_display, src_pixmap );
2375 wine_tsx11_unlock();
2377 LeaveCriticalSection( &xrender_cs );
2379 return ret;
2381 update_format:
2382 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2383 set_color_info( physdev->pict_format, info );
2384 return ERROR_BAD_FORMAT;
2388 /***********************************************************************
2389 * xrenderdrv_AlphaBlend
2391 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2392 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2394 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2395 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2396 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2397 XRenderPictureAttributes pa;
2398 Pixmap tmp_pixmap = 0;
2399 double xscale, yscale;
2400 BOOL use_repeat;
2402 if (src_dev->funcs != dst_dev->funcs)
2404 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2405 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2408 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2410 SetLastError( ERROR_INVALID_PARAMETER );
2411 return FALSE;
2414 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2416 use_repeat = use_source_repeat( physdev_src );
2417 if (!use_repeat)
2419 xscale = src->width / (double)dst->width;
2420 yscale = src->height / (double)dst->height;
2422 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2424 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2426 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2428 /* mono -> color blending needs an intermediate color pixmap */
2429 XRenderColor fg, bg;
2430 int width = src->visrect.right - src->visrect.left;
2431 int height = src->visrect.bottom - src->visrect.top;
2433 /* blending doesn't use the destination DC colors */
2434 fg.red = fg.green = fg.blue = 0;
2435 bg.red = bg.green = bg.blue = 0xffff;
2436 fg.alpha = bg.alpha = 0xffff;
2438 wine_tsx11_lock();
2439 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2440 physdev_dst->pict_format->depth );
2441 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2442 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2443 CPRepeat, &pa );
2444 wine_tsx11_unlock();
2446 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2447 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
2449 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2451 /* we need a source picture with no alpha */
2452 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2453 if (format != physdev_src->format)
2455 wine_tsx11_lock();
2456 pa.subwindow_mode = IncludeInferiors;
2457 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2458 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2459 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2460 wine_tsx11_unlock();
2464 if (tmp_pict) src_pict = tmp_pict;
2466 EnterCriticalSection( &xrender_cs );
2467 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2469 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2470 physdev_src->x11dev->dc_rect.left + src->x,
2471 physdev_src->x11dev->dc_rect.top + src->y,
2472 src->width, src->height,
2473 physdev_dst->x11dev->dc_rect.left + dst->x,
2474 physdev_dst->x11dev->dc_rect.top + dst->y,
2475 dst->width, dst->height, xscale, yscale );
2477 wine_tsx11_lock();
2478 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2479 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2480 wine_tsx11_unlock();
2482 LeaveCriticalSection( &xrender_cs );
2483 return TRUE;
2486 /***********************************************************************
2487 * xrenderdrv_GradientFill
2489 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2490 void * grad_array, ULONG ngrad, ULONG mode )
2492 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2493 static const XFixed stops[2] = { 0, 1 << 16 };
2494 struct xrender_physdev *physdev = get_xrender_dev( dev );
2495 XLinearGradient gradient;
2496 XRenderColor colors[2];
2497 Picture src_pict, dst_pict;
2498 unsigned int i;
2499 const GRADIENT_RECT *rect = grad_array;
2500 POINT pt[2];
2502 if (!pXRenderCreateLinearGradient) goto fallback;
2504 /* <= 16-bpp uses dithering */
2505 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2507 switch (mode)
2509 case GRADIENT_FILL_RECT_H:
2510 case GRADIENT_FILL_RECT_V:
2511 for (i = 0; i < ngrad; i++, rect++)
2513 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2514 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2516 colors[0].red = v1->Red * 257 / 256;
2517 colors[0].green = v1->Green * 257 / 256;
2518 colors[0].blue = v1->Blue * 257 / 256;
2519 colors[1].red = v2->Red * 257 / 256;
2520 colors[1].green = v2->Green * 257 / 256;
2521 colors[1].blue = v2->Blue * 257 / 256;
2522 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2523 colors[0].alpha = colors[1].alpha = 65535;
2525 pt[0].x = v1->x;
2526 pt[0].y = v1->y;
2527 pt[1].x = v2->x;
2528 pt[1].y = v2->y;
2529 LPtoDP( dev->hdc, pt, 2 );
2530 if (mode == GRADIENT_FILL_RECT_H)
2532 gradient.p1.y = gradient.p2.y = 0;
2533 if (pt[1].x > pt[0].x)
2535 gradient.p1.x = 0;
2536 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2538 else
2540 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2541 gradient.p2.x = 0;
2544 else
2546 gradient.p1.x = gradient.p2.x = 0;
2547 if (pt[1].y > pt[0].y)
2549 gradient.p1.y = 0;
2550 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2552 else
2554 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2555 gradient.p2.y = 0;
2559 TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2560 mode, pt[0].x, pt[0].y, pt[1].x, pt[1].y,
2561 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2562 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2564 dst_pict = get_xrender_picture( physdev, 0, NULL );
2566 wine_tsx11_lock();
2567 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2568 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2569 0, 0, abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y),
2570 physdev->x11dev->dc_rect.left + min( pt[0].x, pt[1].x ),
2571 physdev->x11dev->dc_rect.top + min( pt[0].y, pt[1].y ),
2572 abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y), 1, 1 );
2573 pXRenderFreePicture( gdi_display, src_pict );
2574 wine_tsx11_unlock();
2576 return TRUE;
2579 fallback:
2580 #endif
2581 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2582 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2585 /***********************************************************************
2586 * xrenderdrv_SelectBrush
2588 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2590 struct xrender_physdev *physdev = get_xrender_dev( dev );
2591 X_PHYSBITMAP *physbitmap;
2592 BOOL delete_bitmap = FALSE;
2593 BITMAP bm;
2594 HBITMAP bitmap;
2595 Pixmap pixmap;
2596 XRenderPictFormat *pict_format;
2597 Picture src_pict, dst_pict;
2598 XRenderPictureAttributes pa;
2600 if (!pattern) goto x11drv_fallback;
2601 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2603 bitmap = pattern->bitmap;
2604 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2606 if (!(bitmap = create_brush_bitmap( physdev->x11dev, pattern ))) return 0;
2607 physbitmap = X11DRV_get_phys_bitmap( bitmap );
2608 delete_bitmap = TRUE;
2611 if (physbitmap->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2612 if (!(pict_format = pict_formats[physbitmap->format])) goto x11drv_fallback;
2614 GetObjectW( bitmap, sizeof(bm), &bm );
2616 wine_tsx11_lock();
2617 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2618 physdev->pict_format->depth );
2620 pa.repeat = RepeatNone;
2621 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_format, CPRepeat, &pa);
2622 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2624 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, bm.bmWidth, bm.bmHeight,
2625 0, 0, bm.bmWidth, bm.bmHeight, 1.0, 1.0 );
2626 pXRenderFreePicture( gdi_display, src_pict );
2627 pXRenderFreePicture( gdi_display, dst_pict );
2629 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2630 physdev->x11dev->brush.pixmap = pixmap;
2631 physdev->x11dev->brush.fillStyle = FillTiled;
2632 physdev->x11dev->brush.pixel = 0; /* ignored */
2633 physdev->x11dev->brush.style = BS_PATTERN;
2634 wine_tsx11_unlock();
2636 if (delete_bitmap) DeleteObject( bitmap );
2637 return hbrush;
2639 x11drv_fallback:
2640 if (delete_bitmap) DeleteObject( bitmap );
2641 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2642 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2646 static const struct gdi_dc_funcs xrender_funcs =
2648 NULL, /* pAbortDoc */
2649 NULL, /* pAbortPath */
2650 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2651 NULL, /* pAngleArc */
2652 NULL, /* pArc */
2653 NULL, /* pArcTo */
2654 NULL, /* pBeginPath */
2655 xrenderdrv_BlendImage, /* pBlendImage */
2656 NULL, /* pChoosePixelFormat */
2657 NULL, /* pChord */
2658 NULL, /* pCloseFigure */
2659 xrenderdrv_CopyBitmap, /* pCopyBitmap */
2660 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2661 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2662 xrenderdrv_CreateDC, /* pCreateDC */
2663 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2664 xrenderdrv_DeleteDC, /* pDeleteDC */
2665 NULL, /* pDeleteObject */
2666 NULL, /* pDescribePixelFormat */
2667 NULL, /* pDeviceCapabilities */
2668 NULL, /* pEllipse */
2669 NULL, /* pEndDoc */
2670 NULL, /* pEndPage */
2671 NULL, /* pEndPath */
2672 NULL, /* pEnumFonts */
2673 NULL, /* pEnumICMProfiles */
2674 NULL, /* pExcludeClipRect */
2675 NULL, /* pExtDeviceMode */
2676 xrenderdrv_ExtEscape, /* pExtEscape */
2677 NULL, /* pExtFloodFill */
2678 NULL, /* pExtSelectClipRgn */
2679 xrenderdrv_ExtTextOut, /* pExtTextOut */
2680 NULL, /* pFillPath */
2681 NULL, /* pFillRgn */
2682 NULL, /* pFlattenPath */
2683 NULL, /* pFontIsLinked */
2684 NULL, /* pFrameRgn */
2685 NULL, /* pGdiComment */
2686 NULL, /* pGdiRealizationInfo */
2687 NULL, /* pGetCharABCWidths */
2688 NULL, /* pGetCharABCWidthsI */
2689 NULL, /* pGetCharWidth */
2690 NULL, /* pGetDeviceCaps */
2691 NULL, /* pGetDeviceGammaRamp */
2692 NULL, /* pGetFontData */
2693 NULL, /* pGetFontUnicodeRanges */
2694 NULL, /* pGetGlyphIndices */
2695 NULL, /* pGetGlyphOutline */
2696 NULL, /* pGetICMProfile */
2697 xrenderdrv_GetImage, /* pGetImage */
2698 NULL, /* pGetKerningPairs */
2699 NULL, /* pGetNearestColor */
2700 NULL, /* pGetOutlineTextMetrics */
2701 NULL, /* pGetPixel */
2702 NULL, /* pGetPixelFormat */
2703 NULL, /* pGetSystemPaletteEntries */
2704 NULL, /* pGetTextCharsetInfo */
2705 NULL, /* pGetTextExtentExPoint */
2706 NULL, /* pGetTextExtentExPointI */
2707 NULL, /* pGetTextFace */
2708 NULL, /* pGetTextMetrics */
2709 xrenderdrv_GradientFill, /* pGradientFill */
2710 NULL, /* pIntersectClipRect */
2711 NULL, /* pInvertRgn */
2712 NULL, /* pLineTo */
2713 NULL, /* pModifyWorldTransform */
2714 NULL, /* pMoveTo */
2715 NULL, /* pOffsetClipRgn */
2716 NULL, /* pOffsetViewportOrg */
2717 NULL, /* pOffsetWindowOrg */
2718 NULL, /* pPaintRgn */
2719 NULL, /* pPatBlt */
2720 NULL, /* pPie */
2721 NULL, /* pPolyBezier */
2722 NULL, /* pPolyBezierTo */
2723 NULL, /* pPolyDraw */
2724 NULL, /* pPolyPolygon */
2725 NULL, /* pPolyPolyline */
2726 NULL, /* pPolygon */
2727 NULL, /* pPolyline */
2728 NULL, /* pPolylineTo */
2729 xrenderdrv_PutImage, /* pPutImage */
2730 NULL, /* pRealizeDefaultPalette */
2731 NULL, /* pRealizePalette */
2732 NULL, /* pRectangle */
2733 NULL, /* pResetDC */
2734 NULL, /* pRestoreDC */
2735 NULL, /* pRoundRect */
2736 NULL, /* pSaveDC */
2737 NULL, /* pScaleViewportExt */
2738 NULL, /* pScaleWindowExt */
2739 xrenderdrv_SelectBitmap, /* pSelectBitmap */
2740 xrenderdrv_SelectBrush, /* pSelectBrush */
2741 NULL, /* pSelectClipPath */
2742 xrenderdrv_SelectFont, /* pSelectFont */
2743 NULL, /* pSelectPalette */
2744 NULL, /* pSelectPen */
2745 NULL, /* pSetArcDirection */
2746 NULL, /* pSetBkColor */
2747 NULL, /* pSetBkMode */
2748 NULL, /* pSetDCBrushColor */
2749 NULL, /* pSetDCPenColor */
2750 NULL, /* pSetDIBitsToDevice */
2751 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2752 NULL, /* pSetDeviceGammaRamp */
2753 NULL, /* pSetLayout */
2754 NULL, /* pSetMapMode */
2755 NULL, /* pSetMapperFlags */
2756 NULL, /* pSetPixel */
2757 NULL, /* pSetPixelFormat */
2758 NULL, /* pSetPolyFillMode */
2759 NULL, /* pSetROP2 */
2760 NULL, /* pSetRelAbs */
2761 NULL, /* pSetStretchBltMode */
2762 NULL, /* pSetTextAlign */
2763 NULL, /* pSetTextCharacterExtra */
2764 NULL, /* pSetTextColor */
2765 NULL, /* pSetTextJustification */
2766 NULL, /* pSetViewportExt */
2767 NULL, /* pSetViewportOrg */
2768 NULL, /* pSetWindowExt */
2769 NULL, /* pSetWindowOrg */
2770 NULL, /* pSetWorldTransform */
2771 NULL, /* pStartDoc */
2772 NULL, /* pStartPage */
2773 xrenderdrv_StretchBlt, /* pStretchBlt */
2774 NULL, /* pStretchDIBits */
2775 NULL, /* pStrokeAndFillPath */
2776 NULL, /* pStrokePath */
2777 NULL, /* pSwapBuffers */
2778 NULL, /* pUnrealizePalette */
2779 NULL, /* pWidenPath */
2780 /* OpenGL not supported */
2783 #else /* SONAME_LIBXRENDER */
2785 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2787 TRACE("XRender support not compiled in.\n");
2788 return NULL;
2791 void X11DRV_XRender_Finalize(void)
2795 #endif /* SONAME_LIBXRENDER */