joy.cpl: Correct joystick testing thread behavior.
[wine.git] / dlls / winex11.drv / xrender.c
blob85229a74bac54ae796b054590e61914a7727a67a
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 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
43 #ifdef SONAME_LIBXRENDER
45 WINE_DECLARE_DEBUG_CHANNEL(winediag);
47 #include <X11/Xlib.h>
48 #include <X11/extensions/Xrender.h>
50 #ifndef RepeatNone /* added in 0.10 */
51 #define RepeatNone 0
52 #define RepeatNormal 1
53 #define RepeatPad 2
54 #define RepeatReflect 3
55 #endif
57 enum wxr_format
59 WXR_FORMAT_MONO,
60 WXR_FORMAT_GRAY,
61 WXR_FORMAT_X1R5G5B5,
62 WXR_FORMAT_X1B5G5R5,
63 WXR_FORMAT_R5G6B5,
64 WXR_FORMAT_B5G6R5,
65 WXR_FORMAT_R8G8B8,
66 WXR_FORMAT_B8G8R8,
67 WXR_FORMAT_A8R8G8B8,
68 WXR_FORMAT_B8G8R8A8,
69 WXR_FORMAT_X8R8G8B8,
70 WXR_FORMAT_B8G8R8X8,
71 WXR_NB_FORMATS,
72 WXR_INVALID_FORMAT = WXR_NB_FORMATS
75 typedef struct wine_xrender_format_template
77 unsigned int depth;
78 unsigned int alpha;
79 unsigned int alphaMask;
80 unsigned int red;
81 unsigned int redMask;
82 unsigned int green;
83 unsigned int greenMask;
84 unsigned int blue;
85 unsigned int blueMask;
86 } WineXRenderFormatTemplate;
88 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
90 /* Format depth alpha mask red mask green mask blue mask*/
91 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
92 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
93 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
94 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
95 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
96 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
97 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
98 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
99 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
101 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
105 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
107 /* format phys red phys green phys blue log red log green log blue */
108 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
109 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
110 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
111 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
112 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
113 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
114 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
115 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
116 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
118 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
122 static enum wxr_format default_format = WXR_INVALID_FORMAT;
123 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
125 typedef struct
127 LOGFONTW lf;
128 XFORM xform;
129 SIZE devsize; /* size in device coords */
130 DWORD hash;
131 } LFANDSIZE;
133 #define INITIAL_REALIZED_BUF_SIZE 128
135 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
137 typedef struct
139 GlyphSet glyphset;
140 XRenderPictFormat *font_format;
141 int nrealized;
142 BOOL *realized;
143 XGlyphInfo *gis;
144 } gsCacheEntryFormat;
146 typedef struct
148 LFANDSIZE lfsz;
149 AA_Type aa_default;
150 gsCacheEntryFormat * format[AA_MAXVALUE];
151 INT count;
152 INT next;
153 } gsCacheEntry;
155 struct xrender_physdev
157 struct gdi_physdev dev;
158 X11DRV_PDEVICE *x11dev;
159 HRGN region;
160 enum wxr_format format;
161 int cache_index;
162 BOOL update_clip;
163 Picture pict;
164 Picture pict_src;
165 XRenderPictFormat *pict_format;
168 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
170 return (struct xrender_physdev *)dev;
173 static const struct gdi_dc_funcs xrender_funcs;
175 static gsCacheEntry *glyphsetCache = NULL;
176 static DWORD glyphsetCacheSize = 0;
177 static INT lastfree = -1;
178 static INT mru = -1;
180 #define INIT_CACHE_SIZE 10
182 static int antialias = 1;
184 static void *xrender_handle;
186 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
187 MAKE_FUNCPTR(XRenderAddGlyphs)
188 MAKE_FUNCPTR(XRenderChangePicture)
189 MAKE_FUNCPTR(XRenderComposite)
190 MAKE_FUNCPTR(XRenderCompositeText16)
191 MAKE_FUNCPTR(XRenderCreateGlyphSet)
192 MAKE_FUNCPTR(XRenderCreatePicture)
193 MAKE_FUNCPTR(XRenderFillRectangle)
194 MAKE_FUNCPTR(XRenderFindFormat)
195 MAKE_FUNCPTR(XRenderFindVisualFormat)
196 MAKE_FUNCPTR(XRenderFreeGlyphSet)
197 MAKE_FUNCPTR(XRenderFreePicture)
198 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
199 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
200 MAKE_FUNCPTR(XRenderCreateLinearGradient)
201 #endif
202 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
203 MAKE_FUNCPTR(XRenderSetPictureTransform)
204 #endif
205 MAKE_FUNCPTR(XRenderQueryExtension)
207 #ifdef SONAME_LIBFONTCONFIG
208 #include <fontconfig/fontconfig.h>
209 MAKE_FUNCPTR(FcConfigSubstitute)
210 MAKE_FUNCPTR(FcDefaultSubstitute)
211 MAKE_FUNCPTR(FcFontMatch)
212 MAKE_FUNCPTR(FcInit)
213 MAKE_FUNCPTR(FcPatternCreate)
214 MAKE_FUNCPTR(FcPatternDestroy)
215 MAKE_FUNCPTR(FcPatternAddInteger)
216 MAKE_FUNCPTR(FcPatternAddString)
217 MAKE_FUNCPTR(FcPatternGetBool)
218 MAKE_FUNCPTR(FcPatternGetInteger)
219 MAKE_FUNCPTR(FcPatternGetString)
220 static void *fontconfig_handle;
221 static BOOL fontconfig_installed;
222 #endif
224 #undef MAKE_FUNCPTR
226 static CRITICAL_SECTION xrender_cs;
227 static CRITICAL_SECTION_DEBUG critsect_debug =
229 0, 0, &xrender_cs,
230 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
231 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
233 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
235 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
236 ( ( (ULONG)_x4 << 24 ) | \
237 ( (ULONG)_x3 << 16 ) | \
238 ( (ULONG)_x2 << 8 ) | \
239 (ULONG)_x1 )
241 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
243 #define GASP_GRIDFIT 0x01
244 #define GASP_DOGRAY 0x02
246 #ifdef WORDS_BIGENDIAN
247 #define get_be_word(x) (x)
248 #define NATIVE_BYTE_ORDER MSBFirst
249 #else
250 #define get_be_word(x) RtlUshortByteSwap(x)
251 #define NATIVE_BYTE_ORDER LSBFirst
252 #endif
254 static BOOL has_alpha( enum wxr_format format )
256 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
259 static enum wxr_format get_format_without_alpha( enum wxr_format format )
261 switch (format)
263 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
264 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
265 default: return format;
269 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
271 templ->id = 0;
272 templ->type = PictTypeDirect;
273 templ->depth = fmt->depth;
274 templ->direct.alpha = fmt->alpha;
275 templ->direct.alphaMask = fmt->alphaMask;
276 templ->direct.red = fmt->red;
277 templ->direct.redMask = fmt->redMask;
278 templ->direct.green = fmt->green;
279 templ->direct.greenMask = fmt->greenMask;
280 templ->direct.blue = fmt->blue;
281 templ->direct.blueMask = fmt->blueMask;
282 templ->colormap = 0;
284 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
286 return TRUE;
289 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
291 if(fmt->depth != screen_depth)
292 return FALSE;
293 if( (fmt->redMask << fmt->red) != visual->red_mask)
294 return FALSE;
295 if( (fmt->greenMask << fmt->green) != visual->green_mask)
296 return FALSE;
297 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
298 return FALSE;
300 /* We never select a default ARGB visual */
301 if(fmt->alphaMask)
302 return FALSE;
304 return TRUE;
307 static int load_xrender_formats(void)
309 int count = 0;
310 unsigned int i;
312 for (i = 0; i < WXR_NB_FORMATS; i++)
314 XRenderPictFormat templ;
316 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
318 wine_tsx11_lock();
319 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
320 if (!pict_formats[i])
322 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
323 if (visual->class == DirectColor)
325 XVisualInfo info;
326 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
327 screen_depth, TrueColor, &info ))
329 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
330 if (pict_formats[i]) visual = info.visual;
334 wine_tsx11_unlock();
335 if (pict_formats[i]) default_format = i;
337 else
339 unsigned long mask = 0;
340 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
342 wine_tsx11_lock();
343 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
344 wine_tsx11_unlock();
346 if (pict_formats[i])
348 count++;
349 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
352 return count;
355 /***********************************************************************
356 * X11DRV_XRender_Init
358 * Let's see if our XServer has the extension available
361 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
363 int event_base, i;
364 BOOL ok;
366 if (!client_side_with_render) return NULL;
367 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
369 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
370 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
371 LOAD_FUNCPTR(XRenderAddGlyphs);
372 LOAD_FUNCPTR(XRenderChangePicture);
373 LOAD_FUNCPTR(XRenderComposite);
374 LOAD_FUNCPTR(XRenderCompositeText16);
375 LOAD_FUNCPTR(XRenderCreateGlyphSet);
376 LOAD_FUNCPTR(XRenderCreatePicture);
377 LOAD_FUNCPTR(XRenderFillRectangle);
378 LOAD_FUNCPTR(XRenderFindFormat);
379 LOAD_FUNCPTR(XRenderFindVisualFormat);
380 LOAD_FUNCPTR(XRenderFreeGlyphSet);
381 LOAD_FUNCPTR(XRenderFreePicture);
382 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
383 LOAD_FUNCPTR(XRenderQueryExtension);
384 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
385 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
386 #endif
387 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
388 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
389 #endif
390 #undef LOAD_OPTIONAL_FUNCPTR
391 #undef LOAD_FUNCPTR
393 wine_tsx11_lock();
394 ok = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
395 wine_tsx11_unlock();
396 if (!ok) return NULL;
398 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
399 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
401 ERR_(winediag)("Wine has detected that you probably have a buggy version "
402 "of libXrender. Because of this client side font rendering "
403 "will be disabled. Please upgrade this library.\n");
404 return NULL;
407 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask)
409 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
410 return NULL;
413 #ifdef SONAME_LIBFONTCONFIG
414 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
416 #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;}
417 LOAD_FUNCPTR(FcConfigSubstitute);
418 LOAD_FUNCPTR(FcDefaultSubstitute);
419 LOAD_FUNCPTR(FcFontMatch);
420 LOAD_FUNCPTR(FcInit);
421 LOAD_FUNCPTR(FcPatternCreate);
422 LOAD_FUNCPTR(FcPatternDestroy);
423 LOAD_FUNCPTR(FcPatternAddInteger);
424 LOAD_FUNCPTR(FcPatternAddString);
425 LOAD_FUNCPTR(FcPatternGetBool);
426 LOAD_FUNCPTR(FcPatternGetInteger);
427 LOAD_FUNCPTR(FcPatternGetString);
428 #undef LOAD_FUNCPTR
429 fontconfig_installed = pFcInit();
431 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
433 sym_not_found:
434 #endif
436 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
437 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
439 glyphsetCacheSize = INIT_CACHE_SIZE;
440 lastfree = 0;
441 for(i = 0; i < INIT_CACHE_SIZE; i++) {
442 glyphsetCache[i].next = i + 1;
443 glyphsetCache[i].count = -1;
445 glyphsetCache[i-1].next = -1;
447 if(screen_depth <= 8 || !client_side_antialias_with_render) antialias = 0;
449 return &xrender_funcs;
452 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
453 static void get_xrender_color( struct xrender_physdev *physdev, COLORREF src_color, XRenderColor *dst_color )
455 if (src_color & (1 << 24)) /* PALETTEINDEX */
457 HPALETTE pal = GetCurrentObject( physdev->dev.hdc, OBJ_PAL );
458 PALETTEENTRY pal_ent;
460 if (!GetPaletteEntries( pal, LOWORD(src_color), 1, &pal_ent ))
461 GetPaletteEntries( pal, 0, 1, &pal_ent );
462 dst_color->red = pal_ent.peRed * 257;
463 dst_color->green = pal_ent.peGreen * 257;
464 dst_color->blue = pal_ent.peBlue * 257;
466 else
468 if (src_color >> 16 == 0x10ff) src_color = 0; /* DIBINDEX */
470 dst_color->red = GetRValue( src_color ) * 257;
471 dst_color->green = GetGValue( src_color ) * 257;
472 dst_color->blue = GetBValue( src_color ) * 257;
475 if (physdev->format == WXR_FORMAT_MONO && !dst_color->red && !dst_color->green && !dst_color->blue)
476 dst_color->alpha = 0;
477 else
478 dst_color->alpha = 0xffff;
481 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
483 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
485 switch (info->bmiHeader.biBitCount)
487 case 1:
488 return WXR_FORMAT_MONO;
489 case 4:
490 case 8:
491 break;
492 case 24:
493 if (info->bmiHeader.biCompression != BI_RGB) break;
494 return WXR_FORMAT_R8G8B8;
495 case 16:
496 case 32:
497 if (info->bmiHeader.biCompression == BI_BITFIELDS)
499 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
500 unsigned int i;
502 for (i = 0; i < WXR_NB_FORMATS; i++)
504 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
505 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
506 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
507 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
508 return i;
510 break;
512 if (info->bmiHeader.biCompression != BI_RGB) break;
513 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
515 return WXR_INVALID_FORMAT;
518 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
519 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
521 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
522 XTransform xform = {{
523 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
524 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
525 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
528 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
529 #endif
532 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
534 XRenderPictureAttributes pa;
535 RGNDATA *data;
537 if (!rgn)
539 wine_tsx11_lock();
540 pa.clip_mask = None;
541 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
542 wine_tsx11_unlock();
544 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
546 wine_tsx11_lock();
547 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
548 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
549 (XRectangle *)data->Buffer, data->rdh.nCount );
550 wine_tsx11_unlock();
551 HeapFree( GetProcessHeap(), 0, data );
556 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
558 if (!dev->pict && dev->pict_format)
560 XRenderPictureAttributes pa;
562 wine_tsx11_lock();
563 pa.subwindow_mode = IncludeInferiors;
564 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
565 dev->pict_format, CPSubwindowMode, &pa );
566 wine_tsx11_unlock();
567 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
568 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
569 dev->update_clip = (dev->region != 0);
572 if (clip_rect)
574 HRGN rgn = CreateRectRgnIndirect( clip_rect );
575 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
576 if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
577 update_xrender_clipping( dev, rgn );
578 DeleteObject( rgn );
580 else if (clip_rgn)
582 if (dev->region)
584 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
585 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
586 update_xrender_clipping( dev, rgn );
587 DeleteObject( rgn );
589 else update_xrender_clipping( dev, clip_rgn );
591 else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
593 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
594 return dev->pict;
597 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
599 if (!dev->pict_src && dev->pict_format)
601 XRenderPictureAttributes pa;
603 wine_tsx11_lock();
604 pa.subwindow_mode = IncludeInferiors;
605 pa.repeat = repeat ? RepeatNormal : RepeatNone;
606 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
607 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
608 wine_tsx11_unlock();
610 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
611 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
614 return dev->pict_src;
617 static void free_xrender_picture( struct xrender_physdev *dev )
619 if (dev->pict || dev->pict_src)
621 wine_tsx11_lock();
622 XFlush( gdi_display );
623 if (dev->pict)
625 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
626 pXRenderFreePicture(gdi_display, dev->pict);
627 dev->pict = 0;
629 if(dev->pict_src)
631 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
632 pXRenderFreePicture(gdi_display, dev->pict_src);
633 dev->pict_src = 0;
635 wine_tsx11_unlock();
639 /* return a mask picture used to force alpha to 0 */
640 static Picture get_no_alpha_mask(void)
642 static Pixmap pixmap;
643 static Picture pict;
645 wine_tsx11_lock();
646 if (!pict)
648 XRenderPictureAttributes pa;
649 XRenderColor col;
651 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
652 pa.repeat = RepeatNormal;
653 pa.component_alpha = True;
654 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
655 CPRepeat|CPComponentAlpha, &pa );
656 col.red = col.green = col.blue = 0xffff;
657 col.alpha = 0;
658 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
660 wine_tsx11_unlock();
661 return pict;
664 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
666 if(p1->hash != p2->hash) return TRUE;
667 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
668 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
669 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
670 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
673 #if 0
674 static void walk_cache(void)
676 int i;
678 EnterCriticalSection(&xrender_cs);
679 for(i=mru; i >= 0; i = glyphsetCache[i].next)
680 TRACE("item %d\n", i);
681 LeaveCriticalSection(&xrender_cs);
683 #endif
685 static int LookupEntry(LFANDSIZE *plfsz)
687 int i, prev_i = -1;
689 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
690 TRACE("%d\n", i);
691 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
693 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
694 glyphsetCache[i].count++;
695 if(prev_i >= 0) {
696 glyphsetCache[prev_i].next = glyphsetCache[i].next;
697 glyphsetCache[i].next = mru;
698 mru = i;
700 TRACE("found font in cache %d\n", i);
701 return i;
703 prev_i = i;
705 TRACE("font not in cache\n");
706 return -1;
709 static void FreeEntry(int entry)
711 int format;
713 for(format = 0; format < AA_MAXVALUE; format++) {
714 gsCacheEntryFormat * formatEntry;
716 if( !glyphsetCache[entry].format[format] )
717 continue;
719 formatEntry = glyphsetCache[entry].format[format];
721 if(formatEntry->glyphset) {
722 wine_tsx11_lock();
723 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
724 wine_tsx11_unlock();
725 formatEntry->glyphset = 0;
727 if(formatEntry->nrealized) {
728 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
729 formatEntry->realized = NULL;
730 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
731 formatEntry->gis = NULL;
732 formatEntry->nrealized = 0;
735 HeapFree(GetProcessHeap(), 0, formatEntry);
736 glyphsetCache[entry].format[format] = NULL;
740 static int AllocEntry(void)
742 int best = -1, prev_best = -1, i, prev_i = -1;
744 if(lastfree >= 0) {
745 assert(glyphsetCache[lastfree].count == -1);
746 glyphsetCache[lastfree].count = 1;
747 best = lastfree;
748 lastfree = glyphsetCache[lastfree].next;
749 assert(best != mru);
750 glyphsetCache[best].next = mru;
751 mru = best;
753 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
754 return mru;
757 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
758 if(glyphsetCache[i].count == 0) {
759 best = i;
760 prev_best = prev_i;
762 prev_i = i;
765 if(best >= 0) {
766 TRACE("freeing unused glyphset at cache %d\n", best);
767 FreeEntry(best);
768 glyphsetCache[best].count = 1;
769 if(prev_best >= 0) {
770 glyphsetCache[prev_best].next = glyphsetCache[best].next;
771 glyphsetCache[best].next = mru;
772 mru = best;
773 } else {
774 assert(mru == best);
776 return mru;
779 TRACE("Growing cache\n");
781 if (glyphsetCache)
782 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
783 glyphsetCache,
784 (glyphsetCacheSize + INIT_CACHE_SIZE)
785 * sizeof(*glyphsetCache));
786 else
787 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
788 (glyphsetCacheSize + INIT_CACHE_SIZE)
789 * sizeof(*glyphsetCache));
791 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
792 i++) {
793 glyphsetCache[i].next = i + 1;
794 glyphsetCache[i].count = -1;
796 glyphsetCache[i-1].next = -1;
797 glyphsetCacheSize += INIT_CACHE_SIZE;
799 lastfree = glyphsetCache[best].next;
800 glyphsetCache[best].count = 1;
801 glyphsetCache[best].next = mru;
802 mru = best;
803 TRACE("new free cache slot at %d\n", mru);
804 return mru;
807 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
809 DWORD size;
810 WORD *gasp, *buffer;
811 WORD num_recs;
812 DWORD ppem;
813 TEXTMETRICW tm;
815 *flags = 0;
817 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
818 if(size == GDI_ERROR)
819 return FALSE;
821 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
822 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
824 GetTextMetricsW(hdc, &tm);
825 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
827 gasp++;
828 num_recs = get_be_word(*gasp);
829 gasp++;
830 while(num_recs--)
832 *flags = get_be_word(*(gasp + 1));
833 if(ppem <= get_be_word(*gasp))
834 break;
835 gasp += 2;
837 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
839 HeapFree(GetProcessHeap(), 0, buffer);
840 return TRUE;
843 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
845 AA_Type ret;
846 WORD flags;
847 UINT font_smoothing_type, font_smoothing_orientation;
849 if (subpixel &&
850 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
851 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
853 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
854 &font_smoothing_orientation, 0) &&
855 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
857 ret = AA_BGR;
859 else
860 ret = AA_RGB;
861 /*FIXME
862 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
863 But, Wine's subpixel rendering can support the portrait mode.
866 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
867 ret = AA_Grey;
868 else
869 ret = AA_None;
871 return ret;
874 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
876 int ret;
877 int format;
878 gsCacheEntry *entry;
879 static int hinter = -1;
880 static int subpixel = -1;
881 BOOL font_smoothing;
883 if((ret = LookupEntry(plfsz)) != -1) return ret;
885 ret = AllocEntry();
886 entry = glyphsetCache + ret;
887 entry->lfsz = *plfsz;
888 for( format = 0; format < AA_MAXVALUE; format++ ) {
889 assert( !entry->format[format] );
892 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
894 if(hinter == -1 || subpixel == -1)
896 RASTERIZER_STATUS status;
897 GetRasterizerCaps(&status, sizeof(status));
898 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
899 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
902 switch (plfsz->lf.lfQuality)
904 case ANTIALIASED_QUALITY:
905 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
906 return ret; /* ignore further configuration */
907 case CLEARTYPE_QUALITY:
908 case CLEARTYPE_NATURAL_QUALITY:
909 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
910 break;
911 case DEFAULT_QUALITY:
912 case DRAFT_QUALITY:
913 case PROOF_QUALITY:
914 default:
915 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
916 font_smoothing)
918 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
920 else
921 entry->aa_default = AA_None;
922 break;
925 font_smoothing = TRUE; /* default to enabled */
926 #ifdef SONAME_LIBFONTCONFIG
927 if (fontconfig_installed)
929 FcPattern *match, *pattern;
930 FcResult result;
931 char family[LF_FACESIZE * 4];
933 #if defined(__i386__) && defined(__GNUC__)
934 /* fontconfig generates floating point exceptions, mask them */
935 WORD cw, default_cw = 0x37f;
936 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
937 #endif
939 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
940 pattern = pFcPatternCreate();
941 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
942 if (plfsz->lf.lfWeight != FW_DONTCARE)
944 int weight;
945 switch (plfsz->lf.lfWeight)
947 case FW_THIN: weight = FC_WEIGHT_THIN; break;
948 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
949 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
950 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
951 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
952 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
953 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
954 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
955 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
956 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
958 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
960 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
961 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
962 pFcDefaultSubstitute( pattern );
963 if ((match = pFcFontMatch( NULL, pattern, &result )))
965 int rgba;
966 FcBool antialias;
968 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
969 antialias = TRUE;
970 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
972 FcChar8 *file;
973 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
975 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
976 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
978 switch (rgba)
980 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
981 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
982 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
983 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
984 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
987 if (!antialias) font_smoothing = FALSE;
988 pFcPatternDestroy( match );
990 pFcPatternDestroy( pattern );
992 #if defined(__i386__) && defined(__GNUC__)
993 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
994 #endif
996 #endif /* SONAME_LIBFONTCONFIG */
998 /* now check Xft resources */
1000 char *value;
1001 BOOL antialias = TRUE;
1003 wine_tsx11_lock();
1004 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1006 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1007 value[0] == '0' || !strcasecmp( value, "off" ))
1008 antialias = FALSE;
1010 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1012 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1013 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1014 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1015 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1016 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1017 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1019 wine_tsx11_unlock();
1020 if (!antialias) font_smoothing = FALSE;
1023 if (!font_smoothing) entry->aa_default = AA_None;
1025 else
1026 entry->aa_default = AA_None;
1028 return ret;
1031 static void dec_ref_cache(int index)
1033 assert(index >= 0);
1034 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1035 assert(glyphsetCache[index].count > 0);
1036 glyphsetCache[index].count--;
1039 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1041 DWORD hash = 0, *ptr, two_chars;
1042 WORD *pwc;
1043 int i;
1045 hash ^= plfsz->devsize.cx;
1046 hash ^= plfsz->devsize.cy;
1047 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1048 hash ^= *ptr;
1049 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1050 hash ^= *ptr;
1051 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1052 two_chars = *ptr;
1053 pwc = (WCHAR *)&two_chars;
1054 if(!*pwc) break;
1055 *pwc = toupperW(*pwc);
1056 pwc++;
1057 *pwc = toupperW(*pwc);
1058 hash ^= two_chars;
1059 if(!*pwc) break;
1061 plfsz->hash = hash;
1062 return;
1065 /***********************************************************************
1066 * X11DRV_XRender_Finalize
1068 void X11DRV_XRender_Finalize(void)
1070 int i;
1072 EnterCriticalSection(&xrender_cs);
1073 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1074 FreeEntry(i);
1075 LeaveCriticalSection(&xrender_cs);
1076 DeleteCriticalSection(&xrender_cs);
1079 /**********************************************************************
1080 * xrenderdrv_SelectFont
1082 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1084 LFANDSIZE lfsz;
1085 struct xrender_physdev *physdev = get_xrender_dev( dev );
1086 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1087 HFONT ret = next->funcs->pSelectFont( next, hfont );
1089 if (!ret) return 0;
1091 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1093 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1094 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1095 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1096 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1097 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1098 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1100 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1101 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1102 lfsz.xform.eM21, lfsz.xform.eM22);
1104 if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE && lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
1105 lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
1107 /* Not used fields, would break hashing */
1108 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1110 lfsz_calc_hash(&lfsz);
1112 EnterCriticalSection(&xrender_cs);
1113 if (physdev->cache_index != -1)
1114 dec_ref_cache( physdev->cache_index );
1115 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1116 LeaveCriticalSection(&xrender_cs);
1117 return ret;
1120 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1122 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1123 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1125 if (!physdev) return FALSE;
1126 physdev->x11dev = x11dev;
1127 physdev->cache_index = -1;
1128 physdev->format = format;
1129 physdev->pict_format = pict_formats[format];
1130 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1131 return TRUE;
1134 /* store the color mask data in the bitmap info structure */
1135 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1137 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1139 info->bmiHeader.biPlanes = 1;
1140 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1141 info->bmiHeader.biCompression = BI_RGB;
1142 info->bmiHeader.biClrUsed = 0;
1144 switch (info->bmiHeader.biBitCount)
1146 case 16:
1147 colors[0] = format->direct.redMask << format->direct.red;
1148 colors[1] = format->direct.greenMask << format->direct.green;
1149 colors[2] = format->direct.blueMask << format->direct.blue;
1150 info->bmiHeader.biCompression = BI_BITFIELDS;
1151 break;
1152 case 32:
1153 colors[0] = format->direct.redMask << format->direct.red;
1154 colors[1] = format->direct.greenMask << format->direct.green;
1155 colors[2] = format->direct.blueMask << format->direct.blue;
1156 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1157 info->bmiHeader.biCompression = BI_BITFIELDS;
1158 break;
1163 /**********************************************************************
1164 * xrenderdrv_CreateDC
1166 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1167 LPCWSTR output, const DEVMODEW* initData )
1169 return create_xrender_dc( pdev, default_format );
1172 /**********************************************************************
1173 * xrenderdrv_CreateCompatibleDC
1175 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1177 if (orig) /* chain to x11drv first */
1179 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1180 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1182 /* otherwise we have been called by x11drv */
1184 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1187 /**********************************************************************
1188 * xrenderdrv_DeleteDC
1190 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1192 struct xrender_physdev *physdev = get_xrender_dev( dev );
1194 free_xrender_picture( physdev );
1196 EnterCriticalSection( &xrender_cs );
1197 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1198 LeaveCriticalSection( &xrender_cs );
1200 HeapFree( GetProcessHeap(), 0, physdev );
1201 return TRUE;
1204 /**********************************************************************
1205 * xrenderdrv_ExtEscape
1207 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1208 INT out_count, LPVOID out_data )
1210 struct xrender_physdev *physdev = get_xrender_dev( dev );
1212 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1214 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1216 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1218 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1219 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1220 return ret;
1223 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1226 /***********************************************************************
1227 * xrenderdrv_SetDeviceClipping
1229 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1231 struct xrender_physdev *physdev = get_xrender_dev( dev );
1233 physdev->region = rgn;
1234 physdev->update_clip = TRUE;
1236 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1237 dev->funcs->pSetDeviceClipping( dev, rgn );
1241 /************************************************************************
1242 * UploadGlyph
1244 * Helper to ExtTextOut. Must be called inside xrender_cs
1246 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1248 unsigned int buflen;
1249 char *buf;
1250 Glyph gid;
1251 GLYPHMETRICS gm;
1252 XGlyphInfo gi;
1253 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1254 gsCacheEntryFormat *formatEntry;
1255 UINT ggo_format = GGO_GLYPH_INDEX;
1256 enum wxr_format wxr_format;
1257 static const char zero[4];
1258 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1260 switch(format) {
1261 case AA_Grey:
1262 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1263 break;
1264 case AA_RGB:
1265 ggo_format |= WINE_GGO_HRGB_BITMAP;
1266 break;
1267 case AA_BGR:
1268 ggo_format |= WINE_GGO_HBGR_BITMAP;
1269 break;
1270 case AA_VRGB:
1271 ggo_format |= WINE_GGO_VRGB_BITMAP;
1272 break;
1273 case AA_VBGR:
1274 ggo_format |= WINE_GGO_VBGR_BITMAP;
1275 break;
1277 default:
1278 ERR("aa = %d - not implemented\n", format);
1279 case AA_None:
1280 ggo_format |= GGO_BITMAP;
1281 break;
1284 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1285 if(buflen == GDI_ERROR) {
1286 if(format != AA_None) {
1287 format = AA_None;
1288 entry->aa_default = AA_None;
1289 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1290 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1292 if(buflen == GDI_ERROR) {
1293 WARN("GetGlyphOutlineW failed using default glyph\n");
1294 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1295 if(buflen == GDI_ERROR) {
1296 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1297 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1298 if(buflen == GDI_ERROR) {
1299 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1300 return;
1304 TRACE("Turning off antialiasing for this monochrome font\n");
1307 /* If there is nothing for the current type, we create the entry. */
1308 if( !entry->format[format] ) {
1309 entry->format[format] = HeapAlloc(GetProcessHeap(),
1310 HEAP_ZERO_MEMORY,
1311 sizeof(gsCacheEntryFormat));
1313 formatEntry = entry->format[format];
1315 if(formatEntry->nrealized <= glyph) {
1316 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1318 if (formatEntry->realized)
1319 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1320 HEAP_ZERO_MEMORY,
1321 formatEntry->realized,
1322 formatEntry->nrealized * sizeof(BOOL));
1323 else
1324 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1325 HEAP_ZERO_MEMORY,
1326 formatEntry->nrealized * sizeof(BOOL));
1328 if (formatEntry->gis)
1329 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1330 HEAP_ZERO_MEMORY,
1331 formatEntry->gis,
1332 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1333 else
1334 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1335 HEAP_ZERO_MEMORY,
1336 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1340 if(formatEntry->glyphset == 0) {
1341 switch(format) {
1342 case AA_Grey:
1343 wxr_format = WXR_FORMAT_GRAY;
1344 break;
1346 case AA_RGB:
1347 case AA_BGR:
1348 case AA_VRGB:
1349 case AA_VBGR:
1350 wxr_format = WXR_FORMAT_A8R8G8B8;
1351 break;
1353 default:
1354 ERR("aa = %d - not implemented\n", format);
1355 case AA_None:
1356 wxr_format = WXR_FORMAT_MONO;
1357 break;
1360 wine_tsx11_lock();
1361 formatEntry->font_format = pict_formats[wxr_format];
1362 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1363 wine_tsx11_unlock();
1367 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1368 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1369 formatEntry->realized[glyph] = TRUE;
1371 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1372 buflen,
1373 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1374 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1376 gi.width = gm.gmBlackBoxX;
1377 gi.height = gm.gmBlackBoxY;
1378 gi.x = -gm.gmptGlyphOrigin.x;
1379 gi.y = gm.gmptGlyphOrigin.y;
1380 gi.xOff = gm.gmCellIncX;
1381 gi.yOff = gm.gmCellIncY;
1383 if(TRACE_ON(xrender)) {
1384 int pitch, i, j;
1385 char output[300];
1386 unsigned char *line;
1388 if(format == AA_None) {
1389 pitch = ((gi.width + 31) / 32) * 4;
1390 for(i = 0; i < gi.height; i++) {
1391 line = (unsigned char*) buf + i * pitch;
1392 output[0] = '\0';
1393 for(j = 0; j < pitch * 8; j++) {
1394 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1396 TRACE("%s\n", output);
1398 } else {
1399 static const char blks[] = " .:;!o*#";
1400 char str[2];
1402 str[1] = '\0';
1403 pitch = ((gi.width + 3) / 4) * 4;
1404 for(i = 0; i < gi.height; i++) {
1405 line = (unsigned char*) buf + i * pitch;
1406 output[0] = '\0';
1407 for(j = 0; j < pitch; j++) {
1408 str[0] = blks[line[j] >> 5];
1409 strcat(output, str);
1411 TRACE("%s\n", output);
1417 if(formatEntry->glyphset) {
1418 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1419 unsigned char *byte = (unsigned char*) buf, c;
1420 int i = buflen;
1422 while(i--) {
1423 c = *byte;
1425 /* magic to flip bit order */
1426 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1427 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1428 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1430 *byte++ = c;
1433 else if ( format != AA_Grey &&
1434 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1436 unsigned int i, *data = (unsigned int *)buf;
1437 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1439 gid = glyph;
1442 XRenderCompositeText seems to ignore 0x0 glyphs when
1443 AA_None, which means we lose the advance width of glyphs
1444 like the space. We'll pretend that such glyphs are 1x1
1445 bitmaps.
1448 if(buflen == 0)
1449 gi.width = gi.height = 1;
1451 wine_tsx11_lock();
1452 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1453 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1454 wine_tsx11_unlock();
1455 HeapFree(GetProcessHeap(), 0, buf);
1458 formatEntry->gis[glyph] = gi;
1461 /*************************************************************
1462 * get_tile_pict
1464 * Returns an appropriate Picture for tiling the text colour.
1465 * Call and use result within the xrender_cs
1467 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1469 static struct
1471 Pixmap xpm;
1472 Picture pict;
1473 XRenderColor current_color;
1474 } tiles[WXR_NB_FORMATS], *tile;
1476 tile = &tiles[wxr_format];
1478 if(!tile->xpm)
1480 XRenderPictureAttributes pa;
1481 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1483 wine_tsx11_lock();
1484 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1486 pa.repeat = RepeatNormal;
1487 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1488 wine_tsx11_unlock();
1490 /* init current_color to something different from text_pixel */
1491 tile->current_color = *color;
1492 tile->current_color.red ^= 0xffff;
1494 if (wxr_format == WXR_FORMAT_MONO)
1496 /* for a 1bpp bitmap we always need a 1 in the tile */
1497 XRenderColor col;
1498 col.red = col.green = col.blue = 0;
1499 col.alpha = 0xffff;
1500 wine_tsx11_lock();
1501 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1502 wine_tsx11_unlock();
1506 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1508 wine_tsx11_lock();
1509 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1510 wine_tsx11_unlock();
1511 tile->current_color = *color;
1513 return tile->pict;
1516 /*************************************************************
1517 * get_mask_pict
1519 * Returns an appropriate Picture for masking with the specified alpha.
1520 * Call and use result within the xrender_cs
1522 static Picture get_mask_pict( int alpha )
1524 static Pixmap pixmap;
1525 static Picture pict;
1526 static int current_alpha;
1528 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1530 if (!pixmap)
1532 XRenderPictureAttributes pa;
1534 wine_tsx11_lock();
1535 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1536 pa.repeat = RepeatNormal;
1537 pict = pXRenderCreatePicture( gdi_display, pixmap,
1538 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1539 wine_tsx11_unlock();
1540 current_alpha = -1;
1543 if (alpha != current_alpha)
1545 XRenderColor col;
1546 col.red = col.green = col.blue = 0;
1547 col.alpha = current_alpha = alpha;
1548 wine_tsx11_lock();
1549 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1550 wine_tsx11_unlock();
1552 return pict;
1555 /***********************************************************************
1556 * xrenderdrv_ExtTextOut
1558 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1559 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1561 struct xrender_physdev *physdev = get_xrender_dev( dev );
1562 gsCacheEntry *entry;
1563 gsCacheEntryFormat *formatEntry;
1564 AA_Type aa_type = AA_None;
1565 unsigned int idx;
1566 Picture pict, tile_pict = 0;
1567 XGlyphElt16 *elts;
1568 POINT offset, desired, current;
1569 int render_op = PictOpOver;
1570 XRenderColor col;
1571 RECT rect, bounds;
1573 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1574 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1576 if(flags & ETO_OPAQUE)
1578 XRenderColor bg;
1580 if (physdev->format == WXR_FORMAT_MONO)
1581 /* use the inverse of the text color */
1582 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1583 else
1584 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1586 wine_tsx11_lock();
1587 set_xrender_transformation( pict, 1, 1, 0, 0 );
1588 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1589 physdev->x11dev->dc_rect.left + lprect->left,
1590 physdev->x11dev->dc_rect.top + lprect->top,
1591 lprect->right - lprect->left,
1592 lprect->bottom - lprect->top );
1593 wine_tsx11_unlock();
1594 add_device_bounds( physdev->x11dev, lprect );
1597 if(count == 0) return TRUE;
1599 EnterCriticalSection(&xrender_cs);
1601 entry = glyphsetCache + physdev->cache_index;
1602 aa_type = entry->aa_default;
1603 formatEntry = entry->format[aa_type];
1605 for(idx = 0; idx < count; idx++) {
1606 if( !formatEntry ) {
1607 UploadGlyph(physdev, wstr[idx], aa_type);
1608 /* re-evaluate antialias since aa_default may have changed */
1609 aa_type = entry->aa_default;
1610 formatEntry = entry->format[aa_type];
1611 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1612 UploadGlyph(physdev, wstr[idx], aa_type);
1615 if (!formatEntry)
1617 WARN("could not upload requested glyphs\n");
1618 LeaveCriticalSection(&xrender_cs);
1619 return FALSE;
1622 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1623 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1625 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1627 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1628 So we pass zeros to the function and move to our starting position using the first
1629 element of the elts array. */
1631 desired.x = physdev->x11dev->dc_rect.left + x;
1632 desired.y = physdev->x11dev->dc_rect.top + y;
1633 offset.x = offset.y = 0;
1634 current.x = current.y = 0;
1636 tile_pict = get_tile_pict(physdev->format, &col);
1638 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1640 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1641 render_op = PictOpOutReverse; /* This gives us 'black' text */
1643 reset_bounds( &bounds );
1644 for(idx = 0; idx < count; idx++)
1646 elts[idx].glyphset = formatEntry->glyphset;
1647 elts[idx].chars = wstr + idx;
1648 elts[idx].nchars = 1;
1649 elts[idx].xOff = desired.x - current.x;
1650 elts[idx].yOff = desired.y - current.y;
1652 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1653 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1655 rect.left = desired.x - physdev->x11dev->dc_rect.left - formatEntry->gis[wstr[idx]].x;
1656 rect.top = desired.y - physdev->x11dev->dc_rect.top - formatEntry->gis[wstr[idx]].y;
1657 rect.right = rect.left + formatEntry->gis[wstr[idx]].width;
1658 rect.bottom = rect.top + formatEntry->gis[wstr[idx]].height;
1659 add_bounds_rect( &bounds, &rect );
1661 if(!lpDx)
1663 desired.x += formatEntry->gis[wstr[idx]].xOff;
1664 desired.y += formatEntry->gis[wstr[idx]].yOff;
1666 else
1668 if(flags & ETO_PDY)
1670 offset.x += lpDx[idx * 2];
1671 offset.y += lpDx[idx * 2 + 1];
1673 else
1674 offset.x += lpDx[idx];
1675 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1676 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1680 wine_tsx11_lock();
1681 /* Make sure we don't have any transforms set from a previous call */
1682 set_xrender_transformation(pict, 1, 1, 0, 0);
1683 pXRenderCompositeText16(gdi_display, render_op,
1684 tile_pict,
1685 pict,
1686 formatEntry->font_format,
1687 0, 0, 0, 0, elts, count);
1688 wine_tsx11_unlock();
1689 HeapFree(GetProcessHeap(), 0, elts);
1691 LeaveCriticalSection(&xrender_cs);
1692 add_device_bounds( physdev->x11dev, &bounds );
1693 return TRUE;
1696 /* multiply the alpha channel of a picture */
1697 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1698 int x, int y, int width, int height )
1700 XRenderPictureAttributes pa;
1701 Pixmap src_pixmap, mask_pixmap;
1702 Picture src_pict, mask_pict;
1703 XRenderColor color;
1705 wine_tsx11_lock();
1706 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1707 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1708 pa.repeat = RepeatNormal;
1709 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1710 pa.component_alpha = True;
1711 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1712 color.red = color.green = color.blue = color.alpha = 0xffff;
1713 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1714 color.alpha = alpha;
1715 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1716 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1717 0, 0, 0, 0, x, y, width, height );
1718 pXRenderFreePicture( gdi_display, src_pict );
1719 pXRenderFreePicture( gdi_display, mask_pict );
1720 XFreePixmap( gdi_display, src_pixmap );
1721 XFreePixmap( gdi_display, mask_pixmap );
1722 wine_tsx11_unlock();
1725 /* Helper function for (stretched) blitting using xrender */
1726 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1727 int x_src, int y_src, int width_src, int height_src,
1728 int x_dst, int y_dst, int width_dst, int height_dst,
1729 double xscale, double yscale )
1731 int x_offset, y_offset;
1733 if (width_src < 0)
1735 x_src += width_src + 1;
1736 width_src = -width_src;
1738 if (height_src < 0)
1740 y_src += height_src + 1;
1741 height_src = -height_src;
1743 if (width_dst < 0)
1745 x_dst += width_dst + 1;
1746 width_dst = -width_dst;
1748 if (height_dst < 0)
1750 y_dst += height_dst + 1;
1751 height_dst = -height_dst;
1754 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1755 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1756 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1757 wine_tsx11_lock();
1758 if(xscale != 1.0 || yscale != 1.0)
1760 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1761 * in the wrong quadrant of the x-y plane.
1763 x_offset = (xscale < 0) ? -width_dst : 0;
1764 y_offset = (yscale < 0) ? -height_dst : 0;
1765 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1767 else
1769 x_offset = x_src;
1770 y_offset = y_src;
1771 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1773 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1774 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1775 wine_tsx11_unlock();
1778 /* Helper function for (stretched) mono->color blitting using xrender */
1779 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1780 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1781 int x_src, int y_src, int width_src, int height_src,
1782 int x_dst, int y_dst, int width_dst, int height_dst,
1783 double xscale, double yscale )
1785 Picture tile_pict;
1786 int x_offset, y_offset;
1787 XRenderColor color;
1789 if (width_src < 0)
1791 x_src += width_src + 1;
1792 width_src = -width_src;
1794 if (height_src < 0)
1796 y_src += height_src + 1;
1797 height_src = -height_src;
1799 if (width_dst < 0)
1801 x_dst += width_dst + 1;
1802 width_dst = -width_dst;
1804 if (height_dst < 0)
1806 y_dst += height_dst + 1;
1807 height_dst = -height_dst;
1810 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1811 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1812 * the tile data.
1814 EnterCriticalSection( &xrender_cs );
1815 color = *bg;
1816 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1817 tile_pict = get_tile_pict( dst_format, &color );
1819 wine_tsx11_lock();
1820 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1822 if (xscale != 1.0 || yscale != 1.0)
1824 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1825 * in the wrong quadrant of the x-y plane.
1827 x_offset = (xscale < 0) ? -width_dst : 0;
1828 y_offset = (yscale < 0) ? -height_dst : 0;
1829 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1831 else
1833 x_offset = x_src;
1834 y_offset = y_src;
1835 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1837 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1838 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1839 wine_tsx11_unlock();
1840 LeaveCriticalSection( &xrender_cs );
1842 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1843 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1844 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1845 x_dst, y_dst, width_dst, height_dst );
1848 /* create a pixmap and render picture for an image */
1849 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1850 struct bitblt_coords *src, enum wxr_format format,
1851 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1853 DWORD ret;
1854 int width = src->visrect.right - src->visrect.left;
1855 int height = src->visrect.bottom - src->visrect.top;
1856 int depth = pict_formats[format]->depth;
1857 struct gdi_image_bits dst_bits;
1858 XRenderPictureAttributes pa;
1859 GC gc;
1860 XImage *image;
1862 wine_tsx11_lock();
1863 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1864 info->bmiHeader.biWidth, height, 32, 0 );
1865 wine_tsx11_unlock();
1866 if (!image) return ERROR_OUTOFMEMORY;
1868 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1869 if (ret) return ret;
1871 image->data = dst_bits.ptr;
1873 *use_repeat = (width == 1 && height == 1);
1874 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1876 wine_tsx11_lock();
1877 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1878 gc = XCreateGC( gdi_display, *pixmap, 0, NULL );
1879 XPutImage( gdi_display, *pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1880 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1881 XFreeGC( gdi_display, gc );
1882 wine_tsx11_unlock();
1884 /* make coordinates relative to the pixmap */
1885 src->x -= src->visrect.left;
1886 src->y -= src->visrect.top;
1887 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1889 image->data = NULL;
1890 wine_tsx11_lock();
1891 XDestroyImage( image );
1892 wine_tsx11_unlock();
1893 if (dst_bits.free) dst_bits.free( &dst_bits );
1894 return ret;
1897 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1898 Drawable drawable, const struct bitblt_coords *src,
1899 const struct bitblt_coords *dst )
1901 int x_dst, y_dst;
1902 Picture src_pict = 0, dst_pict, mask_pict = 0;
1903 double xscale = src->width / (double)dst->width;
1904 double yscale = src->height / (double)dst->height;
1906 if (drawable) /* using an intermediate pixmap */
1908 x_dst = dst->x;
1909 y_dst = dst->y;
1910 wine_tsx11_lock();
1911 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, 0, NULL );
1912 wine_tsx11_unlock();
1914 else
1916 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
1917 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
1918 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1921 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1923 /* mono -> color */
1924 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1926 XRenderColor fg, bg;
1928 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
1929 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
1930 fg.alpha = bg.alpha = 0;
1932 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
1933 physdev_src->x11dev->dc_rect.left + src->x,
1934 physdev_src->x11dev->dc_rect.top + src->y,
1935 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1937 else /* color -> color (can be at different depths) or mono -> mono */
1939 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
1940 mask_pict = get_no_alpha_mask();
1942 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
1943 physdev_src->x11dev->dc_rect.left + src->x,
1944 physdev_src->x11dev->dc_rect.top + src->y,
1945 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1948 if (drawable)
1950 wine_tsx11_lock();
1951 pXRenderFreePicture( gdi_display, dst_pict );
1952 wine_tsx11_unlock();
1957 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
1958 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
1959 Drawable drawable, struct bitblt_coords *src,
1960 struct bitblt_coords *dst, BOOL use_repeat )
1962 int x_dst, y_dst;
1963 Picture dst_pict;
1964 double xscale, yscale;
1966 if (drawable) /* using an intermediate pixmap */
1968 RGNDATA *clip_data = NULL;
1970 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1971 x_dst = dst->x;
1972 y_dst = dst->y;
1973 wine_tsx11_lock();
1974 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL );
1975 if (clip_data)
1976 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
1977 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
1978 wine_tsx11_unlock();
1979 HeapFree( GetProcessHeap(), 0, clip_data );
1981 else
1983 x_dst = physdev->x11dev->dc_rect.left + dst->x;
1984 y_dst = physdev->x11dev->dc_rect.top + dst->y;
1985 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
1988 if (!use_repeat)
1990 xscale = src->width / (double)dst->width;
1991 yscale = src->height / (double)dst->height;
1993 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1995 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
1996 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1998 if (drawable)
2000 wine_tsx11_lock();
2001 pXRenderFreePicture( gdi_display, dst_pict );
2002 wine_tsx11_unlock();
2007 /***********************************************************************
2008 * xrenderdrv_StretchBlt
2010 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2011 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2013 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2014 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2015 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2017 if (src_dev->funcs != dst_dev->funcs)
2019 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2020 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2023 /* XRender is of no use for color -> mono */
2024 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2025 goto x11drv_fallback;
2027 /* if not stretching, we only need to handle format conversion */
2028 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2030 if (rop != SRCCOPY)
2032 GC tmpGC;
2033 Pixmap tmp_pixmap;
2034 struct bitblt_coords tmp;
2036 /* make coordinates relative to tmp pixmap */
2037 tmp = *dst;
2038 tmp.x -= tmp.visrect.left;
2039 tmp.y -= tmp.visrect.top;
2040 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2042 wine_tsx11_lock();
2043 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2044 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2045 XSetGraphicsExposures( gdi_display, tmpGC, False );
2046 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2047 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
2048 wine_tsx11_unlock();
2050 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2051 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2053 wine_tsx11_lock();
2054 XFreePixmap( gdi_display, tmp_pixmap );
2055 XFreeGC( gdi_display, tmpGC );
2056 wine_tsx11_unlock();
2058 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2060 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2061 return TRUE;
2063 x11drv_fallback:
2064 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2068 /***********************************************************************
2069 * xrenderdrv_PutImage
2071 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
2072 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2073 struct bitblt_coords *dst, DWORD rop )
2075 struct xrender_physdev *physdev = get_xrender_dev( dev );
2076 DWORD ret;
2077 Pixmap tmp_pixmap;
2078 GC gc;
2079 enum wxr_format src_format, dst_format;
2080 XRenderPictFormat *pict_format;
2081 Pixmap src_pixmap;
2082 Picture src_pict, mask_pict = 0;
2083 BOOL use_repeat;
2085 dst_format = physdev->format;
2086 src_format = get_xrender_format_from_bitmapinfo( info );
2087 if (!(pict_format = pict_formats[src_format])) goto update_format;
2089 /* make sure we can create an image with the same bpp */
2090 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2091 goto update_format;
2093 /* mono <-> color conversions not supported */
2094 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2095 goto x11drv_fallback;
2097 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2099 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2101 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2102 if (!ret)
2104 struct bitblt_coords tmp;
2106 if (rop != SRCCOPY)
2108 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2110 /* make coordinates relative to tmp pixmap */
2111 tmp = *dst;
2112 tmp.x -= tmp.visrect.left;
2113 tmp.y -= tmp.visrect.top;
2114 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2116 wine_tsx11_lock();
2117 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2118 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2119 XSetGraphicsExposures( gdi_display, gc, False );
2120 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2121 tmp.visrect.right - tmp.visrect.left,
2122 tmp.visrect.bottom - tmp.visrect.top,
2123 physdev->pict_format->depth );
2124 wine_tsx11_unlock();
2126 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2127 NULL, tmp_pixmap, src, &tmp, use_repeat );
2128 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2130 wine_tsx11_lock();
2131 XFreePixmap( gdi_display, tmp_pixmap );
2132 XFreeGC( gdi_display, gc );
2133 wine_tsx11_unlock();
2135 if (restore_region) restore_clipping_region( physdev->x11dev );
2137 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2138 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2140 add_device_bounds( physdev->x11dev, &dst->visrect );
2142 wine_tsx11_lock();
2143 pXRenderFreePicture( gdi_display, src_pict );
2144 XFreePixmap( gdi_display, src_pixmap );
2145 wine_tsx11_unlock();
2147 return ret;
2149 update_format:
2150 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2151 set_color_info( pict_formats[dst_format], info );
2152 return ERROR_BAD_FORMAT;
2154 x11drv_fallback:
2155 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2156 return dev->funcs->pPutImage( dev, clip, info, bits, src, dst, rop );
2160 /***********************************************************************
2161 * xrenderdrv_BlendImage
2163 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2164 struct bitblt_coords *src, struct bitblt_coords *dst,
2165 BLENDFUNCTION func )
2167 struct xrender_physdev *physdev = get_xrender_dev( dev );
2168 DWORD ret;
2169 enum wxr_format format;
2170 XRenderPictFormat *pict_format;
2171 Picture dst_pict, src_pict, mask_pict;
2172 Pixmap src_pixmap;
2173 BOOL use_repeat;
2175 format = get_xrender_format_from_bitmapinfo( info );
2176 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2177 format = get_format_without_alpha( format );
2178 else if (format != WXR_FORMAT_A8R8G8B8)
2179 return ERROR_INVALID_PARAMETER;
2181 if (!(pict_format = pict_formats[format])) goto update_format;
2183 /* make sure we can create an image with the same bpp */
2184 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2185 goto update_format;
2187 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2188 goto update_format;
2190 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2192 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2193 if (!ret)
2195 double xscale, yscale;
2197 if (!use_repeat)
2199 xscale = src->width / (double)dst->width;
2200 yscale = src->height / (double)dst->height;
2202 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2204 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2206 EnterCriticalSection( &xrender_cs );
2207 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2209 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2210 src->x, src->y, src->width, src->height,
2211 physdev->x11dev->dc_rect.left + dst->x,
2212 physdev->x11dev->dc_rect.top + dst->y,
2213 dst->width, dst->height, xscale, yscale );
2215 wine_tsx11_lock();
2216 pXRenderFreePicture( gdi_display, src_pict );
2217 XFreePixmap( gdi_display, src_pixmap );
2218 wine_tsx11_unlock();
2220 LeaveCriticalSection( &xrender_cs );
2221 add_device_bounds( physdev->x11dev, &dst->visrect );
2223 return ret;
2225 update_format:
2226 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2227 set_color_info( physdev->pict_format, info );
2228 return ERROR_BAD_FORMAT;
2232 /***********************************************************************
2233 * xrenderdrv_AlphaBlend
2235 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2236 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2238 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2239 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2240 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2241 XRenderPictureAttributes pa;
2242 Pixmap tmp_pixmap = 0;
2243 double xscale, yscale;
2245 if (src_dev->funcs != dst_dev->funcs)
2247 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2248 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2251 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2253 SetLastError( ERROR_INVALID_PARAMETER );
2254 return FALSE;
2257 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2259 xscale = src->width / (double)dst->width;
2260 yscale = src->height / (double)dst->height;
2262 src_pict = get_xrender_picture_source( physdev_src, FALSE );
2264 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2266 /* mono -> color blending needs an intermediate color pixmap */
2267 XRenderColor fg, bg;
2268 int width = src->visrect.right - src->visrect.left;
2269 int height = src->visrect.bottom - src->visrect.top;
2271 /* blending doesn't use the destination DC colors */
2272 fg.red = fg.green = fg.blue = 0;
2273 bg.red = bg.green = bg.blue = 0xffff;
2274 fg.alpha = bg.alpha = 0xffff;
2276 wine_tsx11_lock();
2277 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2278 physdev_dst->pict_format->depth );
2279 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format, 0, NULL );
2280 wine_tsx11_unlock();
2282 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2283 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
2285 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2287 /* we need a source picture with no alpha */
2288 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2289 if (format != physdev_src->format)
2291 wine_tsx11_lock();
2292 pa.subwindow_mode = IncludeInferiors;
2293 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2294 pict_formats[format], CPSubwindowMode, &pa );
2295 wine_tsx11_unlock();
2299 if (tmp_pict) src_pict = tmp_pict;
2301 EnterCriticalSection( &xrender_cs );
2302 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2304 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2305 physdev_src->x11dev->dc_rect.left + src->x,
2306 physdev_src->x11dev->dc_rect.top + src->y,
2307 src->width, src->height,
2308 physdev_dst->x11dev->dc_rect.left + dst->x,
2309 physdev_dst->x11dev->dc_rect.top + dst->y,
2310 dst->width, dst->height, xscale, yscale );
2312 wine_tsx11_lock();
2313 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2314 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2315 wine_tsx11_unlock();
2317 LeaveCriticalSection( &xrender_cs );
2318 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2319 return TRUE;
2322 /***********************************************************************
2323 * xrenderdrv_GradientFill
2325 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2326 void * grad_array, ULONG ngrad, ULONG mode )
2328 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2329 static const XFixed stops[2] = { 0, 1 << 16 };
2330 struct xrender_physdev *physdev = get_xrender_dev( dev );
2331 XLinearGradient gradient;
2332 XRenderColor colors[2];
2333 Picture src_pict, dst_pict;
2334 unsigned int i;
2335 const GRADIENT_RECT *rect = grad_array;
2336 RECT rc;
2337 POINT pt[2];
2339 if (!pXRenderCreateLinearGradient) goto fallback;
2341 /* <= 16-bpp uses dithering */
2342 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2344 switch (mode)
2346 case GRADIENT_FILL_RECT_H:
2347 case GRADIENT_FILL_RECT_V:
2348 for (i = 0; i < ngrad; i++, rect++)
2350 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2351 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2353 colors[0].red = v1->Red * 257 / 256;
2354 colors[0].green = v1->Green * 257 / 256;
2355 colors[0].blue = v1->Blue * 257 / 256;
2356 colors[1].red = v2->Red * 257 / 256;
2357 colors[1].green = v2->Green * 257 / 256;
2358 colors[1].blue = v2->Blue * 257 / 256;
2359 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2360 colors[0].alpha = colors[1].alpha = 65535;
2362 pt[0].x = v1->x;
2363 pt[0].y = v1->y;
2364 pt[1].x = v2->x;
2365 pt[1].y = v2->y;
2366 LPtoDP( dev->hdc, pt, 2 );
2367 if (mode == GRADIENT_FILL_RECT_H)
2369 gradient.p1.y = gradient.p2.y = 0;
2370 if (pt[1].x > pt[0].x)
2372 gradient.p1.x = 0;
2373 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2375 else
2377 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2378 gradient.p2.x = 0;
2381 else
2383 gradient.p1.x = gradient.p2.x = 0;
2384 if (pt[1].y > pt[0].y)
2386 gradient.p1.y = 0;
2387 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2389 else
2391 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2392 gradient.p2.y = 0;
2396 rc.left = min( pt[0].x, pt[1].x );
2397 rc.top = min( pt[0].y, pt[1].y );
2398 rc.right = max( pt[0].x, pt[1].x );
2399 rc.bottom = max( pt[0].y, pt[1].y );
2401 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2402 mode, wine_dbgstr_rect( &rc ),
2403 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2404 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2406 dst_pict = get_xrender_picture( physdev, 0, NULL );
2408 wine_tsx11_lock();
2409 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2410 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2411 0, 0, rc.right - rc.left, rc.bottom - rc.top,
2412 physdev->x11dev->dc_rect.left + rc.left,
2413 physdev->x11dev->dc_rect.top + rc.top,
2414 rc.right - rc.left, rc.bottom - rc.top, 1, 1 );
2415 pXRenderFreePicture( gdi_display, src_pict );
2416 wine_tsx11_unlock();
2417 add_device_bounds( physdev->x11dev, &rc );
2419 return TRUE;
2422 fallback:
2423 #endif
2424 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2425 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2428 /***********************************************************************
2429 * xrenderdrv_SelectBrush
2431 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2433 struct xrender_physdev *physdev = get_xrender_dev( dev );
2434 Pixmap pixmap;
2435 XVisualInfo vis;
2436 XRenderPictFormat *format = physdev->pict_format;
2438 if (!pattern) goto x11drv_fallback;
2439 if (pattern->info->bmiHeader.biBitCount == 1) goto x11drv_fallback;
2440 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2442 memset( &vis, 0, sizeof(vis) );
2443 vis.depth = format->depth;
2444 vis.red_mask = format->direct.redMask << format->direct.red;
2445 vis.green_mask = format->direct.greenMask << format->direct.green;
2446 vis.blue_mask = format->direct.blueMask << format->direct.blue;
2448 pixmap = create_pixmap_from_image( physdev->dev.hdc, &vis, pattern->info,
2449 &pattern->bits, pattern->usage );
2450 if (!pixmap) return 0;
2452 wine_tsx11_lock();
2453 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2454 physdev->x11dev->brush.pixmap = pixmap;
2455 physdev->x11dev->brush.fillStyle = FillTiled;
2456 physdev->x11dev->brush.pixel = 0; /* ignored */
2457 physdev->x11dev->brush.style = BS_PATTERN;
2458 wine_tsx11_unlock();
2459 return hbrush;
2461 x11drv_fallback:
2462 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2463 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2467 static const struct gdi_dc_funcs xrender_funcs =
2469 NULL, /* pAbortDoc */
2470 NULL, /* pAbortPath */
2471 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2472 NULL, /* pAngleArc */
2473 NULL, /* pArc */
2474 NULL, /* pArcTo */
2475 NULL, /* pBeginPath */
2476 xrenderdrv_BlendImage, /* pBlendImage */
2477 NULL, /* pChord */
2478 NULL, /* pCloseFigure */
2479 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2480 xrenderdrv_CreateDC, /* pCreateDC */
2481 xrenderdrv_DeleteDC, /* pDeleteDC */
2482 NULL, /* pDeleteObject */
2483 NULL, /* pDescribePixelFormat */
2484 NULL, /* pDeviceCapabilities */
2485 NULL, /* pEllipse */
2486 NULL, /* pEndDoc */
2487 NULL, /* pEndPage */
2488 NULL, /* pEndPath */
2489 NULL, /* pEnumFonts */
2490 NULL, /* pEnumICMProfiles */
2491 NULL, /* pExcludeClipRect */
2492 NULL, /* pExtDeviceMode */
2493 xrenderdrv_ExtEscape, /* pExtEscape */
2494 NULL, /* pExtFloodFill */
2495 NULL, /* pExtSelectClipRgn */
2496 xrenderdrv_ExtTextOut, /* pExtTextOut */
2497 NULL, /* pFillPath */
2498 NULL, /* pFillRgn */
2499 NULL, /* pFlattenPath */
2500 NULL, /* pFontIsLinked */
2501 NULL, /* pFrameRgn */
2502 NULL, /* pGdiComment */
2503 NULL, /* pGdiRealizationInfo */
2504 NULL, /* pGetBoundsRect */
2505 NULL, /* pGetCharABCWidths */
2506 NULL, /* pGetCharABCWidthsI */
2507 NULL, /* pGetCharWidth */
2508 NULL, /* pGetDeviceCaps */
2509 NULL, /* pGetDeviceGammaRamp */
2510 NULL, /* pGetFontData */
2511 NULL, /* pGetFontUnicodeRanges */
2512 NULL, /* pGetGlyphIndices */
2513 NULL, /* pGetGlyphOutline */
2514 NULL, /* pGetICMProfile */
2515 NULL, /* pGetImage */
2516 NULL, /* pGetKerningPairs */
2517 NULL, /* pGetNearestColor */
2518 NULL, /* pGetOutlineTextMetrics */
2519 NULL, /* pGetPixel */
2520 NULL, /* pGetSystemPaletteEntries */
2521 NULL, /* pGetTextCharsetInfo */
2522 NULL, /* pGetTextExtentExPoint */
2523 NULL, /* pGetTextExtentExPointI */
2524 NULL, /* pGetTextFace */
2525 NULL, /* pGetTextMetrics */
2526 xrenderdrv_GradientFill, /* pGradientFill */
2527 NULL, /* pIntersectClipRect */
2528 NULL, /* pInvertRgn */
2529 NULL, /* pLineTo */
2530 NULL, /* pModifyWorldTransform */
2531 NULL, /* pMoveTo */
2532 NULL, /* pOffsetClipRgn */
2533 NULL, /* pOffsetViewportOrg */
2534 NULL, /* pOffsetWindowOrg */
2535 NULL, /* pPaintRgn */
2536 NULL, /* pPatBlt */
2537 NULL, /* pPie */
2538 NULL, /* pPolyBezier */
2539 NULL, /* pPolyBezierTo */
2540 NULL, /* pPolyDraw */
2541 NULL, /* pPolyPolygon */
2542 NULL, /* pPolyPolyline */
2543 NULL, /* pPolygon */
2544 NULL, /* pPolyline */
2545 NULL, /* pPolylineTo */
2546 xrenderdrv_PutImage, /* pPutImage */
2547 NULL, /* pRealizeDefaultPalette */
2548 NULL, /* pRealizePalette */
2549 NULL, /* pRectangle */
2550 NULL, /* pResetDC */
2551 NULL, /* pRestoreDC */
2552 NULL, /* pRoundRect */
2553 NULL, /* pSaveDC */
2554 NULL, /* pScaleViewportExt */
2555 NULL, /* pScaleWindowExt */
2556 NULL, /* pSelectBitmap */
2557 xrenderdrv_SelectBrush, /* pSelectBrush */
2558 NULL, /* pSelectClipPath */
2559 xrenderdrv_SelectFont, /* pSelectFont */
2560 NULL, /* pSelectPalette */
2561 NULL, /* pSelectPen */
2562 NULL, /* pSetArcDirection */
2563 NULL, /* pSetBkColor */
2564 NULL, /* pSetBkMode */
2565 NULL, /* pSetBoundsRect */
2566 NULL, /* pSetDCBrushColor */
2567 NULL, /* pSetDCPenColor */
2568 NULL, /* pSetDIBitsToDevice */
2569 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2570 NULL, /* pSetDeviceGammaRamp */
2571 NULL, /* pSetLayout */
2572 NULL, /* pSetMapMode */
2573 NULL, /* pSetMapperFlags */
2574 NULL, /* pSetPixel */
2575 NULL, /* pSetPixelFormat */
2576 NULL, /* pSetPolyFillMode */
2577 NULL, /* pSetROP2 */
2578 NULL, /* pSetRelAbs */
2579 NULL, /* pSetStretchBltMode */
2580 NULL, /* pSetTextAlign */
2581 NULL, /* pSetTextCharacterExtra */
2582 NULL, /* pSetTextColor */
2583 NULL, /* pSetTextJustification */
2584 NULL, /* pSetViewportExt */
2585 NULL, /* pSetViewportOrg */
2586 NULL, /* pSetWindowExt */
2587 NULL, /* pSetWindowOrg */
2588 NULL, /* pSetWorldTransform */
2589 NULL, /* pStartDoc */
2590 NULL, /* pStartPage */
2591 xrenderdrv_StretchBlt, /* pStretchBlt */
2592 NULL, /* pStretchDIBits */
2593 NULL, /* pStrokeAndFillPath */
2594 NULL, /* pStrokePath */
2595 NULL, /* pSwapBuffers */
2596 NULL, /* pUnrealizePalette */
2597 NULL, /* pWidenPath */
2598 NULL, /* wine_get_wgl_driver */
2599 GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
2602 #else /* SONAME_LIBXRENDER */
2604 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2606 TRACE("XRender support not compiled in.\n");
2607 return NULL;
2610 void X11DRV_XRender_Finalize(void)
2614 #endif /* SONAME_LIBXRENDER */