gdi32: Use the get_clipped_rects helper in the pen functions.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blobb3cf3ba8b6964ace657cca9a2d915793b9ac12e8
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 format = get_bitmap_format( bitmap.bmBitsPixel );
1308 if (pict_formats[format])
1309 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1310 TRUE, &wxr_color_shifts[format] );
1312 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1313 return dev->funcs->pCreateBitmap( dev, hbitmap );
1316 /****************************************************************************
1317 * xrenderdrv_DeleteBitmap
1319 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1321 return X11DRV_DeleteBitmap( hbitmap );
1324 /***********************************************************************
1325 * xrenderdrv_SelectBitmap
1327 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1329 HBITMAP ret;
1330 struct xrender_physdev *physdev = get_xrender_dev( dev );
1332 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1333 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1334 if (ret)
1336 free_xrender_picture( physdev );
1337 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1338 physdev->x11dev->color_shifts );
1339 physdev->pict_format = pict_formats[physdev->format];
1341 return ret;
1344 /***********************************************************************
1345 * xrenderdrv_GetImage
1347 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1348 struct gdi_image_bits *bits, struct bitblt_coords *src )
1350 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1351 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1352 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1355 /***********************************************************************
1356 * xrenderdrv_SetDeviceClipping
1358 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1360 struct xrender_physdev *physdev = get_xrender_dev( dev );
1362 physdev->update_clip = TRUE;
1364 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1365 dev->funcs->pSetDeviceClipping( dev, rgn );
1369 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1371 XRenderPictFormat *pict_format;
1372 ColorShifts shifts;
1373 const DWORD *bitfields;
1374 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1375 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1378 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1379 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1380 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1381 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1382 return FALSE;
1384 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1385 bitfields = dib->dsBitfields;
1386 else if(bits_pixel == 24 || bits_pixel == 32)
1387 bitfields = bitfields_32;
1388 else
1389 bitfields = bitfields_16;
1391 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1392 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1394 /* Common formats should be in our picture format table. */
1395 if (!pict_format)
1397 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1398 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1399 return FALSE;
1402 physBitmap->depth = pict_format->depth;
1403 physBitmap->trueColor = TRUE;
1404 physBitmap->color_shifts = shifts;
1405 return TRUE;
1408 /************************************************************************
1409 * UploadGlyph
1411 * Helper to ExtTextOut. Must be called inside xrender_cs
1413 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1415 unsigned int buflen;
1416 char *buf;
1417 Glyph gid;
1418 GLYPHMETRICS gm;
1419 XGlyphInfo gi;
1420 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1421 gsCacheEntryFormat *formatEntry;
1422 UINT ggo_format = GGO_GLYPH_INDEX;
1423 enum wxr_format wxr_format;
1424 static const char zero[4];
1425 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1427 switch(format) {
1428 case AA_Grey:
1429 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1430 break;
1431 case AA_RGB:
1432 ggo_format |= WINE_GGO_HRGB_BITMAP;
1433 break;
1434 case AA_BGR:
1435 ggo_format |= WINE_GGO_HBGR_BITMAP;
1436 break;
1437 case AA_VRGB:
1438 ggo_format |= WINE_GGO_VRGB_BITMAP;
1439 break;
1440 case AA_VBGR:
1441 ggo_format |= WINE_GGO_VBGR_BITMAP;
1442 break;
1444 default:
1445 ERR("aa = %d - not implemented\n", format);
1446 case AA_None:
1447 ggo_format |= GGO_BITMAP;
1448 break;
1451 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1452 if(buflen == GDI_ERROR) {
1453 if(format != AA_None) {
1454 format = AA_None;
1455 entry->aa_default = AA_None;
1456 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1457 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1459 if(buflen == GDI_ERROR) {
1460 WARN("GetGlyphOutlineW failed using default glyph\n");
1461 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1462 if(buflen == GDI_ERROR) {
1463 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1464 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1465 if(buflen == GDI_ERROR) {
1466 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1467 return;
1471 TRACE("Turning off antialiasing for this monochrome font\n");
1474 /* If there is nothing for the current type, we create the entry. */
1475 if( !entry->format[format] ) {
1476 entry->format[format] = HeapAlloc(GetProcessHeap(),
1477 HEAP_ZERO_MEMORY,
1478 sizeof(gsCacheEntryFormat));
1480 formatEntry = entry->format[format];
1482 if(formatEntry->nrealized <= glyph) {
1483 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1485 if (formatEntry->realized)
1486 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1487 HEAP_ZERO_MEMORY,
1488 formatEntry->realized,
1489 formatEntry->nrealized * sizeof(BOOL));
1490 else
1491 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1492 HEAP_ZERO_MEMORY,
1493 formatEntry->nrealized * sizeof(BOOL));
1495 if (formatEntry->gis)
1496 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1497 HEAP_ZERO_MEMORY,
1498 formatEntry->gis,
1499 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1500 else
1501 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1502 HEAP_ZERO_MEMORY,
1503 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1507 if(formatEntry->glyphset == 0) {
1508 switch(format) {
1509 case AA_Grey:
1510 wxr_format = WXR_FORMAT_GRAY;
1511 break;
1513 case AA_RGB:
1514 case AA_BGR:
1515 case AA_VRGB:
1516 case AA_VBGR:
1517 wxr_format = WXR_FORMAT_A8R8G8B8;
1518 break;
1520 default:
1521 ERR("aa = %d - not implemented\n", format);
1522 case AA_None:
1523 wxr_format = WXR_FORMAT_MONO;
1524 break;
1527 wine_tsx11_lock();
1528 formatEntry->font_format = pict_formats[wxr_format];
1529 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1530 wine_tsx11_unlock();
1534 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1535 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1536 formatEntry->realized[glyph] = TRUE;
1538 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1539 buflen,
1540 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1541 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1543 gi.width = gm.gmBlackBoxX;
1544 gi.height = gm.gmBlackBoxY;
1545 gi.x = -gm.gmptGlyphOrigin.x;
1546 gi.y = gm.gmptGlyphOrigin.y;
1547 gi.xOff = gm.gmCellIncX;
1548 gi.yOff = gm.gmCellIncY;
1550 if(TRACE_ON(xrender)) {
1551 int pitch, i, j;
1552 char output[300];
1553 unsigned char *line;
1555 if(format == AA_None) {
1556 pitch = ((gi.width + 31) / 32) * 4;
1557 for(i = 0; i < gi.height; i++) {
1558 line = (unsigned char*) buf + i * pitch;
1559 output[0] = '\0';
1560 for(j = 0; j < pitch * 8; j++) {
1561 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1563 TRACE("%s\n", output);
1565 } else {
1566 static const char blks[] = " .:;!o*#";
1567 char str[2];
1569 str[1] = '\0';
1570 pitch = ((gi.width + 3) / 4) * 4;
1571 for(i = 0; i < gi.height; i++) {
1572 line = (unsigned char*) buf + i * pitch;
1573 output[0] = '\0';
1574 for(j = 0; j < pitch; j++) {
1575 str[0] = blks[line[j] >> 5];
1576 strcat(output, str);
1578 TRACE("%s\n", output);
1584 if(formatEntry->glyphset) {
1585 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1586 unsigned char *byte = (unsigned char*) buf, c;
1587 int i = buflen;
1589 while(i--) {
1590 c = *byte;
1592 /* magic to flip bit order */
1593 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1594 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1595 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1597 *byte++ = c;
1600 else if ( format != AA_Grey &&
1601 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1603 unsigned int i, *data = (unsigned int *)buf;
1604 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1606 gid = glyph;
1609 XRenderCompositeText seems to ignore 0x0 glyphs when
1610 AA_None, which means we lose the advance width of glyphs
1611 like the space. We'll pretend that such glyphs are 1x1
1612 bitmaps.
1615 if(buflen == 0)
1616 gi.width = gi.height = 1;
1618 wine_tsx11_lock();
1619 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1620 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1621 wine_tsx11_unlock();
1622 HeapFree(GetProcessHeap(), 0, buf);
1625 formatEntry->gis[glyph] = gi;
1628 /*************************************************************
1629 * get_tile_pict
1631 * Returns an appropriate Picture for tiling the text colour.
1632 * Call and use result within the xrender_cs
1634 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1636 static struct
1638 Pixmap xpm;
1639 Picture pict;
1640 XRenderColor current_color;
1641 } tiles[WXR_NB_FORMATS], *tile;
1643 tile = &tiles[wxr_format];
1645 if(!tile->xpm)
1647 XRenderPictureAttributes pa;
1648 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1650 wine_tsx11_lock();
1651 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1653 pa.repeat = RepeatNormal;
1654 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1655 wine_tsx11_unlock();
1657 /* init current_color to something different from text_pixel */
1658 tile->current_color = *color;
1659 tile->current_color.red ^= 0xffff;
1661 if (wxr_format == WXR_FORMAT_MONO)
1663 /* for a 1bpp bitmap we always need a 1 in the tile */
1664 XRenderColor col;
1665 col.red = col.green = col.blue = 0;
1666 col.alpha = 0xffff;
1667 wine_tsx11_lock();
1668 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1669 wine_tsx11_unlock();
1673 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1675 wine_tsx11_lock();
1676 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1677 wine_tsx11_unlock();
1678 tile->current_color = *color;
1680 return tile->pict;
1683 /*************************************************************
1684 * get_mask_pict
1686 * Returns an appropriate Picture for masking with the specified alpha.
1687 * Call and use result within the xrender_cs
1689 static Picture get_mask_pict( int alpha )
1691 static Pixmap pixmap;
1692 static Picture pict;
1693 static int current_alpha;
1695 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1697 if (!pixmap)
1699 XRenderPictureAttributes pa;
1701 wine_tsx11_lock();
1702 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1703 pa.repeat = RepeatNormal;
1704 pict = pXRenderCreatePicture( gdi_display, pixmap,
1705 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1706 wine_tsx11_unlock();
1707 current_alpha = -1;
1710 if (alpha != current_alpha)
1712 XRenderColor col;
1713 col.red = col.green = col.blue = 0;
1714 col.alpha = current_alpha = alpha;
1715 wine_tsx11_lock();
1716 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1717 wine_tsx11_unlock();
1719 return pict;
1722 /***********************************************************************
1723 * xrenderdrv_ExtTextOut
1725 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1726 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1728 struct xrender_physdev *physdev = get_xrender_dev( dev );
1729 XGCValues xgcval;
1730 gsCacheEntry *entry;
1731 gsCacheEntryFormat *formatEntry;
1732 int textPixel, backgroundPixel;
1733 AA_Type aa_type = AA_None;
1734 unsigned int idx;
1735 Picture pict, tile_pict = 0;
1736 XGlyphElt16 *elts;
1737 POINT offset, desired, current;
1738 int render_op = PictOpOver;
1739 XRenderColor col;
1741 if (!X11DRV_XRender_Installed || !physdev->x11dev->has_gdi_font)
1743 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1744 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1747 xgcval.function = GXcopy;
1748 xgcval.background = physdev->x11dev->backgroundPixel;
1749 xgcval.fill_style = FillSolid;
1750 wine_tsx11_lock();
1751 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1752 wine_tsx11_unlock();
1754 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1756 if(physdev->x11dev->depth == 1) {
1757 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1758 textPixel = 0;
1759 backgroundPixel = 1;
1760 } else {
1761 textPixel = 1;
1762 backgroundPixel = 0;
1764 } else {
1765 textPixel = physdev->x11dev->textPixel;
1766 backgroundPixel = physdev->x11dev->backgroundPixel;
1769 if(flags & ETO_OPAQUE)
1771 wine_tsx11_lock();
1772 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
1773 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
1774 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
1775 lprect->right - lprect->left, lprect->bottom - lprect->top );
1776 wine_tsx11_unlock();
1779 if(count == 0)
1781 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1782 return TRUE;
1785 EnterCriticalSection(&xrender_cs);
1787 entry = glyphsetCache + physdev->cache_index;
1788 aa_type = entry->aa_default;
1789 formatEntry = entry->format[aa_type];
1791 for(idx = 0; idx < count; idx++) {
1792 if( !formatEntry ) {
1793 UploadGlyph(physdev, wstr[idx], aa_type);
1794 /* re-evaluate antialias since aa_default may have changed */
1795 aa_type = entry->aa_default;
1796 formatEntry = entry->format[aa_type];
1797 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1798 UploadGlyph(physdev, wstr[idx], aa_type);
1801 if (!formatEntry)
1803 WARN("could not upload requested glyphs\n");
1804 LeaveCriticalSection(&xrender_cs);
1805 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1806 return FALSE;
1809 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1810 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1812 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1813 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1815 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1816 So we pass zeros to the function and move to our starting position using the first
1817 element of the elts array. */
1819 desired.x = physdev->x11dev->dc_rect.left + x;
1820 desired.y = physdev->x11dev->dc_rect.top + y;
1821 offset.x = offset.y = 0;
1822 current.x = current.y = 0;
1824 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
1825 tile_pict = get_tile_pict(physdev->format, &col);
1827 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1829 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
1830 render_op = PictOpOutReverse; /* This gives us 'black' text */
1832 for(idx = 0; idx < count; idx++)
1834 elts[idx].glyphset = formatEntry->glyphset;
1835 elts[idx].chars = wstr + idx;
1836 elts[idx].nchars = 1;
1837 elts[idx].xOff = desired.x - current.x;
1838 elts[idx].yOff = desired.y - current.y;
1840 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1841 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1843 if(!lpDx)
1845 desired.x += formatEntry->gis[wstr[idx]].xOff;
1846 desired.y += formatEntry->gis[wstr[idx]].yOff;
1848 else
1850 if(flags & ETO_PDY)
1852 offset.x += lpDx[idx * 2];
1853 offset.y += lpDx[idx * 2 + 1];
1855 else
1856 offset.x += lpDx[idx];
1857 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1858 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1862 wine_tsx11_lock();
1863 /* Make sure we don't have any transforms set from a previous call */
1864 set_xrender_transformation(pict, 1, 1, 0, 0);
1865 pXRenderCompositeText16(gdi_display, render_op,
1866 tile_pict,
1867 pict,
1868 formatEntry->font_format,
1869 0, 0, 0, 0, elts, count);
1870 wine_tsx11_unlock();
1871 HeapFree(GetProcessHeap(), 0, elts);
1873 LeaveCriticalSection(&xrender_cs);
1874 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1875 return TRUE;
1878 /* multiply the alpha channel of a picture */
1879 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1880 int x, int y, int width, int height )
1882 XRenderPictureAttributes pa;
1883 Pixmap src_pixmap, mask_pixmap;
1884 Picture src_pict, mask_pict;
1885 XRenderColor color;
1887 wine_tsx11_lock();
1888 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1889 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1890 pa.repeat = RepeatNormal;
1891 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1892 pa.component_alpha = True;
1893 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1894 color.red = color.green = color.blue = color.alpha = 0xffff;
1895 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1896 color.alpha = alpha;
1897 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1898 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1899 0, 0, 0, 0, x, y, width, height );
1900 pXRenderFreePicture( gdi_display, src_pict );
1901 pXRenderFreePicture( gdi_display, mask_pict );
1902 XFreePixmap( gdi_display, src_pixmap );
1903 XFreePixmap( gdi_display, mask_pixmap );
1904 wine_tsx11_unlock();
1907 /* Helper function for (stretched) blitting using xrender */
1908 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1909 int x_src, int y_src, int x_dst, int y_dst,
1910 double xscale, double yscale, int width, int height )
1912 int x_offset, y_offset;
1914 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1915 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1916 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1917 wine_tsx11_lock();
1918 if(xscale != 1.0 || yscale != 1.0)
1920 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1921 * in the wrong quadrant of the x-y plane.
1923 x_offset = (xscale < 0) ? -width : 0;
1924 y_offset = (yscale < 0) ? -height : 0;
1925 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1927 else
1929 x_offset = x_src;
1930 y_offset = y_src;
1931 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1933 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1934 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
1935 wine_tsx11_unlock();
1938 /* Helper function for (stretched) mono->color blitting using xrender */
1939 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1940 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1941 int x_src, int y_src, int x_dst, int y_dst,
1942 double xscale, double yscale, int width, int height )
1944 Picture tile_pict;
1945 int x_offset, y_offset;
1946 XRenderColor color;
1948 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1949 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1950 * the tile data.
1952 EnterCriticalSection( &xrender_cs );
1953 color = *bg;
1954 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1955 tile_pict = get_tile_pict( dst_format, &color );
1957 wine_tsx11_lock();
1958 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
1960 if (xscale != 1.0 || yscale != 1.0)
1962 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1963 * in the wrong quadrant of the x-y plane.
1965 x_offset = (xscale < 0) ? -width : 0;
1966 y_offset = (yscale < 0) ? -height : 0;
1967 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1969 else
1971 x_offset = x_src;
1972 y_offset = y_src;
1973 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1975 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1976 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
1977 wine_tsx11_unlock();
1978 LeaveCriticalSection( &xrender_cs );
1980 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1981 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1982 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
1985 /* create a pixmap and render picture for an image */
1986 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1987 struct bitblt_coords *src, enum wxr_format format,
1988 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1990 DWORD ret;
1991 int width = src->visrect.right - src->visrect.left;
1992 int height = src->visrect.bottom - src->visrect.top;
1993 int depth = pict_formats[format]->depth;
1994 struct gdi_image_bits dst_bits;
1995 XRenderPictureAttributes pa;
1996 XImage *image;
1998 wine_tsx11_lock();
1999 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2000 info->bmiHeader.biWidth, height, 32, 0 );
2001 wine_tsx11_unlock();
2002 if (!image) return ERROR_OUTOFMEMORY;
2004 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2005 if (ret) return ret;
2007 image->data = dst_bits.ptr;
2008 /* hack: make sure the bits are readable if we are reading from a DIB section */
2009 /* to be removed once we get rid of DIB access protections */
2010 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2012 *use_repeat = (width == 1 && height == 1);
2013 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2015 wine_tsx11_lock();
2016 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2017 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2018 src->visrect.left, 0, 0, 0, width, height );
2019 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2020 wine_tsx11_unlock();
2022 /* make coordinates relative to the pixmap */
2023 src->x -= src->visrect.left;
2024 src->y -= src->visrect.top;
2025 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2027 image->data = NULL;
2028 wine_tsx11_lock();
2029 XDestroyImage( image );
2030 wine_tsx11_unlock();
2031 if (dst_bits.free) dst_bits.free( &dst_bits );
2032 return ret;
2035 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2036 Drawable drawable, const struct bitblt_coords *src,
2037 const struct bitblt_coords *dst )
2039 int width = abs( dst->width );
2040 int height = abs( dst->height );
2041 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2042 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2043 int x_dst, y_dst;
2044 Picture src_pict = 0, dst_pict, mask_pict = 0;
2045 BOOL use_repeat;
2046 double xscale, yscale;
2048 use_repeat = use_source_repeat( physdev_src );
2049 if (!use_repeat)
2051 xscale = src->width / (double)dst->width;
2052 yscale = src->height / (double)dst->height;
2054 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2056 if (drawable) /* using an intermediate pixmap */
2058 XRenderPictureAttributes pa;
2060 x_dst = dst->x;
2061 y_dst = dst->y;
2062 pa.repeat = RepeatNone;
2063 wine_tsx11_lock();
2064 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2065 wine_tsx11_unlock();
2067 else
2069 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2070 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2071 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2074 if (src->width < 0) x_src += src->width + 1;
2075 if (src->height < 0) y_src += src->height + 1;
2076 if (dst->width < 0) x_dst += dst->width + 1;
2077 if (dst->height < 0) y_dst += dst->height + 1;
2079 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2081 /* mono -> color */
2082 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2084 XRenderColor fg, bg;
2086 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, &fg );
2087 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, &bg );
2088 fg.alpha = bg.alpha = 0;
2090 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2091 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2093 else /* color -> color (can be at different depths) or mono -> mono */
2095 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2096 mask_pict = get_no_alpha_mask();
2098 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2099 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2102 if (drawable)
2104 wine_tsx11_lock();
2105 pXRenderFreePicture( gdi_display, dst_pict );
2106 wine_tsx11_unlock();
2111 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2112 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2113 Drawable drawable, struct bitblt_coords *src,
2114 struct bitblt_coords *dst, BOOL use_repeat )
2116 int x_src, y_src, x_dst, y_dst;
2117 Picture dst_pict;
2118 XRenderPictureAttributes pa;
2119 double xscale, yscale;
2121 if (drawable) /* using an intermediate pixmap */
2123 RGNDATA *clip_data = NULL;
2125 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2126 x_dst = dst->x;
2127 y_dst = dst->y;
2128 pa.repeat = RepeatNone;
2129 wine_tsx11_lock();
2130 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2131 if (clip_data)
2132 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2133 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2134 wine_tsx11_unlock();
2135 HeapFree( GetProcessHeap(), 0, clip_data );
2137 else
2139 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2140 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2141 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2144 if (!use_repeat)
2146 xscale = src->width / (double)dst->width;
2147 yscale = src->height / (double)dst->height;
2149 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2151 x_src = src->x;
2152 y_src = src->y;
2153 if (src->width < 0) x_src += src->width + 1;
2154 if (src->height < 0) y_src += src->height + 1;
2155 if (dst->width < 0) x_dst += dst->width + 1;
2156 if (dst->height < 0) y_dst += dst->height + 1;
2158 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2159 xscale, yscale, abs( dst->width ), abs( dst->height ));
2161 if (drawable)
2163 wine_tsx11_lock();
2164 pXRenderFreePicture( gdi_display, dst_pict );
2165 wine_tsx11_unlock();
2170 /***********************************************************************
2171 * xrenderdrv_StretchBlt
2173 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2174 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2176 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2177 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2178 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2180 if (src_dev->funcs != dst_dev->funcs)
2182 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2183 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2186 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2188 /* XRender is of no use for color -> mono */
2189 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2190 goto x11drv_fallback;
2192 /* if not stretching, we only need to handle format conversion */
2193 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2195 if (rop != SRCCOPY)
2197 GC tmpGC;
2198 Pixmap tmp_pixmap;
2199 struct bitblt_coords tmp;
2201 /* make coordinates relative to tmp pixmap */
2202 tmp = *dst;
2203 tmp.x -= tmp.visrect.left;
2204 tmp.y -= tmp.visrect.top;
2205 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2207 wine_tsx11_lock();
2208 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2209 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2210 XSetGraphicsExposures( gdi_display, tmpGC, False );
2211 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2212 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2213 wine_tsx11_unlock();
2215 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2216 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2218 wine_tsx11_lock();
2219 XFreePixmap( gdi_display, tmp_pixmap );
2220 XFreeGC( gdi_display, tmpGC );
2221 wine_tsx11_unlock();
2223 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2225 return TRUE;
2227 x11drv_fallback:
2228 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2232 /***********************************************************************
2233 * xrenderdrv_PutImage
2235 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2236 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2237 struct bitblt_coords *dst, DWORD rop )
2239 struct xrender_physdev *physdev;
2240 X_PHYSBITMAP *bitmap;
2241 DWORD ret;
2242 Pixmap tmp_pixmap;
2243 GC gc;
2244 enum wxr_format src_format, dst_format;
2245 XRenderPictFormat *pict_format;
2246 Pixmap src_pixmap;
2247 Picture src_pict, mask_pict = 0;
2248 BOOL use_repeat;
2250 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2252 if (hbitmap)
2254 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2255 physdev = NULL;
2256 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2258 else
2260 physdev = get_xrender_dev( dev );
2261 bitmap = NULL;
2262 dst_format = physdev->format;
2265 src_format = get_xrender_format_from_bitmapinfo( info );
2266 if (!(pict_format = pict_formats[src_format])) goto update_format;
2268 /* make sure we can create an image with the same bpp */
2269 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2270 goto update_format;
2272 /* mono <-> color conversions not supported */
2273 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2274 goto x11drv_fallback;
2276 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2278 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2280 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2281 if (!ret)
2283 struct bitblt_coords tmp;
2285 if (bitmap)
2287 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2288 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2290 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2291 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2292 DeleteObject( rgn );
2294 else
2296 if (rop != SRCCOPY)
2298 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2300 /* make coordinates relative to tmp pixmap */
2301 tmp = *dst;
2302 tmp.x -= tmp.visrect.left;
2303 tmp.y -= tmp.visrect.top;
2304 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2306 wine_tsx11_lock();
2307 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2308 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2309 XSetGraphicsExposures( gdi_display, gc, False );
2310 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2311 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2312 wine_tsx11_unlock();
2314 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2315 NULL, tmp_pixmap, src, &tmp, use_repeat );
2316 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2318 wine_tsx11_lock();
2319 XFreePixmap( gdi_display, tmp_pixmap );
2320 XFreeGC( gdi_display, gc );
2321 wine_tsx11_unlock();
2323 if (restore_region) restore_clipping_region( physdev->x11dev );
2325 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2326 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2329 wine_tsx11_lock();
2330 pXRenderFreePicture( gdi_display, src_pict );
2331 XFreePixmap( gdi_display, src_pixmap );
2332 wine_tsx11_unlock();
2334 return ret;
2336 update_format:
2337 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2338 set_color_info( pict_formats[dst_format], info );
2339 return ERROR_BAD_FORMAT;
2341 x11drv_fallback:
2342 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2343 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2344 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2348 /***********************************************************************
2349 * xrenderdrv_BlendImage
2351 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2352 struct bitblt_coords *src, struct bitblt_coords *dst,
2353 BLENDFUNCTION func )
2355 struct xrender_physdev *physdev = get_xrender_dev( dev );
2356 DWORD ret;
2357 enum wxr_format format;
2358 XRenderPictFormat *pict_format;
2359 Picture dst_pict, src_pict, mask_pict;
2360 Pixmap src_pixmap;
2361 BOOL use_repeat;
2363 if (!X11DRV_XRender_Installed)
2365 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2366 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2369 format = get_xrender_format_from_bitmapinfo( info );
2370 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2371 format = get_format_without_alpha( format );
2372 else if (format != WXR_FORMAT_A8R8G8B8)
2373 return ERROR_INVALID_PARAMETER;
2375 if (!(pict_format = pict_formats[format])) goto update_format;
2377 /* make sure we can create an image with the same bpp */
2378 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2379 goto update_format;
2381 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2382 goto update_format;
2384 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2386 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2387 if (!ret)
2389 double xscale, yscale;
2391 if (!use_repeat)
2393 xscale = src->width / (double)dst->width;
2394 yscale = src->height / (double)dst->height;
2396 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2398 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2400 EnterCriticalSection( &xrender_cs );
2401 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2403 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2404 physdev->x11dev->dc_rect.left + dst->x,
2405 physdev->x11dev->dc_rect.top + dst->y,
2406 xscale, yscale, dst->width, dst->height );
2408 wine_tsx11_lock();
2409 pXRenderFreePicture( gdi_display, src_pict );
2410 XFreePixmap( gdi_display, src_pixmap );
2411 wine_tsx11_unlock();
2413 LeaveCriticalSection( &xrender_cs );
2415 return ret;
2417 update_format:
2418 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2419 set_color_info( physdev->pict_format, info );
2420 return ERROR_BAD_FORMAT;
2424 /***********************************************************************
2425 * xrenderdrv_AlphaBlend
2427 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2428 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2430 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2431 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2432 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2433 XRenderPictureAttributes pa;
2434 Pixmap tmp_pixmap = 0;
2435 double xscale, yscale;
2436 BOOL use_repeat;
2438 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2440 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2441 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2444 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2446 SetLastError( ERROR_INVALID_PARAMETER );
2447 return FALSE;
2450 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2452 use_repeat = use_source_repeat( physdev_src );
2453 if (!use_repeat)
2455 xscale = src->width / (double)dst->width;
2456 yscale = src->height / (double)dst->height;
2458 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2460 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2462 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2464 /* mono -> color blending needs an intermediate color pixmap */
2465 XRenderColor fg, bg;
2466 int width = src->visrect.right - src->visrect.left;
2467 int height = src->visrect.bottom - src->visrect.top;
2469 /* blending doesn't use the destination DC colors */
2470 fg.red = fg.green = fg.blue = 0;
2471 bg.red = bg.green = bg.blue = 0xffff;
2472 fg.alpha = bg.alpha = 0xffff;
2474 wine_tsx11_lock();
2475 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2476 physdev_dst->pict_format->depth );
2477 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2478 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2479 CPRepeat, &pa );
2480 wine_tsx11_unlock();
2482 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2483 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2485 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2487 /* we need a source picture with no alpha */
2488 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2489 if (format != physdev_src->format)
2491 wine_tsx11_lock();
2492 pa.subwindow_mode = IncludeInferiors;
2493 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2494 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2495 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2496 wine_tsx11_unlock();
2500 if (tmp_pict) src_pict = tmp_pict;
2502 EnterCriticalSection( &xrender_cs );
2503 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2505 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2506 physdev_src->x11dev->dc_rect.left + src->x,
2507 physdev_src->x11dev->dc_rect.top + src->y,
2508 physdev_dst->x11dev->dc_rect.left + dst->x,
2509 physdev_dst->x11dev->dc_rect.top + dst->y,
2510 xscale, yscale, dst->width, dst->height );
2512 wine_tsx11_lock();
2513 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2514 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2515 wine_tsx11_unlock();
2517 LeaveCriticalSection( &xrender_cs );
2518 return TRUE;
2521 /***********************************************************************
2522 * xrenderdrv_GradientFill
2524 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2525 void * grad_array, ULONG ngrad, ULONG mode )
2527 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2528 static const XFixed stops[2] = { 0, 1 << 16 };
2529 struct xrender_physdev *physdev = get_xrender_dev( dev );
2530 XLinearGradient gradient;
2531 XRenderColor colors[2];
2532 Picture src_pict, dst_pict;
2533 unsigned int i;
2534 const GRADIENT_RECT *rect = grad_array;
2535 POINT pt[2];
2537 if (!X11DRV_XRender_Installed) goto fallback;
2538 if (!pXRenderCreateLinearGradient) goto fallback;
2540 /* <= 16-bpp uses dithering */
2541 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2543 switch (mode)
2545 case GRADIENT_FILL_RECT_H:
2546 case GRADIENT_FILL_RECT_V:
2547 for (i = 0; i < ngrad; i++, rect++)
2549 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2550 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2552 colors[0].red = v1->Red * 257 / 256;
2553 colors[0].green = v1->Green * 257 / 256;
2554 colors[0].blue = v1->Blue * 257 / 256;
2555 colors[1].red = v2->Red * 257 / 256;
2556 colors[1].green = v2->Green * 257 / 256;
2557 colors[1].blue = v2->Blue * 257 / 256;
2558 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2559 colors[0].alpha = colors[1].alpha = 65535;
2561 pt[0].x = v1->x;
2562 pt[0].y = v1->y;
2563 pt[1].x = v2->x;
2564 pt[1].y = v2->y;
2565 LPtoDP( dev->hdc, pt, 2 );
2566 if (mode == GRADIENT_FILL_RECT_H)
2568 gradient.p1.y = gradient.p2.y = 0;
2569 if (pt[1].x > pt[0].x)
2571 gradient.p1.x = 0;
2572 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2574 else
2576 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2577 gradient.p2.x = 0;
2580 else
2582 gradient.p1.x = gradient.p2.x = 0;
2583 if (pt[1].y > pt[0].y)
2585 gradient.p1.y = 0;
2586 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2588 else
2590 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2591 gradient.p2.y = 0;
2595 TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2596 mode, pt[0].x, pt[0].y, pt[1].x, pt[1].y,
2597 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2598 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2600 dst_pict = get_xrender_picture( physdev, 0, NULL );
2602 wine_tsx11_lock();
2603 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2604 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0,
2605 physdev->x11dev->dc_rect.left + min( pt[0].x, pt[1].x ),
2606 physdev->x11dev->dc_rect.top + min( pt[0].y, pt[1].y ),
2607 1, 1, abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y) );
2608 pXRenderFreePicture( gdi_display, src_pict );
2609 wine_tsx11_unlock();
2611 return TRUE;
2614 fallback:
2615 #endif
2616 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2617 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2620 /***********************************************************************
2621 * xrenderdrv_SelectBrush
2623 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, HBITMAP bitmap,
2624 const BITMAPINFO *info, void *bits, UINT usage )
2626 struct xrender_physdev *physdev = get_xrender_dev( dev );
2627 X_PHYSBITMAP *physbitmap;
2628 enum wxr_format format;
2629 BOOL delete_bitmap = FALSE;
2630 BITMAP bm;
2631 Pixmap pixmap;
2632 Picture src_pict, dst_pict;
2633 XRenderPictureAttributes pa;
2635 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2636 if (!bitmap && !info) goto x11drv_fallback;
2637 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2639 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2641 if (!(bitmap = create_brush_bitmap( physdev->x11dev, info, bits, usage ))) return 0;
2642 physbitmap = X11DRV_get_phys_bitmap( bitmap );
2643 delete_bitmap = TRUE;
2646 format = get_xrender_format_from_color_shifts( physbitmap->depth, &physbitmap->color_shifts );
2647 if (format == WXR_FORMAT_MONO || !pict_formats[format]) goto x11drv_fallback;
2649 GetObjectW( bitmap, sizeof(bm), &bm );
2651 X11DRV_DIB_Lock( physbitmap, DIB_Status_GdiMod );
2653 wine_tsx11_lock();
2654 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2655 physdev->pict_format->depth );
2657 pa.repeat = RepeatNone;
2658 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_formats[format], CPRepeat, &pa);
2659 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2661 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, bm.bmWidth, bm.bmHeight );
2662 pXRenderFreePicture( gdi_display, src_pict );
2663 pXRenderFreePicture( gdi_display, dst_pict );
2665 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2666 physdev->x11dev->brush.pixmap = pixmap;
2667 physdev->x11dev->brush.fillStyle = FillTiled;
2668 physdev->x11dev->brush.pixel = 0; /* ignored */
2669 physdev->x11dev->brush.style = BS_PATTERN;
2670 wine_tsx11_unlock();
2672 X11DRV_DIB_Unlock( physbitmap, TRUE );
2673 if (delete_bitmap) DeleteObject( bitmap );
2674 return hbrush;
2676 x11drv_fallback:
2677 if (delete_bitmap) DeleteObject( bitmap );
2678 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2679 return dev->funcs->pSelectBrush( dev, hbrush, bitmap, info, bits, usage );
2683 static const struct gdi_dc_funcs xrender_funcs =
2685 NULL, /* pAbortDoc */
2686 NULL, /* pAbortPath */
2687 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2688 NULL, /* pAngleArc */
2689 NULL, /* pArc */
2690 NULL, /* pArcTo */
2691 NULL, /* pBeginPath */
2692 xrenderdrv_BlendImage, /* pBlendImage */
2693 NULL, /* pChoosePixelFormat */
2694 NULL, /* pChord */
2695 NULL, /* pCloseFigure */
2696 xrenderdrv_CopyBitmap, /* pCopyBitmap */
2697 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2698 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2699 xrenderdrv_CreateDC, /* pCreateDC */
2700 NULL, /* pCreateDIBSection */
2701 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2702 xrenderdrv_DeleteDC, /* pDeleteDC */
2703 NULL, /* pDeleteObject */
2704 NULL, /* pDescribePixelFormat */
2705 NULL, /* pDeviceCapabilities */
2706 NULL, /* pEllipse */
2707 NULL, /* pEndDoc */
2708 NULL, /* pEndPage */
2709 NULL, /* pEndPath */
2710 NULL, /* pEnumFonts */
2711 NULL, /* pEnumICMProfiles */
2712 NULL, /* pExcludeClipRect */
2713 NULL, /* pExtDeviceMode */
2714 xrenderdrv_ExtEscape, /* pExtEscape */
2715 NULL, /* pExtFloodFill */
2716 NULL, /* pExtSelectClipRgn */
2717 xrenderdrv_ExtTextOut, /* pExtTextOut */
2718 NULL, /* pFillPath */
2719 NULL, /* pFillRgn */
2720 NULL, /* pFlattenPath */
2721 NULL, /* pFontIsLinked */
2722 NULL, /* pFrameRgn */
2723 NULL, /* pGdiComment */
2724 NULL, /* pGdiRealizationInfo */
2725 NULL, /* pGetCharABCWidths */
2726 NULL, /* pGetCharABCWidthsI */
2727 NULL, /* pGetCharWidth */
2728 NULL, /* pGetDeviceCaps */
2729 NULL, /* pGetDeviceGammaRamp */
2730 NULL, /* pGetFontData */
2731 NULL, /* pGetFontUnicodeRanges */
2732 NULL, /* pGetGlyphIndices */
2733 NULL, /* pGetGlyphOutline */
2734 NULL, /* pGetICMProfile */
2735 xrenderdrv_GetImage, /* pGetImage */
2736 NULL, /* pGetKerningPairs */
2737 NULL, /* pGetNearestColor */
2738 NULL, /* pGetOutlineTextMetrics */
2739 NULL, /* pGetPixel */
2740 NULL, /* pGetPixelFormat */
2741 NULL, /* pGetSystemPaletteEntries */
2742 NULL, /* pGetTextCharsetInfo */
2743 NULL, /* pGetTextExtentExPoint */
2744 NULL, /* pGetTextExtentExPointI */
2745 NULL, /* pGetTextFace */
2746 NULL, /* pGetTextMetrics */
2747 xrenderdrv_GradientFill, /* pGradientFill */
2748 NULL, /* pIntersectClipRect */
2749 NULL, /* pInvertRgn */
2750 NULL, /* pLineTo */
2751 NULL, /* pModifyWorldTransform */
2752 NULL, /* pMoveTo */
2753 NULL, /* pOffsetClipRgn */
2754 NULL, /* pOffsetViewportOrg */
2755 NULL, /* pOffsetWindowOrg */
2756 NULL, /* pPaintRgn */
2757 NULL, /* pPatBlt */
2758 NULL, /* pPie */
2759 NULL, /* pPolyBezier */
2760 NULL, /* pPolyBezierTo */
2761 NULL, /* pPolyDraw */
2762 NULL, /* pPolyPolygon */
2763 NULL, /* pPolyPolyline */
2764 NULL, /* pPolygon */
2765 NULL, /* pPolyline */
2766 NULL, /* pPolylineTo */
2767 xrenderdrv_PutImage, /* pPutImage */
2768 NULL, /* pRealizeDefaultPalette */
2769 NULL, /* pRealizePalette */
2770 NULL, /* pRectangle */
2771 NULL, /* pResetDC */
2772 NULL, /* pRestoreDC */
2773 NULL, /* pRoundRect */
2774 NULL, /* pSaveDC */
2775 NULL, /* pScaleViewportExt */
2776 NULL, /* pScaleWindowExt */
2777 xrenderdrv_SelectBitmap, /* pSelectBitmap */
2778 xrenderdrv_SelectBrush, /* pSelectBrush */
2779 NULL, /* pSelectClipPath */
2780 xrenderdrv_SelectFont, /* pSelectFont */
2781 NULL, /* pSelectPalette */
2782 NULL, /* pSelectPen */
2783 NULL, /* pSetArcDirection */
2784 NULL, /* pSetBkColor */
2785 NULL, /* pSetBkMode */
2786 NULL, /* pSetDCBrushColor */
2787 NULL, /* pSetDCPenColor */
2788 NULL, /* pSetDIBColorTable */
2789 NULL, /* pSetDIBitsToDevice */
2790 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2791 NULL, /* pSetDeviceGammaRamp */
2792 NULL, /* pSetLayout */
2793 NULL, /* pSetMapMode */
2794 NULL, /* pSetMapperFlags */
2795 NULL, /* pSetPixel */
2796 NULL, /* pSetPixelFormat */
2797 NULL, /* pSetPolyFillMode */
2798 NULL, /* pSetROP2 */
2799 NULL, /* pSetRelAbs */
2800 NULL, /* pSetStretchBltMode */
2801 NULL, /* pSetTextAlign */
2802 NULL, /* pSetTextCharacterExtra */
2803 NULL, /* pSetTextColor */
2804 NULL, /* pSetTextJustification */
2805 NULL, /* pSetViewportExt */
2806 NULL, /* pSetViewportOrg */
2807 NULL, /* pSetWindowExt */
2808 NULL, /* pSetWindowOrg */
2809 NULL, /* pSetWorldTransform */
2810 NULL, /* pStartDoc */
2811 NULL, /* pStartPage */
2812 xrenderdrv_StretchBlt, /* pStretchBlt */
2813 NULL, /* pStretchDIBits */
2814 NULL, /* pStrokeAndFillPath */
2815 NULL, /* pStrokePath */
2816 NULL, /* pSwapBuffers */
2817 NULL, /* pUnrealizePalette */
2818 NULL, /* pWidenPath */
2819 /* OpenGL not supported */
2822 #else /* SONAME_LIBXRENDER */
2824 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2826 TRACE("XRender support not compiled in.\n");
2827 return NULL;
2830 void X11DRV_XRender_Finalize(void)
2834 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2836 return FALSE;
2839 #endif /* SONAME_LIBXRENDER */