winex11: Allow the visible region to be zero when not clipping.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blobd81130da24822a2d8dd7f298a7783a7e116334ee
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 static BOOL X11DRV_XRender_Installed = FALSE;
51 #include <X11/Xlib.h>
52 #include <X11/extensions/Xrender.h>
54 #ifndef RepeatNone /* added in 0.10 */
55 #define RepeatNone 0
56 #define RepeatNormal 1
57 #define RepeatPad 2
58 #define RepeatReflect 3
59 #endif
61 enum wxr_format
63 WXR_FORMAT_MONO,
64 WXR_FORMAT_GRAY,
65 WXR_FORMAT_X1R5G5B5,
66 WXR_FORMAT_X1B5G5R5,
67 WXR_FORMAT_R5G6B5,
68 WXR_FORMAT_B5G6R5,
69 WXR_FORMAT_R8G8B8,
70 WXR_FORMAT_B8G8R8,
71 WXR_FORMAT_A8R8G8B8,
72 WXR_FORMAT_B8G8R8A8,
73 WXR_FORMAT_X8R8G8B8,
74 WXR_FORMAT_B8G8R8X8,
75 WXR_NB_FORMATS,
76 WXR_INVALID_FORMAT = WXR_NB_FORMATS
79 typedef struct wine_xrender_format_template
81 unsigned int depth;
82 unsigned int alpha;
83 unsigned int alphaMask;
84 unsigned int red;
85 unsigned int redMask;
86 unsigned int green;
87 unsigned int greenMask;
88 unsigned int blue;
89 unsigned int blueMask;
90 } WineXRenderFormatTemplate;
92 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
94 /* Format depth alpha mask red mask green mask blue mask*/
95 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
96 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
97 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
98 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
99 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
100 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
101 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
103 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
105 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
106 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
109 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
111 /* format phys red phys green phys blue log red log green log blue */
112 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
113 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
114 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
115 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
116 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
117 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
118 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
120 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
122 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
123 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
126 static enum wxr_format default_format = WXR_INVALID_FORMAT;
127 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
129 typedef struct
131 LOGFONTW lf;
132 XFORM xform;
133 SIZE devsize; /* size in device coords */
134 DWORD hash;
135 } LFANDSIZE;
137 #define INITIAL_REALIZED_BUF_SIZE 128
139 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
141 typedef struct
143 GlyphSet glyphset;
144 XRenderPictFormat *font_format;
145 int nrealized;
146 BOOL *realized;
147 XGlyphInfo *gis;
148 } gsCacheEntryFormat;
150 typedef struct
152 LFANDSIZE lfsz;
153 AA_Type aa_default;
154 gsCacheEntryFormat * format[AA_MAXVALUE];
155 INT count;
156 INT next;
157 } gsCacheEntry;
159 struct xrender_physdev
161 struct gdi_physdev dev;
162 X11DRV_PDEVICE *x11dev;
163 enum wxr_format format;
164 int cache_index;
165 BOOL update_clip;
166 Picture pict;
167 Picture pict_src;
168 XRenderPictFormat *pict_format;
171 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
173 return (struct xrender_physdev *)dev;
176 static const struct gdi_dc_funcs xrender_funcs;
178 static gsCacheEntry *glyphsetCache = NULL;
179 static DWORD glyphsetCacheSize = 0;
180 static INT lastfree = -1;
181 static INT mru = -1;
183 #define INIT_CACHE_SIZE 10
185 static int antialias = 1;
187 static void *xrender_handle;
189 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
190 MAKE_FUNCPTR(XRenderAddGlyphs)
191 MAKE_FUNCPTR(XRenderChangePicture)
192 MAKE_FUNCPTR(XRenderComposite)
193 MAKE_FUNCPTR(XRenderCompositeText16)
194 MAKE_FUNCPTR(XRenderCreateGlyphSet)
195 MAKE_FUNCPTR(XRenderCreatePicture)
196 MAKE_FUNCPTR(XRenderFillRectangle)
197 MAKE_FUNCPTR(XRenderFindFormat)
198 MAKE_FUNCPTR(XRenderFindVisualFormat)
199 MAKE_FUNCPTR(XRenderFreeGlyphSet)
200 MAKE_FUNCPTR(XRenderFreePicture)
201 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
202 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
203 MAKE_FUNCPTR(XRenderCreateLinearGradient)
204 #endif
205 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
206 MAKE_FUNCPTR(XRenderSetPictureTransform)
207 #endif
208 MAKE_FUNCPTR(XRenderQueryExtension)
210 #ifdef SONAME_LIBFONTCONFIG
211 #include <fontconfig/fontconfig.h>
212 MAKE_FUNCPTR(FcConfigSubstitute)
213 MAKE_FUNCPTR(FcDefaultSubstitute)
214 MAKE_FUNCPTR(FcFontMatch)
215 MAKE_FUNCPTR(FcInit)
216 MAKE_FUNCPTR(FcPatternCreate)
217 MAKE_FUNCPTR(FcPatternDestroy)
218 MAKE_FUNCPTR(FcPatternAddInteger)
219 MAKE_FUNCPTR(FcPatternAddString)
220 MAKE_FUNCPTR(FcPatternGetBool)
221 MAKE_FUNCPTR(FcPatternGetInteger)
222 MAKE_FUNCPTR(FcPatternGetString)
223 static void *fontconfig_handle;
224 static BOOL fontconfig_installed;
225 #endif
227 #undef MAKE_FUNCPTR
229 static CRITICAL_SECTION xrender_cs;
230 static CRITICAL_SECTION_DEBUG critsect_debug =
232 0, 0, &xrender_cs,
233 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
234 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
236 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
238 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
239 ( ( (ULONG)_x4 << 24 ) | \
240 ( (ULONG)_x3 << 16 ) | \
241 ( (ULONG)_x2 << 8 ) | \
242 (ULONG)_x1 )
244 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
246 #define GASP_GRIDFIT 0x01
247 #define GASP_DOGRAY 0x02
249 #ifdef WORDS_BIGENDIAN
250 #define get_be_word(x) (x)
251 #define NATIVE_BYTE_ORDER MSBFirst
252 #else
253 #define get_be_word(x) RtlUshortByteSwap(x)
254 #define NATIVE_BYTE_ORDER LSBFirst
255 #endif
257 static BOOL has_alpha( enum wxr_format format )
259 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
262 static enum wxr_format get_format_without_alpha( enum wxr_format format )
264 switch (format)
266 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
267 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
268 default: return format;
272 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
274 templ->id = 0;
275 templ->type = PictTypeDirect;
276 templ->depth = fmt->depth;
277 templ->direct.alpha = fmt->alpha;
278 templ->direct.alphaMask = fmt->alphaMask;
279 templ->direct.red = fmt->red;
280 templ->direct.redMask = fmt->redMask;
281 templ->direct.green = fmt->green;
282 templ->direct.greenMask = fmt->greenMask;
283 templ->direct.blue = fmt->blue;
284 templ->direct.blueMask = fmt->blueMask;
285 templ->colormap = 0;
287 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
289 return TRUE;
292 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
294 if(fmt->depth != screen_depth)
295 return FALSE;
296 if( (fmt->redMask << fmt->red) != visual->red_mask)
297 return FALSE;
298 if( (fmt->greenMask << fmt->green) != visual->green_mask)
299 return FALSE;
300 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
301 return FALSE;
303 /* We never select a default ARGB visual */
304 if(fmt->alphaMask)
305 return FALSE;
307 return TRUE;
310 static int load_xrender_formats(void)
312 int count = 0;
313 unsigned int i;
315 for (i = 0; i < WXR_NB_FORMATS; i++)
317 XRenderPictFormat templ;
319 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
321 wine_tsx11_lock();
322 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
323 if (!pict_formats[i])
325 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
326 if (visual->class == DirectColor)
328 XVisualInfo info;
329 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
330 screen_depth, TrueColor, &info ))
332 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
333 if (pict_formats[i]) visual = info.visual;
337 wine_tsx11_unlock();
338 if (pict_formats[i]) default_format = i;
340 else
342 unsigned long mask = 0;
343 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
345 wine_tsx11_lock();
346 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
347 wine_tsx11_unlock();
349 if (pict_formats[i])
351 count++;
352 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
355 return count;
358 /***********************************************************************
359 * X11DRV_XRender_Init
361 * Let's see if our XServer has the extension available
364 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
366 int event_base, i;
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 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
399 wine_tsx11_unlock();
400 if (!X11DRV_XRender_Installed) 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 X11DRV_XRender_Installed = FALSE;
409 return NULL;
412 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask)
414 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
415 X11DRV_XRender_Installed = FALSE;
416 return NULL;
419 #ifdef SONAME_LIBFONTCONFIG
420 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
422 #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;}
423 LOAD_FUNCPTR(FcConfigSubstitute);
424 LOAD_FUNCPTR(FcDefaultSubstitute);
425 LOAD_FUNCPTR(FcFontMatch);
426 LOAD_FUNCPTR(FcInit);
427 LOAD_FUNCPTR(FcPatternCreate);
428 LOAD_FUNCPTR(FcPatternDestroy);
429 LOAD_FUNCPTR(FcPatternAddInteger);
430 LOAD_FUNCPTR(FcPatternAddString);
431 LOAD_FUNCPTR(FcPatternGetBool);
432 LOAD_FUNCPTR(FcPatternGetInteger);
433 LOAD_FUNCPTR(FcPatternGetString);
434 #undef LOAD_FUNCPTR
435 fontconfig_installed = pFcInit();
437 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
439 sym_not_found:
440 #endif
442 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
443 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
445 glyphsetCacheSize = INIT_CACHE_SIZE;
446 lastfree = 0;
447 for(i = 0; i < INIT_CACHE_SIZE; i++) {
448 glyphsetCache[i].next = i + 1;
449 glyphsetCache[i].count = -1;
451 glyphsetCache[i-1].next = -1;
453 if(screen_depth <= 8 || !client_side_antialias_with_render) antialias = 0;
455 return &xrender_funcs;
458 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
459 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
461 if(pf->direct.redMask)
462 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
463 else
464 dst_color->red = 0;
466 if(pf->direct.greenMask)
467 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
468 else
469 dst_color->green = 0;
471 if(pf->direct.blueMask)
472 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
473 else
474 dst_color->blue = 0;
476 dst_color->alpha = 0xffff;
479 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
481 int redMask, greenMask, blueMask;
482 unsigned int i;
484 if (depth == 1) return WXR_FORMAT_MONO;
486 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
487 if (!shifts) return default_format;
489 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
490 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
491 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
493 /* Try to locate a format which matches the specification of the dibsection. */
494 for(i = 0; i < WXR_NB_FORMATS; i++)
496 if( depth == wxr_formats_template[i].depth &&
497 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
498 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
499 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
500 return i;
503 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
504 ERR("No XRender format found for %u %08x/%08x/%08x\n", depth, redMask, greenMask, blueMask);
505 return WXR_INVALID_FORMAT;
508 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
510 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
512 switch (info->bmiHeader.biBitCount)
514 case 1:
515 return WXR_FORMAT_MONO;
516 case 4:
517 case 8:
518 break;
519 case 24:
520 if (info->bmiHeader.biCompression != BI_RGB) break;
521 return WXR_FORMAT_R8G8B8;
522 case 16:
523 case 32:
524 if (info->bmiHeader.biCompression == BI_BITFIELDS)
526 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
527 unsigned int i;
529 for (i = 0; i < WXR_NB_FORMATS; i++)
531 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
532 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
533 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
534 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
535 return i;
537 break;
539 if (info->bmiHeader.biCompression != BI_RGB) break;
540 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
542 return WXR_INVALID_FORMAT;
545 static enum wxr_format get_bitmap_format( int bpp )
547 enum wxr_format format = WXR_INVALID_FORMAT;
549 if (bpp == screen_bpp)
551 switch (bpp)
553 case 16: format = WXR_FORMAT_R5G6B5; break;
554 case 24: format = WXR_FORMAT_R8G8B8; break;
555 case 32: format = WXR_FORMAT_A8R8G8B8; break;
558 return format;
561 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
562 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
564 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
565 XTransform xform = {{
566 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
567 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
568 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
571 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
572 #endif
575 /* check if we can use repeating instead of scaling for the specified source DC */
576 static BOOL use_source_repeat( struct xrender_physdev *dev )
578 return (dev->x11dev->bitmap &&
579 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
580 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
583 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
585 XRenderPictureAttributes pa;
586 RGNDATA *data;
588 if (!rgn)
590 wine_tsx11_lock();
591 pa.clip_mask = None;
592 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
593 wine_tsx11_unlock();
595 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
597 wine_tsx11_lock();
598 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
599 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
600 (XRectangle *)data->Buffer, data->rdh.nCount );
601 wine_tsx11_unlock();
602 HeapFree( GetProcessHeap(), 0, data );
607 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
609 if (!dev->pict && dev->pict_format)
611 XRenderPictureAttributes pa;
613 wine_tsx11_lock();
614 pa.subwindow_mode = IncludeInferiors;
615 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
616 dev->pict_format, CPSubwindowMode, &pa );
617 wine_tsx11_unlock();
618 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
619 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
620 dev->update_clip = (dev->x11dev->region != 0);
623 if (clip_rect)
625 HRGN rgn = CreateRectRgnIndirect( clip_rect );
626 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
627 if (dev->x11dev->region) CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
628 update_xrender_clipping( dev, rgn );
629 DeleteObject( rgn );
631 else if (clip_rgn)
633 if (dev->x11dev->region)
635 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
636 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
637 update_xrender_clipping( dev, rgn );
638 DeleteObject( rgn );
640 else update_xrender_clipping( dev, clip_rgn );
642 else if (dev->update_clip) update_xrender_clipping( dev, dev->x11dev->region );
644 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
645 return dev->pict;
648 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
650 if (!dev->pict_src && dev->pict_format)
652 XRenderPictureAttributes pa;
654 wine_tsx11_lock();
655 pa.subwindow_mode = IncludeInferiors;
656 pa.repeat = repeat ? RepeatNormal : RepeatNone;
657 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
658 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
659 wine_tsx11_unlock();
661 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
662 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
665 return dev->pict_src;
668 static void free_xrender_picture( struct xrender_physdev *dev )
670 if (dev->pict || dev->pict_src)
672 wine_tsx11_lock();
673 XFlush( gdi_display );
674 if (dev->pict)
676 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
677 pXRenderFreePicture(gdi_display, dev->pict);
678 dev->pict = 0;
680 if(dev->pict_src)
682 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
683 pXRenderFreePicture(gdi_display, dev->pict_src);
684 dev->pict_src = 0;
686 wine_tsx11_unlock();
690 /* return a mask picture used to force alpha to 0 */
691 static Picture get_no_alpha_mask(void)
693 static Pixmap pixmap;
694 static Picture pict;
696 wine_tsx11_lock();
697 if (!pict)
699 XRenderPictureAttributes pa;
700 XRenderColor col;
702 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
703 pa.repeat = RepeatNormal;
704 pa.component_alpha = True;
705 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
706 CPRepeat|CPComponentAlpha, &pa );
707 col.red = col.green = col.blue = 0xffff;
708 col.alpha = 0;
709 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
711 wine_tsx11_unlock();
712 return pict;
715 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
717 if(p1->hash != p2->hash) return TRUE;
718 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
719 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
720 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
721 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
724 #if 0
725 static void walk_cache(void)
727 int i;
729 EnterCriticalSection(&xrender_cs);
730 for(i=mru; i >= 0; i = glyphsetCache[i].next)
731 TRACE("item %d\n", i);
732 LeaveCriticalSection(&xrender_cs);
734 #endif
736 static int LookupEntry(LFANDSIZE *plfsz)
738 int i, prev_i = -1;
740 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
741 TRACE("%d\n", i);
742 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
744 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
745 glyphsetCache[i].count++;
746 if(prev_i >= 0) {
747 glyphsetCache[prev_i].next = glyphsetCache[i].next;
748 glyphsetCache[i].next = mru;
749 mru = i;
751 TRACE("found font in cache %d\n", i);
752 return i;
754 prev_i = i;
756 TRACE("font not in cache\n");
757 return -1;
760 static void FreeEntry(int entry)
762 int format;
764 for(format = 0; format < AA_MAXVALUE; format++) {
765 gsCacheEntryFormat * formatEntry;
767 if( !glyphsetCache[entry].format[format] )
768 continue;
770 formatEntry = glyphsetCache[entry].format[format];
772 if(formatEntry->glyphset) {
773 wine_tsx11_lock();
774 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
775 wine_tsx11_unlock();
776 formatEntry->glyphset = 0;
778 if(formatEntry->nrealized) {
779 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
780 formatEntry->realized = NULL;
781 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
782 formatEntry->gis = NULL;
783 formatEntry->nrealized = 0;
786 HeapFree(GetProcessHeap(), 0, formatEntry);
787 glyphsetCache[entry].format[format] = NULL;
791 static int AllocEntry(void)
793 int best = -1, prev_best = -1, i, prev_i = -1;
795 if(lastfree >= 0) {
796 assert(glyphsetCache[lastfree].count == -1);
797 glyphsetCache[lastfree].count = 1;
798 best = lastfree;
799 lastfree = glyphsetCache[lastfree].next;
800 assert(best != mru);
801 glyphsetCache[best].next = mru;
802 mru = best;
804 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
805 return mru;
808 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
809 if(glyphsetCache[i].count == 0) {
810 best = i;
811 prev_best = prev_i;
813 prev_i = i;
816 if(best >= 0) {
817 TRACE("freeing unused glyphset at cache %d\n", best);
818 FreeEntry(best);
819 glyphsetCache[best].count = 1;
820 if(prev_best >= 0) {
821 glyphsetCache[prev_best].next = glyphsetCache[best].next;
822 glyphsetCache[best].next = mru;
823 mru = best;
824 } else {
825 assert(mru == best);
827 return mru;
830 TRACE("Growing cache\n");
832 if (glyphsetCache)
833 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
834 glyphsetCache,
835 (glyphsetCacheSize + INIT_CACHE_SIZE)
836 * sizeof(*glyphsetCache));
837 else
838 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
839 (glyphsetCacheSize + INIT_CACHE_SIZE)
840 * sizeof(*glyphsetCache));
842 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
843 i++) {
844 glyphsetCache[i].next = i + 1;
845 glyphsetCache[i].count = -1;
847 glyphsetCache[i-1].next = -1;
848 glyphsetCacheSize += INIT_CACHE_SIZE;
850 lastfree = glyphsetCache[best].next;
851 glyphsetCache[best].count = 1;
852 glyphsetCache[best].next = mru;
853 mru = best;
854 TRACE("new free cache slot at %d\n", mru);
855 return mru;
858 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
860 DWORD size;
861 WORD *gasp, *buffer;
862 WORD num_recs;
863 DWORD ppem;
864 TEXTMETRICW tm;
866 *flags = 0;
868 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
869 if(size == GDI_ERROR)
870 return FALSE;
872 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
873 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
875 GetTextMetricsW(hdc, &tm);
876 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
878 gasp++;
879 num_recs = get_be_word(*gasp);
880 gasp++;
881 while(num_recs--)
883 *flags = get_be_word(*(gasp + 1));
884 if(ppem <= get_be_word(*gasp))
885 break;
886 gasp += 2;
888 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
890 HeapFree(GetProcessHeap(), 0, buffer);
891 return TRUE;
894 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
896 AA_Type ret;
897 WORD flags;
898 UINT font_smoothing_type, font_smoothing_orientation;
900 if (X11DRV_XRender_Installed && subpixel &&
901 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
902 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
904 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
905 &font_smoothing_orientation, 0) &&
906 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
908 ret = AA_BGR;
910 else
911 ret = AA_RGB;
912 /*FIXME
913 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
914 But, Wine's subpixel rendering can support the portrait mode.
917 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
918 ret = AA_Grey;
919 else
920 ret = AA_None;
922 return ret;
925 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
927 int ret;
928 int format;
929 gsCacheEntry *entry;
930 static int hinter = -1;
931 static int subpixel = -1;
932 BOOL font_smoothing;
934 if((ret = LookupEntry(plfsz)) != -1) return ret;
936 ret = AllocEntry();
937 entry = glyphsetCache + ret;
938 entry->lfsz = *plfsz;
939 for( format = 0; format < AA_MAXVALUE; format++ ) {
940 assert( !entry->format[format] );
943 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
945 if(hinter == -1 || subpixel == -1)
947 RASTERIZER_STATUS status;
948 GetRasterizerCaps(&status, sizeof(status));
949 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
950 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
953 switch (plfsz->lf.lfQuality)
955 case ANTIALIASED_QUALITY:
956 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
957 return ret; /* ignore further configuration */
958 case CLEARTYPE_QUALITY:
959 case CLEARTYPE_NATURAL_QUALITY:
960 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
961 break;
962 case DEFAULT_QUALITY:
963 case DRAFT_QUALITY:
964 case PROOF_QUALITY:
965 default:
966 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
967 font_smoothing)
969 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
971 else
972 entry->aa_default = AA_None;
973 break;
976 font_smoothing = TRUE; /* default to enabled */
977 #ifdef SONAME_LIBFONTCONFIG
978 if (fontconfig_installed)
980 FcPattern *match, *pattern;
981 FcResult result;
982 char family[LF_FACESIZE * 4];
984 #if defined(__i386__) && defined(__GNUC__)
985 /* fontconfig generates floating point exceptions, mask them */
986 WORD cw, default_cw = 0x37f;
987 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
988 #endif
990 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
991 pattern = pFcPatternCreate();
992 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
993 if (plfsz->lf.lfWeight != FW_DONTCARE)
995 int weight;
996 switch (plfsz->lf.lfWeight)
998 case FW_THIN: weight = FC_WEIGHT_THIN; break;
999 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
1000 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
1001 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
1002 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
1003 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
1004 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
1005 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
1006 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
1007 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
1009 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
1011 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
1012 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1013 pFcDefaultSubstitute( pattern );
1014 if ((match = pFcFontMatch( NULL, pattern, &result )))
1016 int rgba;
1017 FcBool antialias;
1019 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
1020 antialias = TRUE;
1021 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
1023 FcChar8 *file;
1024 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
1026 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
1027 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
1029 switch (rgba)
1031 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1032 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1033 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1034 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1035 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1038 if (!antialias) font_smoothing = FALSE;
1039 pFcPatternDestroy( match );
1041 pFcPatternDestroy( pattern );
1043 #if defined(__i386__) && defined(__GNUC__)
1044 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
1045 #endif
1047 #endif /* SONAME_LIBFONTCONFIG */
1049 /* now check Xft resources */
1051 char *value;
1052 BOOL antialias = TRUE;
1054 wine_tsx11_lock();
1055 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1057 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1058 value[0] == '0' || !strcasecmp( value, "off" ))
1059 antialias = FALSE;
1061 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1063 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1064 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1065 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1066 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1067 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1068 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1070 wine_tsx11_unlock();
1071 if (!antialias) font_smoothing = FALSE;
1074 if (!font_smoothing) entry->aa_default = AA_None;
1076 /* we can't support subpixel without xrender */
1077 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1079 else
1080 entry->aa_default = AA_None;
1082 return ret;
1085 static void dec_ref_cache(int index)
1087 assert(index >= 0);
1088 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1089 assert(glyphsetCache[index].count > 0);
1090 glyphsetCache[index].count--;
1093 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1095 DWORD hash = 0, *ptr, two_chars;
1096 WORD *pwc;
1097 int i;
1099 hash ^= plfsz->devsize.cx;
1100 hash ^= plfsz->devsize.cy;
1101 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1102 hash ^= *ptr;
1103 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1104 hash ^= *ptr;
1105 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1106 two_chars = *ptr;
1107 pwc = (WCHAR *)&two_chars;
1108 if(!*pwc) break;
1109 *pwc = toupperW(*pwc);
1110 pwc++;
1111 *pwc = toupperW(*pwc);
1112 hash ^= two_chars;
1113 if(!*pwc) break;
1115 plfsz->hash = hash;
1116 return;
1119 /***********************************************************************
1120 * X11DRV_XRender_Finalize
1122 void X11DRV_XRender_Finalize(void)
1124 int i;
1126 EnterCriticalSection(&xrender_cs);
1127 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1128 FreeEntry(i);
1129 LeaveCriticalSection(&xrender_cs);
1130 DeleteCriticalSection(&xrender_cs);
1133 /**********************************************************************
1134 * xrenderdrv_SelectFont
1136 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1138 struct xrender_physdev *physdev = get_xrender_dev( dev );
1139 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1140 HFONT ret = next->funcs->pSelectFont( next, hfont );
1142 if (!ret) return 0;
1144 if (physdev->x11dev->has_gdi_font)
1146 LFANDSIZE lfsz;
1148 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1150 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1151 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1152 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1153 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1154 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1155 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1157 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1158 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1159 lfsz.xform.eM21, lfsz.xform.eM22);
1161 /* Not used fields, would break hashing */
1162 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1164 lfsz_calc_hash(&lfsz);
1166 EnterCriticalSection(&xrender_cs);
1167 if (physdev->cache_index != -1)
1168 dec_ref_cache( physdev->cache_index );
1169 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1170 LeaveCriticalSection(&xrender_cs);
1172 else
1174 EnterCriticalSection( &xrender_cs );
1175 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1176 physdev->cache_index = -1;
1177 LeaveCriticalSection( &xrender_cs );
1179 return ret;
1182 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1184 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1185 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1187 if (!physdev) return FALSE;
1188 physdev->x11dev = x11dev;
1189 physdev->cache_index = -1;
1190 physdev->format = format;
1191 physdev->pict_format = pict_formats[format];
1192 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1193 return TRUE;
1196 /* store the color mask data in the bitmap info structure */
1197 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1199 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1201 info->bmiHeader.biPlanes = 1;
1202 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1203 info->bmiHeader.biCompression = BI_RGB;
1204 info->bmiHeader.biClrUsed = 0;
1206 switch (info->bmiHeader.biBitCount)
1208 case 16:
1209 colors[0] = format->direct.redMask << format->direct.red;
1210 colors[1] = format->direct.greenMask << format->direct.green;
1211 colors[2] = format->direct.blueMask << format->direct.blue;
1212 info->bmiHeader.biCompression = BI_BITFIELDS;
1213 break;
1214 case 32:
1215 colors[0] = format->direct.redMask << format->direct.red;
1216 colors[1] = format->direct.greenMask << format->direct.green;
1217 colors[2] = format->direct.blueMask << format->direct.blue;
1218 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1219 info->bmiHeader.biCompression = BI_BITFIELDS;
1220 break;
1225 /**********************************************************************
1226 * xrenderdrv_CreateDC
1228 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1229 LPCWSTR output, const DEVMODEW* initData )
1231 return create_xrender_dc( pdev, default_format );
1234 /**********************************************************************
1235 * xrenderdrv_CreateCompatibleDC
1237 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1239 if (orig) /* chain to x11drv first */
1241 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1242 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1244 /* otherwise we have been called by x11drv */
1246 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1249 /**********************************************************************
1250 * xrenderdrv_DeleteDC
1252 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1254 struct xrender_physdev *physdev = get_xrender_dev( dev );
1256 free_xrender_picture( physdev );
1258 EnterCriticalSection( &xrender_cs );
1259 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1260 LeaveCriticalSection( &xrender_cs );
1262 HeapFree( GetProcessHeap(), 0, physdev );
1263 return TRUE;
1266 /**********************************************************************
1267 * xrenderdrv_ExtEscape
1269 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1270 INT out_count, LPVOID out_data )
1272 struct xrender_physdev *physdev = get_xrender_dev( dev );
1274 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1276 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1278 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1280 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1281 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1282 return ret;
1285 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1288 /****************************************************************************
1289 * xrenderdrv_CopyBitmap
1291 static BOOL xrenderdrv_CopyBitmap( HBITMAP src, HBITMAP dst )
1293 return X11DRV_CopyBitmap( src, dst );
1296 /****************************************************************************
1297 * xrenderdrv_CreateBitmap
1299 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1301 enum wxr_format format;
1302 BITMAP bitmap;
1304 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1306 if (bitmap.bmPlanes != 1) return FALSE;
1307 format = get_bitmap_format( bitmap.bmBitsPixel );
1309 if (pict_formats[format])
1310 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1311 TRUE, &wxr_color_shifts[format] );
1313 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1314 return dev->funcs->pCreateBitmap( dev, hbitmap );
1317 /****************************************************************************
1318 * xrenderdrv_DeleteBitmap
1320 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1322 return X11DRV_DeleteBitmap( hbitmap );
1325 /***********************************************************************
1326 * xrenderdrv_SelectBitmap
1328 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1330 HBITMAP ret;
1331 struct xrender_physdev *physdev = get_xrender_dev( dev );
1333 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1334 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1335 if (ret)
1337 free_xrender_picture( physdev );
1338 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1339 physdev->x11dev->color_shifts );
1340 physdev->pict_format = pict_formats[physdev->format];
1342 return ret;
1345 /***********************************************************************
1346 * xrenderdrv_GetImage
1348 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1349 struct gdi_image_bits *bits, struct bitblt_coords *src )
1351 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1352 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1353 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1356 /***********************************************************************
1357 * xrenderdrv_SetDeviceClipping
1359 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1361 struct xrender_physdev *physdev = get_xrender_dev( dev );
1363 physdev->update_clip = TRUE;
1365 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1366 dev->funcs->pSetDeviceClipping( dev, rgn );
1370 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1372 XRenderPictFormat *pict_format;
1373 ColorShifts shifts;
1374 const DWORD *bitfields;
1375 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1376 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1379 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1380 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1381 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1382 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1383 return FALSE;
1385 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1386 bitfields = dib->dsBitfields;
1387 else if(bits_pixel == 24 || bits_pixel == 32)
1388 bitfields = bitfields_32;
1389 else
1390 bitfields = bitfields_16;
1392 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1393 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1395 /* Common formats should be in our picture format table. */
1396 if (!pict_format)
1398 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1399 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1400 return FALSE;
1403 physBitmap->depth = pict_format->depth;
1404 physBitmap->trueColor = TRUE;
1405 physBitmap->color_shifts = shifts;
1406 return TRUE;
1409 /************************************************************************
1410 * UploadGlyph
1412 * Helper to ExtTextOut. Must be called inside xrender_cs
1414 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1416 unsigned int buflen;
1417 char *buf;
1418 Glyph gid;
1419 GLYPHMETRICS gm;
1420 XGlyphInfo gi;
1421 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1422 gsCacheEntryFormat *formatEntry;
1423 UINT ggo_format = GGO_GLYPH_INDEX;
1424 enum wxr_format wxr_format;
1425 static const char zero[4];
1426 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1428 switch(format) {
1429 case AA_Grey:
1430 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1431 break;
1432 case AA_RGB:
1433 ggo_format |= WINE_GGO_HRGB_BITMAP;
1434 break;
1435 case AA_BGR:
1436 ggo_format |= WINE_GGO_HBGR_BITMAP;
1437 break;
1438 case AA_VRGB:
1439 ggo_format |= WINE_GGO_VRGB_BITMAP;
1440 break;
1441 case AA_VBGR:
1442 ggo_format |= WINE_GGO_VBGR_BITMAP;
1443 break;
1445 default:
1446 ERR("aa = %d - not implemented\n", format);
1447 case AA_None:
1448 ggo_format |= GGO_BITMAP;
1449 break;
1452 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1453 if(buflen == GDI_ERROR) {
1454 if(format != AA_None) {
1455 format = AA_None;
1456 entry->aa_default = AA_None;
1457 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1458 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1460 if(buflen == GDI_ERROR) {
1461 WARN("GetGlyphOutlineW failed using default glyph\n");
1462 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1463 if(buflen == GDI_ERROR) {
1464 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1465 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1466 if(buflen == GDI_ERROR) {
1467 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1468 return;
1472 TRACE("Turning off antialiasing for this monochrome font\n");
1475 /* If there is nothing for the current type, we create the entry. */
1476 if( !entry->format[format] ) {
1477 entry->format[format] = HeapAlloc(GetProcessHeap(),
1478 HEAP_ZERO_MEMORY,
1479 sizeof(gsCacheEntryFormat));
1481 formatEntry = entry->format[format];
1483 if(formatEntry->nrealized <= glyph) {
1484 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1486 if (formatEntry->realized)
1487 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1488 HEAP_ZERO_MEMORY,
1489 formatEntry->realized,
1490 formatEntry->nrealized * sizeof(BOOL));
1491 else
1492 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1493 HEAP_ZERO_MEMORY,
1494 formatEntry->nrealized * sizeof(BOOL));
1496 if (formatEntry->gis)
1497 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1498 HEAP_ZERO_MEMORY,
1499 formatEntry->gis,
1500 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1501 else
1502 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1503 HEAP_ZERO_MEMORY,
1504 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1508 if(formatEntry->glyphset == 0) {
1509 switch(format) {
1510 case AA_Grey:
1511 wxr_format = WXR_FORMAT_GRAY;
1512 break;
1514 case AA_RGB:
1515 case AA_BGR:
1516 case AA_VRGB:
1517 case AA_VBGR:
1518 wxr_format = WXR_FORMAT_A8R8G8B8;
1519 break;
1521 default:
1522 ERR("aa = %d - not implemented\n", format);
1523 case AA_None:
1524 wxr_format = WXR_FORMAT_MONO;
1525 break;
1528 wine_tsx11_lock();
1529 formatEntry->font_format = pict_formats[wxr_format];
1530 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1531 wine_tsx11_unlock();
1535 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1536 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1537 formatEntry->realized[glyph] = TRUE;
1539 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1540 buflen,
1541 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1542 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1544 gi.width = gm.gmBlackBoxX;
1545 gi.height = gm.gmBlackBoxY;
1546 gi.x = -gm.gmptGlyphOrigin.x;
1547 gi.y = gm.gmptGlyphOrigin.y;
1548 gi.xOff = gm.gmCellIncX;
1549 gi.yOff = gm.gmCellIncY;
1551 if(TRACE_ON(xrender)) {
1552 int pitch, i, j;
1553 char output[300];
1554 unsigned char *line;
1556 if(format == AA_None) {
1557 pitch = ((gi.width + 31) / 32) * 4;
1558 for(i = 0; i < gi.height; i++) {
1559 line = (unsigned char*) buf + i * pitch;
1560 output[0] = '\0';
1561 for(j = 0; j < pitch * 8; j++) {
1562 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1564 TRACE("%s\n", output);
1566 } else {
1567 static const char blks[] = " .:;!o*#";
1568 char str[2];
1570 str[1] = '\0';
1571 pitch = ((gi.width + 3) / 4) * 4;
1572 for(i = 0; i < gi.height; i++) {
1573 line = (unsigned char*) buf + i * pitch;
1574 output[0] = '\0';
1575 for(j = 0; j < pitch; j++) {
1576 str[0] = blks[line[j] >> 5];
1577 strcat(output, str);
1579 TRACE("%s\n", output);
1585 if(formatEntry->glyphset) {
1586 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1587 unsigned char *byte = (unsigned char*) buf, c;
1588 int i = buflen;
1590 while(i--) {
1591 c = *byte;
1593 /* magic to flip bit order */
1594 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1595 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1596 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1598 *byte++ = c;
1601 else if ( format != AA_Grey &&
1602 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1604 unsigned int i, *data = (unsigned int *)buf;
1605 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1607 gid = glyph;
1610 XRenderCompositeText seems to ignore 0x0 glyphs when
1611 AA_None, which means we lose the advance width of glyphs
1612 like the space. We'll pretend that such glyphs are 1x1
1613 bitmaps.
1616 if(buflen == 0)
1617 gi.width = gi.height = 1;
1619 wine_tsx11_lock();
1620 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1621 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1622 wine_tsx11_unlock();
1623 HeapFree(GetProcessHeap(), 0, buf);
1626 formatEntry->gis[glyph] = gi;
1629 /*************************************************************
1630 * get_tile_pict
1632 * Returns an appropriate Picture for tiling the text colour.
1633 * Call and use result within the xrender_cs
1635 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1637 static struct
1639 Pixmap xpm;
1640 Picture pict;
1641 XRenderColor current_color;
1642 } tiles[WXR_NB_FORMATS], *tile;
1644 tile = &tiles[wxr_format];
1646 if(!tile->xpm)
1648 XRenderPictureAttributes pa;
1649 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1651 wine_tsx11_lock();
1652 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1654 pa.repeat = RepeatNormal;
1655 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1656 wine_tsx11_unlock();
1658 /* init current_color to something different from text_pixel */
1659 tile->current_color = *color;
1660 tile->current_color.red ^= 0xffff;
1662 if (wxr_format == WXR_FORMAT_MONO)
1664 /* for a 1bpp bitmap we always need a 1 in the tile */
1665 XRenderColor col;
1666 col.red = col.green = col.blue = 0;
1667 col.alpha = 0xffff;
1668 wine_tsx11_lock();
1669 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1670 wine_tsx11_unlock();
1674 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1676 wine_tsx11_lock();
1677 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1678 wine_tsx11_unlock();
1679 tile->current_color = *color;
1681 return tile->pict;
1684 /*************************************************************
1685 * get_mask_pict
1687 * Returns an appropriate Picture for masking with the specified alpha.
1688 * Call and use result within the xrender_cs
1690 static Picture get_mask_pict( int alpha )
1692 static Pixmap pixmap;
1693 static Picture pict;
1694 static int current_alpha;
1696 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1698 if (!pixmap)
1700 XRenderPictureAttributes pa;
1702 wine_tsx11_lock();
1703 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1704 pa.repeat = RepeatNormal;
1705 pict = pXRenderCreatePicture( gdi_display, pixmap,
1706 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1707 wine_tsx11_unlock();
1708 current_alpha = -1;
1711 if (alpha != current_alpha)
1713 XRenderColor col;
1714 col.red = col.green = col.blue = 0;
1715 col.alpha = current_alpha = alpha;
1716 wine_tsx11_lock();
1717 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1718 wine_tsx11_unlock();
1720 return pict;
1723 /***********************************************************************
1724 * xrenderdrv_ExtTextOut
1726 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1727 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1729 struct xrender_physdev *physdev = get_xrender_dev( dev );
1730 XGCValues xgcval;
1731 gsCacheEntry *entry;
1732 gsCacheEntryFormat *formatEntry;
1733 int textPixel, backgroundPixel;
1734 AA_Type aa_type = AA_None;
1735 unsigned int idx;
1736 Picture pict, tile_pict = 0;
1737 XGlyphElt16 *elts;
1738 POINT offset, desired, current;
1739 int render_op = PictOpOver;
1740 XRenderColor col;
1742 if (!X11DRV_XRender_Installed || !physdev->x11dev->has_gdi_font)
1744 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1745 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1748 xgcval.function = GXcopy;
1749 xgcval.background = physdev->x11dev->backgroundPixel;
1750 xgcval.fill_style = FillSolid;
1751 wine_tsx11_lock();
1752 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1753 wine_tsx11_unlock();
1755 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1757 if(physdev->x11dev->depth == 1) {
1758 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1759 textPixel = 0;
1760 backgroundPixel = 1;
1761 } else {
1762 textPixel = 1;
1763 backgroundPixel = 0;
1765 } else {
1766 textPixel = physdev->x11dev->textPixel;
1767 backgroundPixel = physdev->x11dev->backgroundPixel;
1770 if(flags & ETO_OPAQUE)
1772 wine_tsx11_lock();
1773 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
1774 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
1775 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
1776 lprect->right - lprect->left, lprect->bottom - lprect->top );
1777 wine_tsx11_unlock();
1780 if(count == 0)
1782 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1783 return TRUE;
1786 EnterCriticalSection(&xrender_cs);
1788 entry = glyphsetCache + physdev->cache_index;
1789 aa_type = entry->aa_default;
1790 formatEntry = entry->format[aa_type];
1792 for(idx = 0; idx < count; idx++) {
1793 if( !formatEntry ) {
1794 UploadGlyph(physdev, wstr[idx], aa_type);
1795 /* re-evaluate antialias since aa_default may have changed */
1796 aa_type = entry->aa_default;
1797 formatEntry = entry->format[aa_type];
1798 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1799 UploadGlyph(physdev, wstr[idx], aa_type);
1802 if (!formatEntry)
1804 WARN("could not upload requested glyphs\n");
1805 LeaveCriticalSection(&xrender_cs);
1806 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1807 return FALSE;
1810 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1811 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1813 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1814 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1816 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1817 So we pass zeros to the function and move to our starting position using the first
1818 element of the elts array. */
1820 desired.x = physdev->x11dev->dc_rect.left + x;
1821 desired.y = physdev->x11dev->dc_rect.top + y;
1822 offset.x = offset.y = 0;
1823 current.x = current.y = 0;
1825 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
1826 tile_pict = get_tile_pict(physdev->format, &col);
1828 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1830 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
1831 render_op = PictOpOutReverse; /* This gives us 'black' text */
1833 for(idx = 0; idx < count; idx++)
1835 elts[idx].glyphset = formatEntry->glyphset;
1836 elts[idx].chars = wstr + idx;
1837 elts[idx].nchars = 1;
1838 elts[idx].xOff = desired.x - current.x;
1839 elts[idx].yOff = desired.y - current.y;
1841 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1842 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1844 if(!lpDx)
1846 desired.x += formatEntry->gis[wstr[idx]].xOff;
1847 desired.y += formatEntry->gis[wstr[idx]].yOff;
1849 else
1851 if(flags & ETO_PDY)
1853 offset.x += lpDx[idx * 2];
1854 offset.y += lpDx[idx * 2 + 1];
1856 else
1857 offset.x += lpDx[idx];
1858 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1859 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1863 wine_tsx11_lock();
1864 /* Make sure we don't have any transforms set from a previous call */
1865 set_xrender_transformation(pict, 1, 1, 0, 0);
1866 pXRenderCompositeText16(gdi_display, render_op,
1867 tile_pict,
1868 pict,
1869 formatEntry->font_format,
1870 0, 0, 0, 0, elts, count);
1871 wine_tsx11_unlock();
1872 HeapFree(GetProcessHeap(), 0, elts);
1874 LeaveCriticalSection(&xrender_cs);
1875 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1876 return TRUE;
1879 /* multiply the alpha channel of a picture */
1880 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1881 int x, int y, int width, int height )
1883 XRenderPictureAttributes pa;
1884 Pixmap src_pixmap, mask_pixmap;
1885 Picture src_pict, mask_pict;
1886 XRenderColor color;
1888 wine_tsx11_lock();
1889 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1890 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1891 pa.repeat = RepeatNormal;
1892 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1893 pa.component_alpha = True;
1894 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1895 color.red = color.green = color.blue = color.alpha = 0xffff;
1896 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1897 color.alpha = alpha;
1898 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1899 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1900 0, 0, 0, 0, x, y, width, height );
1901 pXRenderFreePicture( gdi_display, src_pict );
1902 pXRenderFreePicture( gdi_display, mask_pict );
1903 XFreePixmap( gdi_display, src_pixmap );
1904 XFreePixmap( gdi_display, mask_pixmap );
1905 wine_tsx11_unlock();
1908 /* Helper function for (stretched) blitting using xrender */
1909 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1910 int x_src, int y_src, int x_dst, int y_dst,
1911 double xscale, double yscale, int width, int height )
1913 int x_offset, y_offset;
1915 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1916 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1917 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1918 wine_tsx11_lock();
1919 if(xscale != 1.0 || yscale != 1.0)
1921 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1922 * in the wrong quadrant of the x-y plane.
1924 x_offset = (xscale < 0) ? -width : 0;
1925 y_offset = (yscale < 0) ? -height : 0;
1926 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1928 else
1930 x_offset = x_src;
1931 y_offset = y_src;
1932 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1934 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1935 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
1936 wine_tsx11_unlock();
1939 /* Helper function for (stretched) mono->color blitting using xrender */
1940 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1941 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1942 int x_src, int y_src, int x_dst, int y_dst,
1943 double xscale, double yscale, int width, int height )
1945 Picture tile_pict;
1946 int x_offset, y_offset;
1947 XRenderColor color;
1949 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1950 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1951 * the tile data.
1953 EnterCriticalSection( &xrender_cs );
1954 color = *bg;
1955 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1956 tile_pict = get_tile_pict( dst_format, &color );
1958 wine_tsx11_lock();
1959 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
1961 if (xscale != 1.0 || yscale != 1.0)
1963 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1964 * in the wrong quadrant of the x-y plane.
1966 x_offset = (xscale < 0) ? -width : 0;
1967 y_offset = (yscale < 0) ? -height : 0;
1968 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1970 else
1972 x_offset = x_src;
1973 y_offset = y_src;
1974 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1976 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1977 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
1978 wine_tsx11_unlock();
1979 LeaveCriticalSection( &xrender_cs );
1981 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1982 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1983 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
1986 /* create a pixmap and render picture for an image */
1987 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1988 struct bitblt_coords *src, enum wxr_format format,
1989 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1991 DWORD ret;
1992 int width = src->visrect.right - src->visrect.left;
1993 int height = src->visrect.bottom - src->visrect.top;
1994 int depth = pict_formats[format]->depth;
1995 struct gdi_image_bits dst_bits;
1996 XRenderPictureAttributes pa;
1997 XImage *image;
1999 wine_tsx11_lock();
2000 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2001 info->bmiHeader.biWidth, height, 32, 0 );
2002 wine_tsx11_unlock();
2003 if (!image) return ERROR_OUTOFMEMORY;
2005 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2006 if (ret) return ret;
2008 image->data = dst_bits.ptr;
2009 /* hack: make sure the bits are readable if we are reading from a DIB section */
2010 /* to be removed once we get rid of DIB access protections */
2011 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2013 *use_repeat = (width == 1 && height == 1);
2014 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2016 wine_tsx11_lock();
2017 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2018 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2019 src->visrect.left, 0, 0, 0, width, height );
2020 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2021 wine_tsx11_unlock();
2023 /* make coordinates relative to the pixmap */
2024 src->x -= src->visrect.left;
2025 src->y -= src->visrect.top;
2026 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2028 image->data = NULL;
2029 wine_tsx11_lock();
2030 XDestroyImage( image );
2031 wine_tsx11_unlock();
2032 if (dst_bits.free) dst_bits.free( &dst_bits );
2033 return ret;
2036 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2037 Drawable drawable, const struct bitblt_coords *src,
2038 const struct bitblt_coords *dst )
2040 int width = abs( dst->width );
2041 int height = abs( dst->height );
2042 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2043 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2044 int x_dst, y_dst;
2045 Picture src_pict = 0, dst_pict, mask_pict = 0;
2046 BOOL use_repeat;
2047 double xscale, yscale;
2049 use_repeat = use_source_repeat( physdev_src );
2050 if (!use_repeat)
2052 xscale = src->width / (double)dst->width;
2053 yscale = src->height / (double)dst->height;
2055 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2057 if (drawable) /* using an intermediate pixmap */
2059 XRenderPictureAttributes pa;
2061 x_dst = dst->x;
2062 y_dst = dst->y;
2063 pa.repeat = RepeatNone;
2064 wine_tsx11_lock();
2065 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2066 wine_tsx11_unlock();
2068 else
2070 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2071 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2072 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2075 if (src->width < 0) x_src += src->width + 1;
2076 if (src->height < 0) y_src += src->height + 1;
2077 if (dst->width < 0) x_dst += dst->width + 1;
2078 if (dst->height < 0) y_dst += dst->height + 1;
2080 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2082 /* mono -> color */
2083 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2085 XRenderColor fg, bg;
2087 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, &fg );
2088 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, &bg );
2089 fg.alpha = bg.alpha = 0;
2091 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2092 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2094 else /* color -> color (can be at different depths) or mono -> mono */
2096 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2097 mask_pict = get_no_alpha_mask();
2099 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2100 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2103 if (drawable)
2105 wine_tsx11_lock();
2106 pXRenderFreePicture( gdi_display, dst_pict );
2107 wine_tsx11_unlock();
2112 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2113 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2114 Drawable drawable, struct bitblt_coords *src,
2115 struct bitblt_coords *dst, BOOL use_repeat )
2117 int x_src, y_src, x_dst, y_dst;
2118 Picture dst_pict;
2119 XRenderPictureAttributes pa;
2120 double xscale, yscale;
2122 if (drawable) /* using an intermediate pixmap */
2124 RGNDATA *clip_data = NULL;
2126 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2127 x_dst = dst->x;
2128 y_dst = dst->y;
2129 pa.repeat = RepeatNone;
2130 wine_tsx11_lock();
2131 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2132 if (clip_data)
2133 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2134 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2135 wine_tsx11_unlock();
2136 HeapFree( GetProcessHeap(), 0, clip_data );
2138 else
2140 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2141 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2142 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2145 if (!use_repeat)
2147 xscale = src->width / (double)dst->width;
2148 yscale = src->height / (double)dst->height;
2150 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2152 x_src = src->x;
2153 y_src = src->y;
2154 if (src->width < 0) x_src += src->width + 1;
2155 if (src->height < 0) y_src += src->height + 1;
2156 if (dst->width < 0) x_dst += dst->width + 1;
2157 if (dst->height < 0) y_dst += dst->height + 1;
2159 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2160 xscale, yscale, abs( dst->width ), abs( dst->height ));
2162 if (drawable)
2164 wine_tsx11_lock();
2165 pXRenderFreePicture( gdi_display, dst_pict );
2166 wine_tsx11_unlock();
2171 /***********************************************************************
2172 * xrenderdrv_StretchBlt
2174 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2175 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2177 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2178 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2179 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2181 if (src_dev->funcs != dst_dev->funcs)
2183 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2184 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2187 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2189 /* XRender is of no use for color -> mono */
2190 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2191 goto x11drv_fallback;
2193 /* if not stretching, we only need to handle format conversion */
2194 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2196 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2197 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2199 if (rop != SRCCOPY)
2201 GC tmpGC;
2202 Pixmap tmp_pixmap;
2203 struct bitblt_coords tmp;
2205 /* make coordinates relative to tmp pixmap */
2206 tmp = *dst;
2207 tmp.x -= tmp.visrect.left;
2208 tmp.y -= tmp.visrect.top;
2209 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2211 wine_tsx11_lock();
2212 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2213 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2214 XSetGraphicsExposures( gdi_display, tmpGC, False );
2215 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2216 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2217 wine_tsx11_unlock();
2219 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2220 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2222 wine_tsx11_lock();
2223 XFreePixmap( gdi_display, tmp_pixmap );
2224 XFreeGC( gdi_display, tmpGC );
2225 wine_tsx11_unlock();
2227 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2229 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2230 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2231 return TRUE;
2233 x11drv_fallback:
2234 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2238 /***********************************************************************
2239 * xrenderdrv_PutImage
2241 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2242 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2243 struct bitblt_coords *dst, DWORD rop )
2245 struct xrender_physdev *physdev;
2246 X_PHYSBITMAP *bitmap;
2247 DWORD ret;
2248 Pixmap tmp_pixmap;
2249 GC gc;
2250 enum wxr_format src_format, dst_format;
2251 XRenderPictFormat *pict_format;
2252 Pixmap src_pixmap;
2253 Picture src_pict, mask_pict = 0;
2254 BOOL use_repeat;
2256 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2258 if (hbitmap)
2260 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2261 physdev = NULL;
2262 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2264 else
2266 physdev = get_xrender_dev( dev );
2267 bitmap = NULL;
2268 dst_format = physdev->format;
2271 src_format = get_xrender_format_from_bitmapinfo( info );
2272 if (!(pict_format = pict_formats[src_format])) goto update_format;
2274 /* make sure we can create an image with the same bpp */
2275 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2276 goto update_format;
2278 /* mono <-> color conversions not supported */
2279 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2280 goto x11drv_fallback;
2282 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2284 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2286 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2287 if (!ret)
2289 struct bitblt_coords tmp;
2291 if (bitmap)
2293 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2294 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2296 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2298 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2299 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2301 X11DRV_DIB_Unlock( bitmap, TRUE );
2302 DeleteObject( rgn );
2304 else
2306 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2308 if (rop != SRCCOPY)
2310 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2312 /* make coordinates relative to tmp pixmap */
2313 tmp = *dst;
2314 tmp.x -= tmp.visrect.left;
2315 tmp.y -= tmp.visrect.top;
2316 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2318 wine_tsx11_lock();
2319 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2320 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2321 XSetGraphicsExposures( gdi_display, gc, False );
2322 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2323 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2324 wine_tsx11_unlock();
2326 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2327 NULL, tmp_pixmap, src, &tmp, use_repeat );
2328 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2330 wine_tsx11_lock();
2331 XFreePixmap( gdi_display, tmp_pixmap );
2332 XFreeGC( gdi_display, gc );
2333 wine_tsx11_unlock();
2335 if (restore_region) restore_clipping_region( physdev->x11dev );
2337 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2338 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2340 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2343 wine_tsx11_lock();
2344 pXRenderFreePicture( gdi_display, src_pict );
2345 XFreePixmap( gdi_display, src_pixmap );
2346 wine_tsx11_unlock();
2348 return ret;
2350 update_format:
2351 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2352 set_color_info( pict_formats[dst_format], info );
2353 return ERROR_BAD_FORMAT;
2355 x11drv_fallback:
2356 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2357 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2358 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2362 /***********************************************************************
2363 * xrenderdrv_BlendImage
2365 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2366 struct bitblt_coords *src, struct bitblt_coords *dst,
2367 BLENDFUNCTION func )
2369 struct xrender_physdev *physdev = get_xrender_dev( dev );
2370 DWORD ret;
2371 enum wxr_format format;
2372 XRenderPictFormat *pict_format;
2373 Picture dst_pict, src_pict, mask_pict;
2374 Pixmap src_pixmap;
2375 BOOL use_repeat;
2377 if (!X11DRV_XRender_Installed)
2379 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2380 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2383 format = get_xrender_format_from_bitmapinfo( info );
2384 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2385 format = get_format_without_alpha( format );
2386 else if (format != WXR_FORMAT_A8R8G8B8)
2387 return ERROR_INVALID_PARAMETER;
2389 if (!(pict_format = pict_formats[format])) goto update_format;
2391 /* make sure we can create an image with the same bpp */
2392 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2393 goto update_format;
2395 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2396 goto update_format;
2398 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2400 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2401 if (!ret)
2403 double xscale, yscale;
2405 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2407 if (!use_repeat)
2409 xscale = src->width / (double)dst->width;
2410 yscale = src->height / (double)dst->height;
2412 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2414 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2416 EnterCriticalSection( &xrender_cs );
2417 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2419 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2420 physdev->x11dev->dc_rect.left + dst->x,
2421 physdev->x11dev->dc_rect.top + dst->y,
2422 xscale, yscale, dst->width, dst->height );
2424 wine_tsx11_lock();
2425 pXRenderFreePicture( gdi_display, src_pict );
2426 XFreePixmap( gdi_display, src_pixmap );
2427 wine_tsx11_unlock();
2429 LeaveCriticalSection( &xrender_cs );
2431 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2433 return ret;
2435 update_format:
2436 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2437 set_color_info( physdev->pict_format, info );
2438 return ERROR_BAD_FORMAT;
2442 /***********************************************************************
2443 * xrenderdrv_AlphaBlend
2445 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2446 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2448 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2449 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2450 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2451 XRenderPictureAttributes pa;
2452 Pixmap tmp_pixmap = 0;
2453 double xscale, yscale;
2454 BOOL use_repeat;
2456 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2458 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2459 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2462 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2464 SetLastError( ERROR_INVALID_PARAMETER );
2465 return FALSE;
2468 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2469 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2471 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2473 use_repeat = use_source_repeat( physdev_src );
2474 if (!use_repeat)
2476 xscale = src->width / (double)dst->width;
2477 yscale = src->height / (double)dst->height;
2479 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2481 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2483 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2485 /* mono -> color blending needs an intermediate color pixmap */
2486 XRenderColor fg, bg;
2487 int width = src->visrect.right - src->visrect.left;
2488 int height = src->visrect.bottom - src->visrect.top;
2490 /* blending doesn't use the destination DC colors */
2491 fg.red = fg.green = fg.blue = 0;
2492 bg.red = bg.green = bg.blue = 0xffff;
2493 fg.alpha = bg.alpha = 0xffff;
2495 wine_tsx11_lock();
2496 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2497 physdev_dst->pict_format->depth );
2498 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2499 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2500 CPRepeat, &pa );
2501 wine_tsx11_unlock();
2503 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2504 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2506 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2508 /* we need a source picture with no alpha */
2509 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2510 if (format != physdev_src->format)
2512 wine_tsx11_lock();
2513 pa.subwindow_mode = IncludeInferiors;
2514 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2515 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2516 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2517 wine_tsx11_unlock();
2521 if (tmp_pict) src_pict = tmp_pict;
2523 EnterCriticalSection( &xrender_cs );
2524 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2526 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2527 physdev_src->x11dev->dc_rect.left + src->x,
2528 physdev_src->x11dev->dc_rect.top + src->y,
2529 physdev_dst->x11dev->dc_rect.left + dst->x,
2530 physdev_dst->x11dev->dc_rect.top + dst->y,
2531 xscale, yscale, dst->width, dst->height );
2533 wine_tsx11_lock();
2534 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2535 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2536 wine_tsx11_unlock();
2538 LeaveCriticalSection( &xrender_cs );
2539 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2540 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2541 return TRUE;
2544 /***********************************************************************
2545 * xrenderdrv_GradientFill
2547 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2548 void * grad_array, ULONG ngrad, ULONG mode )
2550 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2551 static const XFixed stops[2] = { 0, 1 << 16 };
2552 struct xrender_physdev *physdev = get_xrender_dev( dev );
2553 XLinearGradient gradient;
2554 XRenderColor colors[2];
2555 Picture src_pict, dst_pict;
2556 unsigned int i;
2557 const GRADIENT_RECT *rect = grad_array;
2558 POINT pt[2];
2560 if (!X11DRV_XRender_Installed) goto fallback;
2561 if (!pXRenderCreateLinearGradient) goto fallback;
2563 /* <= 16-bpp uses dithering */
2564 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2566 switch (mode)
2568 case GRADIENT_FILL_RECT_H:
2569 case GRADIENT_FILL_RECT_V:
2570 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2571 for (i = 0; i < ngrad; i++, rect++)
2573 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2574 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2576 colors[0].red = v1->Red * 257 / 256;
2577 colors[0].green = v1->Green * 257 / 256;
2578 colors[0].blue = v1->Blue * 257 / 256;
2579 colors[1].red = v2->Red * 257 / 256;
2580 colors[1].green = v2->Green * 257 / 256;
2581 colors[1].blue = v2->Blue * 257 / 256;
2582 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2583 colors[0].alpha = colors[1].alpha = 65535;
2585 pt[0].x = v1->x;
2586 pt[0].y = v1->y;
2587 pt[1].x = v2->x;
2588 pt[1].y = v2->y;
2589 LPtoDP( dev->hdc, pt, 2 );
2590 if (mode == GRADIENT_FILL_RECT_H)
2592 gradient.p1.y = gradient.p2.y = 0;
2593 if (pt[1].x > pt[0].x)
2595 gradient.p1.x = 0;
2596 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2598 else
2600 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2601 gradient.p2.x = 0;
2604 else
2606 gradient.p1.x = gradient.p2.x = 0;
2607 if (pt[1].y > pt[0].y)
2609 gradient.p1.y = 0;
2610 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2612 else
2614 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2615 gradient.p2.y = 0;
2619 TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2620 mode, pt[0].x, pt[0].y, pt[1].x, pt[1].y,
2621 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2622 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2624 wine_tsx11_lock();
2625 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2626 dst_pict = get_xrender_picture( physdev, 0, NULL );
2627 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0,
2628 physdev->x11dev->dc_rect.left + min( pt[0].x, pt[1].x ),
2629 physdev->x11dev->dc_rect.top + min( pt[0].y, pt[1].y ),
2630 1, 1, abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y) );
2631 pXRenderFreePicture( gdi_display, src_pict );
2632 wine_tsx11_unlock();
2634 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2635 return TRUE;
2638 fallback:
2639 #endif
2640 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2641 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2644 /***********************************************************************
2645 * xrenderdrv_SelectBrush
2647 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, HBITMAP bitmap,
2648 const BITMAPINFO *info, void *bits, UINT usage )
2650 struct xrender_physdev *physdev = get_xrender_dev( dev );
2651 X_PHYSBITMAP *physbitmap;
2652 enum wxr_format format;
2653 BOOL delete_bitmap = FALSE;
2654 BITMAP bm;
2655 Pixmap pixmap;
2656 Picture src_pict, dst_pict;
2657 XRenderPictureAttributes pa;
2659 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2660 if (!bitmap && !info) goto x11drv_fallback;
2661 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2663 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2665 if (!(bitmap = create_brush_bitmap( physdev->x11dev, info, bits, usage ))) return 0;
2666 physbitmap = X11DRV_get_phys_bitmap( bitmap );
2667 delete_bitmap = TRUE;
2670 format = get_xrender_format_from_color_shifts( physbitmap->depth, &physbitmap->color_shifts );
2671 if (format == WXR_FORMAT_MONO || !pict_formats[format]) goto x11drv_fallback;
2673 GetObjectW( bitmap, sizeof(bm), &bm );
2675 X11DRV_DIB_Lock( physbitmap, DIB_Status_GdiMod );
2677 wine_tsx11_lock();
2678 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2679 physdev->pict_format->depth );
2681 pa.repeat = RepeatNone;
2682 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_formats[format], CPRepeat, &pa);
2683 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2685 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, bm.bmWidth, bm.bmHeight );
2686 pXRenderFreePicture( gdi_display, src_pict );
2687 pXRenderFreePicture( gdi_display, dst_pict );
2689 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2690 physdev->x11dev->brush.pixmap = pixmap;
2691 physdev->x11dev->brush.fillStyle = FillTiled;
2692 physdev->x11dev->brush.pixel = 0; /* ignored */
2693 wine_tsx11_unlock();
2695 X11DRV_DIB_Unlock( physbitmap, TRUE );
2696 if (delete_bitmap) DeleteObject( bitmap );
2697 return hbrush;
2699 x11drv_fallback:
2700 if (delete_bitmap) DeleteObject( bitmap );
2701 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2702 return dev->funcs->pSelectBrush( dev, hbrush, bitmap, info, bits, usage );
2706 static const struct gdi_dc_funcs xrender_funcs =
2708 NULL, /* pAbortDoc */
2709 NULL, /* pAbortPath */
2710 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2711 NULL, /* pAngleArc */
2712 NULL, /* pArc */
2713 NULL, /* pArcTo */
2714 NULL, /* pBeginPath */
2715 xrenderdrv_BlendImage, /* pBlendImage */
2716 NULL, /* pChoosePixelFormat */
2717 NULL, /* pChord */
2718 NULL, /* pCloseFigure */
2719 xrenderdrv_CopyBitmap, /* pCopyBitmap */
2720 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2721 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2722 xrenderdrv_CreateDC, /* pCreateDC */
2723 NULL, /* pCreateDIBSection */
2724 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2725 xrenderdrv_DeleteDC, /* pDeleteDC */
2726 NULL, /* pDeleteObject */
2727 NULL, /* pDescribePixelFormat */
2728 NULL, /* pDeviceCapabilities */
2729 NULL, /* pEllipse */
2730 NULL, /* pEndDoc */
2731 NULL, /* pEndPage */
2732 NULL, /* pEndPath */
2733 NULL, /* pEnumFonts */
2734 NULL, /* pEnumICMProfiles */
2735 NULL, /* pExcludeClipRect */
2736 NULL, /* pExtDeviceMode */
2737 xrenderdrv_ExtEscape, /* pExtEscape */
2738 NULL, /* pExtFloodFill */
2739 NULL, /* pExtSelectClipRgn */
2740 xrenderdrv_ExtTextOut, /* pExtTextOut */
2741 NULL, /* pFillPath */
2742 NULL, /* pFillRgn */
2743 NULL, /* pFlattenPath */
2744 NULL, /* pFontIsLinked */
2745 NULL, /* pFrameRgn */
2746 NULL, /* pGdiComment */
2747 NULL, /* pGdiRealizationInfo */
2748 NULL, /* pGetCharABCWidths */
2749 NULL, /* pGetCharABCWidthsI */
2750 NULL, /* pGetCharWidth */
2751 NULL, /* pGetDeviceCaps */
2752 NULL, /* pGetDeviceGammaRamp */
2753 NULL, /* pGetFontData */
2754 NULL, /* pGetFontUnicodeRanges */
2755 NULL, /* pGetGlyphIndices */
2756 NULL, /* pGetGlyphOutline */
2757 NULL, /* pGetICMProfile */
2758 xrenderdrv_GetImage, /* pGetImage */
2759 NULL, /* pGetKerningPairs */
2760 NULL, /* pGetNearestColor */
2761 NULL, /* pGetOutlineTextMetrics */
2762 NULL, /* pGetPixel */
2763 NULL, /* pGetPixelFormat */
2764 NULL, /* pGetSystemPaletteEntries */
2765 NULL, /* pGetTextCharsetInfo */
2766 NULL, /* pGetTextExtentExPoint */
2767 NULL, /* pGetTextExtentExPointI */
2768 NULL, /* pGetTextFace */
2769 NULL, /* pGetTextMetrics */
2770 xrenderdrv_GradientFill, /* pGradientFill */
2771 NULL, /* pIntersectClipRect */
2772 NULL, /* pInvertRgn */
2773 NULL, /* pLineTo */
2774 NULL, /* pModifyWorldTransform */
2775 NULL, /* pMoveTo */
2776 NULL, /* pOffsetClipRgn */
2777 NULL, /* pOffsetViewportOrg */
2778 NULL, /* pOffsetWindowOrg */
2779 NULL, /* pPaintRgn */
2780 NULL, /* pPatBlt */
2781 NULL, /* pPie */
2782 NULL, /* pPolyBezier */
2783 NULL, /* pPolyBezierTo */
2784 NULL, /* pPolyDraw */
2785 NULL, /* pPolyPolygon */
2786 NULL, /* pPolyPolyline */
2787 NULL, /* pPolygon */
2788 NULL, /* pPolyline */
2789 NULL, /* pPolylineTo */
2790 xrenderdrv_PutImage, /* pPutImage */
2791 NULL, /* pRealizeDefaultPalette */
2792 NULL, /* pRealizePalette */
2793 NULL, /* pRectangle */
2794 NULL, /* pResetDC */
2795 NULL, /* pRestoreDC */
2796 NULL, /* pRoundRect */
2797 NULL, /* pSaveDC */
2798 NULL, /* pScaleViewportExt */
2799 NULL, /* pScaleWindowExt */
2800 xrenderdrv_SelectBitmap, /* pSelectBitmap */
2801 xrenderdrv_SelectBrush, /* pSelectBrush */
2802 NULL, /* pSelectClipPath */
2803 xrenderdrv_SelectFont, /* pSelectFont */
2804 NULL, /* pSelectPalette */
2805 NULL, /* pSelectPen */
2806 NULL, /* pSetArcDirection */
2807 NULL, /* pSetBkColor */
2808 NULL, /* pSetBkMode */
2809 NULL, /* pSetDCBrushColor */
2810 NULL, /* pSetDCPenColor */
2811 NULL, /* pSetDIBColorTable */
2812 NULL, /* pSetDIBitsToDevice */
2813 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2814 NULL, /* pSetDeviceGammaRamp */
2815 NULL, /* pSetLayout */
2816 NULL, /* pSetMapMode */
2817 NULL, /* pSetMapperFlags */
2818 NULL, /* pSetPixel */
2819 NULL, /* pSetPixelFormat */
2820 NULL, /* pSetPolyFillMode */
2821 NULL, /* pSetROP2 */
2822 NULL, /* pSetRelAbs */
2823 NULL, /* pSetStretchBltMode */
2824 NULL, /* pSetTextAlign */
2825 NULL, /* pSetTextCharacterExtra */
2826 NULL, /* pSetTextColor */
2827 NULL, /* pSetTextJustification */
2828 NULL, /* pSetViewportExt */
2829 NULL, /* pSetViewportOrg */
2830 NULL, /* pSetWindowExt */
2831 NULL, /* pSetWindowOrg */
2832 NULL, /* pSetWorldTransform */
2833 NULL, /* pStartDoc */
2834 NULL, /* pStartPage */
2835 xrenderdrv_StretchBlt, /* pStretchBlt */
2836 NULL, /* pStretchDIBits */
2837 NULL, /* pStrokeAndFillPath */
2838 NULL, /* pStrokePath */
2839 NULL, /* pSwapBuffers */
2840 NULL, /* pUnrealizePalette */
2841 NULL, /* pWidenPath */
2842 /* OpenGL not supported */
2845 #else /* SONAME_LIBXRENDER */
2847 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2849 TRACE("XRender support not compiled in.\n");
2850 return NULL;
2853 void X11DRV_XRender_Finalize(void)
2857 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2859 return FALSE;
2862 #endif /* SONAME_LIBXRENDER */