shell32: Use S_OK as successful return code name.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blobcbe9185c0210081d782a9572a70b6d580c1c41a6
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 if(physdev->x11dev->depth == 1) {
1755 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1756 textPixel = 0;
1757 backgroundPixel = 1;
1758 } else {
1759 textPixel = 1;
1760 backgroundPixel = 0;
1762 } else {
1763 textPixel = physdev->x11dev->textPixel;
1764 backgroundPixel = physdev->x11dev->backgroundPixel;
1767 if(flags & ETO_OPAQUE)
1769 wine_tsx11_lock();
1770 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
1771 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
1772 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
1773 lprect->right - lprect->left, lprect->bottom - lprect->top );
1774 wine_tsx11_unlock();
1777 if(count == 0) return TRUE;
1779 EnterCriticalSection(&xrender_cs);
1781 entry = glyphsetCache + physdev->cache_index;
1782 aa_type = entry->aa_default;
1783 formatEntry = entry->format[aa_type];
1785 for(idx = 0; idx < count; idx++) {
1786 if( !formatEntry ) {
1787 UploadGlyph(physdev, wstr[idx], aa_type);
1788 /* re-evaluate antialias since aa_default may have changed */
1789 aa_type = entry->aa_default;
1790 formatEntry = entry->format[aa_type];
1791 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1792 UploadGlyph(physdev, wstr[idx], aa_type);
1795 if (!formatEntry)
1797 WARN("could not upload requested glyphs\n");
1798 LeaveCriticalSection(&xrender_cs);
1799 return FALSE;
1802 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1803 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1805 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1806 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1808 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1809 So we pass zeros to the function and move to our starting position using the first
1810 element of the elts array. */
1812 desired.x = physdev->x11dev->dc_rect.left + x;
1813 desired.y = physdev->x11dev->dc_rect.top + y;
1814 offset.x = offset.y = 0;
1815 current.x = current.y = 0;
1817 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
1818 tile_pict = get_tile_pict(physdev->format, &col);
1820 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1822 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
1823 render_op = PictOpOutReverse; /* This gives us 'black' text */
1825 for(idx = 0; idx < count; idx++)
1827 elts[idx].glyphset = formatEntry->glyphset;
1828 elts[idx].chars = wstr + idx;
1829 elts[idx].nchars = 1;
1830 elts[idx].xOff = desired.x - current.x;
1831 elts[idx].yOff = desired.y - current.y;
1833 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1834 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1836 if(!lpDx)
1838 desired.x += formatEntry->gis[wstr[idx]].xOff;
1839 desired.y += formatEntry->gis[wstr[idx]].yOff;
1841 else
1843 if(flags & ETO_PDY)
1845 offset.x += lpDx[idx * 2];
1846 offset.y += lpDx[idx * 2 + 1];
1848 else
1849 offset.x += lpDx[idx];
1850 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1851 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1855 wine_tsx11_lock();
1856 /* Make sure we don't have any transforms set from a previous call */
1857 set_xrender_transformation(pict, 1, 1, 0, 0);
1858 pXRenderCompositeText16(gdi_display, render_op,
1859 tile_pict,
1860 pict,
1861 formatEntry->font_format,
1862 0, 0, 0, 0, elts, count);
1863 wine_tsx11_unlock();
1864 HeapFree(GetProcessHeap(), 0, elts);
1866 LeaveCriticalSection(&xrender_cs);
1867 return TRUE;
1870 /* multiply the alpha channel of a picture */
1871 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1872 int x, int y, int width, int height )
1874 XRenderPictureAttributes pa;
1875 Pixmap src_pixmap, mask_pixmap;
1876 Picture src_pict, mask_pict;
1877 XRenderColor color;
1879 wine_tsx11_lock();
1880 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1881 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1882 pa.repeat = RepeatNormal;
1883 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1884 pa.component_alpha = True;
1885 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1886 color.red = color.green = color.blue = color.alpha = 0xffff;
1887 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1888 color.alpha = alpha;
1889 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1890 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1891 0, 0, 0, 0, x, y, width, height );
1892 pXRenderFreePicture( gdi_display, src_pict );
1893 pXRenderFreePicture( gdi_display, mask_pict );
1894 XFreePixmap( gdi_display, src_pixmap );
1895 XFreePixmap( gdi_display, mask_pixmap );
1896 wine_tsx11_unlock();
1899 /* Helper function for (stretched) blitting using xrender */
1900 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1901 int x_src, int y_src, int x_dst, int y_dst,
1902 double xscale, double yscale, int width, int height )
1904 int x_offset, y_offset;
1906 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1907 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1908 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1909 wine_tsx11_lock();
1910 if(xscale != 1.0 || yscale != 1.0)
1912 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1913 * in the wrong quadrant of the x-y plane.
1915 x_offset = (xscale < 0) ? -width : 0;
1916 y_offset = (yscale < 0) ? -height : 0;
1917 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1919 else
1921 x_offset = x_src;
1922 y_offset = y_src;
1923 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1925 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1926 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
1927 wine_tsx11_unlock();
1930 /* Helper function for (stretched) mono->color blitting using xrender */
1931 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1932 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1933 int x_src, int y_src, int x_dst, int y_dst,
1934 double xscale, double yscale, int width, int height )
1936 Picture tile_pict;
1937 int x_offset, y_offset;
1938 XRenderColor color;
1940 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1941 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1942 * the tile data.
1944 EnterCriticalSection( &xrender_cs );
1945 color = *bg;
1946 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1947 tile_pict = get_tile_pict( dst_format, &color );
1949 wine_tsx11_lock();
1950 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
1952 if (xscale != 1.0 || yscale != 1.0)
1954 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1955 * in the wrong quadrant of the x-y plane.
1957 x_offset = (xscale < 0) ? -width : 0;
1958 y_offset = (yscale < 0) ? -height : 0;
1959 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1961 else
1963 x_offset = x_src;
1964 y_offset = y_src;
1965 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1967 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1968 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
1969 wine_tsx11_unlock();
1970 LeaveCriticalSection( &xrender_cs );
1972 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1973 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1974 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
1977 /* create a pixmap and render picture for an image */
1978 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1979 struct bitblt_coords *src, enum wxr_format format,
1980 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1982 DWORD ret;
1983 int width = src->visrect.right - src->visrect.left;
1984 int height = src->visrect.bottom - src->visrect.top;
1985 int depth = pict_formats[format]->depth;
1986 struct gdi_image_bits dst_bits;
1987 XRenderPictureAttributes pa;
1988 XImage *image;
1990 wine_tsx11_lock();
1991 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1992 info->bmiHeader.biWidth, height, 32, 0 );
1993 wine_tsx11_unlock();
1994 if (!image) return ERROR_OUTOFMEMORY;
1996 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1997 if (ret) return ret;
1999 image->data = dst_bits.ptr;
2000 /* hack: make sure the bits are readable if we are reading from a DIB section */
2001 /* to be removed once we get rid of DIB access protections */
2002 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2004 *use_repeat = (width == 1 && height == 1);
2005 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2007 wine_tsx11_lock();
2008 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2009 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2010 src->visrect.left, 0, 0, 0, width, height );
2011 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2012 wine_tsx11_unlock();
2014 /* make coordinates relative to the pixmap */
2015 src->x -= src->visrect.left;
2016 src->y -= src->visrect.top;
2017 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2019 image->data = NULL;
2020 wine_tsx11_lock();
2021 XDestroyImage( image );
2022 wine_tsx11_unlock();
2023 if (dst_bits.free) dst_bits.free( &dst_bits );
2024 return ret;
2027 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2028 Drawable drawable, const struct bitblt_coords *src,
2029 const struct bitblt_coords *dst )
2031 int width = abs( dst->width );
2032 int height = abs( dst->height );
2033 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2034 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2035 int x_dst, y_dst;
2036 Picture src_pict = 0, dst_pict, mask_pict = 0;
2037 BOOL use_repeat;
2038 double xscale, yscale;
2040 use_repeat = use_source_repeat( physdev_src );
2041 if (!use_repeat)
2043 xscale = src->width / (double)dst->width;
2044 yscale = src->height / (double)dst->height;
2046 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2048 if (drawable) /* using an intermediate pixmap */
2050 XRenderPictureAttributes pa;
2052 x_dst = dst->x;
2053 y_dst = dst->y;
2054 pa.repeat = RepeatNone;
2055 wine_tsx11_lock();
2056 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2057 wine_tsx11_unlock();
2059 else
2061 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2062 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2063 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2066 if (src->width < 0) x_src += src->width + 1;
2067 if (src->height < 0) y_src += src->height + 1;
2068 if (dst->width < 0) x_dst += dst->width + 1;
2069 if (dst->height < 0) y_dst += dst->height + 1;
2071 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2073 /* mono -> color */
2074 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2076 XRenderColor fg, bg;
2078 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, &fg );
2079 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, &bg );
2080 fg.alpha = bg.alpha = 0;
2082 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2083 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2085 else /* color -> color (can be at different depths) or mono -> mono */
2087 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2088 mask_pict = get_no_alpha_mask();
2090 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2091 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2094 if (drawable)
2096 wine_tsx11_lock();
2097 pXRenderFreePicture( gdi_display, dst_pict );
2098 wine_tsx11_unlock();
2103 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2104 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2105 Drawable drawable, struct bitblt_coords *src,
2106 struct bitblt_coords *dst, BOOL use_repeat )
2108 int x_src, y_src, x_dst, y_dst;
2109 Picture dst_pict;
2110 XRenderPictureAttributes pa;
2111 double xscale, yscale;
2113 if (drawable) /* using an intermediate pixmap */
2115 RGNDATA *clip_data = NULL;
2117 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2118 x_dst = dst->x;
2119 y_dst = dst->y;
2120 pa.repeat = RepeatNone;
2121 wine_tsx11_lock();
2122 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2123 if (clip_data)
2124 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2125 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2126 wine_tsx11_unlock();
2127 HeapFree( GetProcessHeap(), 0, clip_data );
2129 else
2131 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2132 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2133 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2136 if (!use_repeat)
2138 xscale = src->width / (double)dst->width;
2139 yscale = src->height / (double)dst->height;
2141 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2143 x_src = src->x;
2144 y_src = src->y;
2145 if (src->width < 0) x_src += src->width + 1;
2146 if (src->height < 0) y_src += src->height + 1;
2147 if (dst->width < 0) x_dst += dst->width + 1;
2148 if (dst->height < 0) y_dst += dst->height + 1;
2150 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2151 xscale, yscale, abs( dst->width ), abs( dst->height ));
2153 if (drawable)
2155 wine_tsx11_lock();
2156 pXRenderFreePicture( gdi_display, dst_pict );
2157 wine_tsx11_unlock();
2162 /***********************************************************************
2163 * xrenderdrv_StretchBlt
2165 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2166 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2168 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2169 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2170 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2172 if (src_dev->funcs != dst_dev->funcs)
2174 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2175 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2178 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2180 /* XRender is of no use for color -> mono */
2181 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2182 goto x11drv_fallback;
2184 /* if not stretching, we only need to handle format conversion */
2185 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2187 if (rop != SRCCOPY)
2189 GC tmpGC;
2190 Pixmap tmp_pixmap;
2191 struct bitblt_coords tmp;
2193 /* make coordinates relative to tmp pixmap */
2194 tmp = *dst;
2195 tmp.x -= tmp.visrect.left;
2196 tmp.y -= tmp.visrect.top;
2197 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2199 wine_tsx11_lock();
2200 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2201 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2202 XSetGraphicsExposures( gdi_display, tmpGC, False );
2203 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2204 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2205 wine_tsx11_unlock();
2207 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2208 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2210 wine_tsx11_lock();
2211 XFreePixmap( gdi_display, tmp_pixmap );
2212 XFreeGC( gdi_display, tmpGC );
2213 wine_tsx11_unlock();
2215 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2217 return TRUE;
2219 x11drv_fallback:
2220 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2224 /***********************************************************************
2225 * xrenderdrv_PutImage
2227 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2228 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2229 struct bitblt_coords *dst, DWORD rop )
2231 struct xrender_physdev *physdev;
2232 X_PHYSBITMAP *bitmap;
2233 DWORD ret;
2234 Pixmap tmp_pixmap;
2235 GC gc;
2236 enum wxr_format src_format, dst_format;
2237 XRenderPictFormat *pict_format;
2238 Pixmap src_pixmap;
2239 Picture src_pict, mask_pict = 0;
2240 BOOL use_repeat;
2242 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2244 if (hbitmap)
2246 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2247 physdev = NULL;
2248 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2250 else
2252 physdev = get_xrender_dev( dev );
2253 bitmap = NULL;
2254 dst_format = physdev->format;
2257 src_format = get_xrender_format_from_bitmapinfo( info );
2258 if (!(pict_format = pict_formats[src_format])) goto update_format;
2260 /* make sure we can create an image with the same bpp */
2261 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2262 goto update_format;
2264 /* mono <-> color conversions not supported */
2265 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2266 goto x11drv_fallback;
2268 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2270 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2272 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2273 if (!ret)
2275 struct bitblt_coords tmp;
2277 if (bitmap)
2279 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2280 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2282 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2283 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2284 DeleteObject( rgn );
2286 else
2288 if (rop != SRCCOPY)
2290 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2292 /* make coordinates relative to tmp pixmap */
2293 tmp = *dst;
2294 tmp.x -= tmp.visrect.left;
2295 tmp.y -= tmp.visrect.top;
2296 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2298 wine_tsx11_lock();
2299 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2300 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2301 XSetGraphicsExposures( gdi_display, gc, False );
2302 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2303 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2304 wine_tsx11_unlock();
2306 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2307 NULL, tmp_pixmap, src, &tmp, use_repeat );
2308 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2310 wine_tsx11_lock();
2311 XFreePixmap( gdi_display, tmp_pixmap );
2312 XFreeGC( gdi_display, gc );
2313 wine_tsx11_unlock();
2315 if (restore_region) restore_clipping_region( physdev->x11dev );
2317 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2318 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2321 wine_tsx11_lock();
2322 pXRenderFreePicture( gdi_display, src_pict );
2323 XFreePixmap( gdi_display, src_pixmap );
2324 wine_tsx11_unlock();
2326 return ret;
2328 update_format:
2329 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2330 set_color_info( pict_formats[dst_format], info );
2331 return ERROR_BAD_FORMAT;
2333 x11drv_fallback:
2334 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2335 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2336 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2340 /***********************************************************************
2341 * xrenderdrv_BlendImage
2343 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2344 struct bitblt_coords *src, struct bitblt_coords *dst,
2345 BLENDFUNCTION func )
2347 struct xrender_physdev *physdev = get_xrender_dev( dev );
2348 DWORD ret;
2349 enum wxr_format format;
2350 XRenderPictFormat *pict_format;
2351 Picture dst_pict, src_pict, mask_pict;
2352 Pixmap src_pixmap;
2353 BOOL use_repeat;
2355 if (!X11DRV_XRender_Installed)
2357 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2358 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2361 format = get_xrender_format_from_bitmapinfo( info );
2362 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2363 format = get_format_without_alpha( format );
2364 else if (format != WXR_FORMAT_A8R8G8B8)
2365 return ERROR_INVALID_PARAMETER;
2367 if (!(pict_format = pict_formats[format])) goto update_format;
2369 /* make sure we can create an image with the same bpp */
2370 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2371 goto update_format;
2373 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2374 goto update_format;
2376 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2378 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2379 if (!ret)
2381 double xscale, yscale;
2383 if (!use_repeat)
2385 xscale = src->width / (double)dst->width;
2386 yscale = src->height / (double)dst->height;
2388 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2390 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2392 EnterCriticalSection( &xrender_cs );
2393 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2395 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2396 physdev->x11dev->dc_rect.left + dst->x,
2397 physdev->x11dev->dc_rect.top + dst->y,
2398 xscale, yscale, dst->width, dst->height );
2400 wine_tsx11_lock();
2401 pXRenderFreePicture( gdi_display, src_pict );
2402 XFreePixmap( gdi_display, src_pixmap );
2403 wine_tsx11_unlock();
2405 LeaveCriticalSection( &xrender_cs );
2407 return ret;
2409 update_format:
2410 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2411 set_color_info( physdev->pict_format, info );
2412 return ERROR_BAD_FORMAT;
2416 /***********************************************************************
2417 * xrenderdrv_AlphaBlend
2419 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2420 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2422 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2423 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2424 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2425 XRenderPictureAttributes pa;
2426 Pixmap tmp_pixmap = 0;
2427 double xscale, yscale;
2428 BOOL use_repeat;
2430 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2432 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2433 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2436 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2438 SetLastError( ERROR_INVALID_PARAMETER );
2439 return FALSE;
2442 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2444 use_repeat = use_source_repeat( physdev_src );
2445 if (!use_repeat)
2447 xscale = src->width / (double)dst->width;
2448 yscale = src->height / (double)dst->height;
2450 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2452 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2454 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2456 /* mono -> color blending needs an intermediate color pixmap */
2457 XRenderColor fg, bg;
2458 int width = src->visrect.right - src->visrect.left;
2459 int height = src->visrect.bottom - src->visrect.top;
2461 /* blending doesn't use the destination DC colors */
2462 fg.red = fg.green = fg.blue = 0;
2463 bg.red = bg.green = bg.blue = 0xffff;
2464 fg.alpha = bg.alpha = 0xffff;
2466 wine_tsx11_lock();
2467 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2468 physdev_dst->pict_format->depth );
2469 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2470 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2471 CPRepeat, &pa );
2472 wine_tsx11_unlock();
2474 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2475 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2477 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2479 /* we need a source picture with no alpha */
2480 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2481 if (format != physdev_src->format)
2483 wine_tsx11_lock();
2484 pa.subwindow_mode = IncludeInferiors;
2485 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2486 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2487 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2488 wine_tsx11_unlock();
2492 if (tmp_pict) src_pict = tmp_pict;
2494 EnterCriticalSection( &xrender_cs );
2495 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2497 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2498 physdev_src->x11dev->dc_rect.left + src->x,
2499 physdev_src->x11dev->dc_rect.top + src->y,
2500 physdev_dst->x11dev->dc_rect.left + dst->x,
2501 physdev_dst->x11dev->dc_rect.top + dst->y,
2502 xscale, yscale, dst->width, dst->height );
2504 wine_tsx11_lock();
2505 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2506 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2507 wine_tsx11_unlock();
2509 LeaveCriticalSection( &xrender_cs );
2510 return TRUE;
2513 /***********************************************************************
2514 * xrenderdrv_GradientFill
2516 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2517 void * grad_array, ULONG ngrad, ULONG mode )
2519 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2520 static const XFixed stops[2] = { 0, 1 << 16 };
2521 struct xrender_physdev *physdev = get_xrender_dev( dev );
2522 XLinearGradient gradient;
2523 XRenderColor colors[2];
2524 Picture src_pict, dst_pict;
2525 unsigned int i;
2526 const GRADIENT_RECT *rect = grad_array;
2527 POINT pt[2];
2529 if (!X11DRV_XRender_Installed) goto fallback;
2530 if (!pXRenderCreateLinearGradient) goto fallback;
2532 /* <= 16-bpp uses dithering */
2533 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2535 switch (mode)
2537 case GRADIENT_FILL_RECT_H:
2538 case GRADIENT_FILL_RECT_V:
2539 for (i = 0; i < ngrad; i++, rect++)
2541 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2542 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2544 colors[0].red = v1->Red * 257 / 256;
2545 colors[0].green = v1->Green * 257 / 256;
2546 colors[0].blue = v1->Blue * 257 / 256;
2547 colors[1].red = v2->Red * 257 / 256;
2548 colors[1].green = v2->Green * 257 / 256;
2549 colors[1].blue = v2->Blue * 257 / 256;
2550 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2551 colors[0].alpha = colors[1].alpha = 65535;
2553 pt[0].x = v1->x;
2554 pt[0].y = v1->y;
2555 pt[1].x = v2->x;
2556 pt[1].y = v2->y;
2557 LPtoDP( dev->hdc, pt, 2 );
2558 if (mode == GRADIENT_FILL_RECT_H)
2560 gradient.p1.y = gradient.p2.y = 0;
2561 if (pt[1].x > pt[0].x)
2563 gradient.p1.x = 0;
2564 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2566 else
2568 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2569 gradient.p2.x = 0;
2572 else
2574 gradient.p1.x = gradient.p2.x = 0;
2575 if (pt[1].y > pt[0].y)
2577 gradient.p1.y = 0;
2578 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2580 else
2582 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2583 gradient.p2.y = 0;
2587 TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2588 mode, pt[0].x, pt[0].y, pt[1].x, pt[1].y,
2589 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2590 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2592 dst_pict = get_xrender_picture( physdev, 0, NULL );
2594 wine_tsx11_lock();
2595 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2596 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0,
2597 physdev->x11dev->dc_rect.left + min( pt[0].x, pt[1].x ),
2598 physdev->x11dev->dc_rect.top + min( pt[0].y, pt[1].y ),
2599 1, 1, abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y) );
2600 pXRenderFreePicture( gdi_display, src_pict );
2601 wine_tsx11_unlock();
2603 return TRUE;
2606 fallback:
2607 #endif
2608 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2609 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2612 /***********************************************************************
2613 * xrenderdrv_SelectBrush
2615 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2617 struct xrender_physdev *physdev = get_xrender_dev( dev );
2618 X_PHYSBITMAP *physbitmap;
2619 enum wxr_format format;
2620 BOOL delete_bitmap = FALSE;
2621 BITMAP bm;
2622 HBITMAP bitmap;
2623 Pixmap pixmap;
2624 Picture src_pict, dst_pict;
2625 XRenderPictureAttributes pa;
2627 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2628 if (!pattern) goto x11drv_fallback;
2629 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2631 bitmap = pattern->bitmap;
2632 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2634 if (!(bitmap = create_brush_bitmap( physdev->x11dev, pattern ))) return 0;
2635 physbitmap = X11DRV_get_phys_bitmap( bitmap );
2636 delete_bitmap = TRUE;
2639 format = get_xrender_format_from_color_shifts( physbitmap->depth, &physbitmap->color_shifts );
2640 if (format == WXR_FORMAT_MONO || !pict_formats[format]) goto x11drv_fallback;
2642 GetObjectW( bitmap, sizeof(bm), &bm );
2644 X11DRV_DIB_Lock( physbitmap, DIB_Status_GdiMod );
2646 wine_tsx11_lock();
2647 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2648 physdev->pict_format->depth );
2650 pa.repeat = RepeatNone;
2651 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_formats[format], CPRepeat, &pa);
2652 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2654 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, bm.bmWidth, bm.bmHeight );
2655 pXRenderFreePicture( gdi_display, src_pict );
2656 pXRenderFreePicture( gdi_display, dst_pict );
2658 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2659 physdev->x11dev->brush.pixmap = pixmap;
2660 physdev->x11dev->brush.fillStyle = FillTiled;
2661 physdev->x11dev->brush.pixel = 0; /* ignored */
2662 physdev->x11dev->brush.style = BS_PATTERN;
2663 wine_tsx11_unlock();
2665 X11DRV_DIB_Unlock( physbitmap, TRUE );
2666 if (delete_bitmap) DeleteObject( bitmap );
2667 return hbrush;
2669 x11drv_fallback:
2670 if (delete_bitmap) DeleteObject( bitmap );
2671 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2672 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2676 static const struct gdi_dc_funcs xrender_funcs =
2678 NULL, /* pAbortDoc */
2679 NULL, /* pAbortPath */
2680 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2681 NULL, /* pAngleArc */
2682 NULL, /* pArc */
2683 NULL, /* pArcTo */
2684 NULL, /* pBeginPath */
2685 xrenderdrv_BlendImage, /* pBlendImage */
2686 NULL, /* pChoosePixelFormat */
2687 NULL, /* pChord */
2688 NULL, /* pCloseFigure */
2689 xrenderdrv_CopyBitmap, /* pCopyBitmap */
2690 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2691 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2692 xrenderdrv_CreateDC, /* pCreateDC */
2693 NULL, /* pCreateDIBSection */
2694 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2695 xrenderdrv_DeleteDC, /* pDeleteDC */
2696 NULL, /* pDeleteObject */
2697 NULL, /* pDescribePixelFormat */
2698 NULL, /* pDeviceCapabilities */
2699 NULL, /* pEllipse */
2700 NULL, /* pEndDoc */
2701 NULL, /* pEndPage */
2702 NULL, /* pEndPath */
2703 NULL, /* pEnumFonts */
2704 NULL, /* pEnumICMProfiles */
2705 NULL, /* pExcludeClipRect */
2706 NULL, /* pExtDeviceMode */
2707 xrenderdrv_ExtEscape, /* pExtEscape */
2708 NULL, /* pExtFloodFill */
2709 NULL, /* pExtSelectClipRgn */
2710 xrenderdrv_ExtTextOut, /* pExtTextOut */
2711 NULL, /* pFillPath */
2712 NULL, /* pFillRgn */
2713 NULL, /* pFlattenPath */
2714 NULL, /* pFontIsLinked */
2715 NULL, /* pFrameRgn */
2716 NULL, /* pGdiComment */
2717 NULL, /* pGdiRealizationInfo */
2718 NULL, /* pGetCharABCWidths */
2719 NULL, /* pGetCharABCWidthsI */
2720 NULL, /* pGetCharWidth */
2721 NULL, /* pGetDeviceCaps */
2722 NULL, /* pGetDeviceGammaRamp */
2723 NULL, /* pGetFontData */
2724 NULL, /* pGetFontUnicodeRanges */
2725 NULL, /* pGetGlyphIndices */
2726 NULL, /* pGetGlyphOutline */
2727 NULL, /* pGetICMProfile */
2728 xrenderdrv_GetImage, /* pGetImage */
2729 NULL, /* pGetKerningPairs */
2730 NULL, /* pGetNearestColor */
2731 NULL, /* pGetOutlineTextMetrics */
2732 NULL, /* pGetPixel */
2733 NULL, /* pGetPixelFormat */
2734 NULL, /* pGetSystemPaletteEntries */
2735 NULL, /* pGetTextCharsetInfo */
2736 NULL, /* pGetTextExtentExPoint */
2737 NULL, /* pGetTextExtentExPointI */
2738 NULL, /* pGetTextFace */
2739 NULL, /* pGetTextMetrics */
2740 xrenderdrv_GradientFill, /* pGradientFill */
2741 NULL, /* pIntersectClipRect */
2742 NULL, /* pInvertRgn */
2743 NULL, /* pLineTo */
2744 NULL, /* pModifyWorldTransform */
2745 NULL, /* pMoveTo */
2746 NULL, /* pOffsetClipRgn */
2747 NULL, /* pOffsetViewportOrg */
2748 NULL, /* pOffsetWindowOrg */
2749 NULL, /* pPaintRgn */
2750 NULL, /* pPatBlt */
2751 NULL, /* pPie */
2752 NULL, /* pPolyBezier */
2753 NULL, /* pPolyBezierTo */
2754 NULL, /* pPolyDraw */
2755 NULL, /* pPolyPolygon */
2756 NULL, /* pPolyPolyline */
2757 NULL, /* pPolygon */
2758 NULL, /* pPolyline */
2759 NULL, /* pPolylineTo */
2760 xrenderdrv_PutImage, /* pPutImage */
2761 NULL, /* pRealizeDefaultPalette */
2762 NULL, /* pRealizePalette */
2763 NULL, /* pRectangle */
2764 NULL, /* pResetDC */
2765 NULL, /* pRestoreDC */
2766 NULL, /* pRoundRect */
2767 NULL, /* pSaveDC */
2768 NULL, /* pScaleViewportExt */
2769 NULL, /* pScaleWindowExt */
2770 xrenderdrv_SelectBitmap, /* pSelectBitmap */
2771 xrenderdrv_SelectBrush, /* pSelectBrush */
2772 NULL, /* pSelectClipPath */
2773 xrenderdrv_SelectFont, /* pSelectFont */
2774 NULL, /* pSelectPalette */
2775 NULL, /* pSelectPen */
2776 NULL, /* pSetArcDirection */
2777 NULL, /* pSetBkColor */
2778 NULL, /* pSetBkMode */
2779 NULL, /* pSetDCBrushColor */
2780 NULL, /* pSetDCPenColor */
2781 NULL, /* pSetDIBitsToDevice */
2782 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2783 NULL, /* pSetDeviceGammaRamp */
2784 NULL, /* pSetLayout */
2785 NULL, /* pSetMapMode */
2786 NULL, /* pSetMapperFlags */
2787 NULL, /* pSetPixel */
2788 NULL, /* pSetPixelFormat */
2789 NULL, /* pSetPolyFillMode */
2790 NULL, /* pSetROP2 */
2791 NULL, /* pSetRelAbs */
2792 NULL, /* pSetStretchBltMode */
2793 NULL, /* pSetTextAlign */
2794 NULL, /* pSetTextCharacterExtra */
2795 NULL, /* pSetTextColor */
2796 NULL, /* pSetTextJustification */
2797 NULL, /* pSetViewportExt */
2798 NULL, /* pSetViewportOrg */
2799 NULL, /* pSetWindowExt */
2800 NULL, /* pSetWindowOrg */
2801 NULL, /* pSetWorldTransform */
2802 NULL, /* pStartDoc */
2803 NULL, /* pStartPage */
2804 xrenderdrv_StretchBlt, /* pStretchBlt */
2805 NULL, /* pStretchDIBits */
2806 NULL, /* pStrokeAndFillPath */
2807 NULL, /* pStrokePath */
2808 NULL, /* pSwapBuffers */
2809 NULL, /* pUnrealizePalette */
2810 NULL, /* pWidenPath */
2811 /* OpenGL not supported */
2814 #else /* SONAME_LIBXRENDER */
2816 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2818 TRACE("XRender support not compiled in.\n");
2819 return NULL;
2822 void X11DRV_XRender_Finalize(void)
2826 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2828 return FALSE;
2831 #endif /* SONAME_LIBXRENDER */