jscript: Removed unused do_*_tag_format arguments.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blob11b2ccf5bf29ab9105af2f44af73cead7242d3f1
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 static enum wxr_format get_bitmap_format( int bpp )
520 enum wxr_format format = WXR_INVALID_FORMAT;
522 if (bpp == screen_bpp)
524 switch (bpp)
526 case 16: format = WXR_FORMAT_R5G6B5; break;
527 case 24: format = WXR_FORMAT_R8G8B8; break;
528 case 32: format = WXR_FORMAT_A8R8G8B8; break;
531 return format;
534 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
535 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
537 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
538 XTransform xform = {{
539 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
540 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
541 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
544 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
545 #endif
548 /* check if we can use repeating instead of scaling for the specified source DC */
549 static BOOL use_source_repeat( struct xrender_physdev *dev )
551 return (dev->x11dev->bitmap &&
552 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
553 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
556 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
558 XRenderPictureAttributes pa;
559 RGNDATA *data;
561 if (!rgn)
563 wine_tsx11_lock();
564 pa.clip_mask = None;
565 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
566 wine_tsx11_unlock();
568 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
570 wine_tsx11_lock();
571 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
572 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
573 (XRectangle *)data->Buffer, data->rdh.nCount );
574 wine_tsx11_unlock();
575 HeapFree( GetProcessHeap(), 0, data );
580 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
582 if (!dev->pict && dev->pict_format)
584 XRenderPictureAttributes pa;
586 wine_tsx11_lock();
587 pa.subwindow_mode = IncludeInferiors;
588 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
589 dev->pict_format, CPSubwindowMode, &pa );
590 wine_tsx11_unlock();
591 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
592 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
593 dev->update_clip = (dev->region != 0);
596 if (clip_rect)
598 HRGN rgn = CreateRectRgnIndirect( clip_rect );
599 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
600 if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
601 update_xrender_clipping( dev, rgn );
602 DeleteObject( rgn );
604 else if (clip_rgn)
606 if (dev->region)
608 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
609 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
610 update_xrender_clipping( dev, rgn );
611 DeleteObject( rgn );
613 else update_xrender_clipping( dev, clip_rgn );
615 else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
617 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
618 return dev->pict;
621 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
623 if (!dev->pict_src && dev->pict_format)
625 XRenderPictureAttributes pa;
627 wine_tsx11_lock();
628 pa.subwindow_mode = IncludeInferiors;
629 pa.repeat = repeat ? RepeatNormal : RepeatNone;
630 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
631 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
632 wine_tsx11_unlock();
634 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
635 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
638 return dev->pict_src;
641 static void free_xrender_picture( struct xrender_physdev *dev )
643 if (dev->pict || dev->pict_src)
645 wine_tsx11_lock();
646 XFlush( gdi_display );
647 if (dev->pict)
649 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
650 pXRenderFreePicture(gdi_display, dev->pict);
651 dev->pict = 0;
653 if(dev->pict_src)
655 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
656 pXRenderFreePicture(gdi_display, dev->pict_src);
657 dev->pict_src = 0;
659 wine_tsx11_unlock();
663 /* return a mask picture used to force alpha to 0 */
664 static Picture get_no_alpha_mask(void)
666 static Pixmap pixmap;
667 static Picture pict;
669 wine_tsx11_lock();
670 if (!pict)
672 XRenderPictureAttributes pa;
673 XRenderColor col;
675 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
676 pa.repeat = RepeatNormal;
677 pa.component_alpha = True;
678 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
679 CPRepeat|CPComponentAlpha, &pa );
680 col.red = col.green = col.blue = 0xffff;
681 col.alpha = 0;
682 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
684 wine_tsx11_unlock();
685 return pict;
688 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
690 if(p1->hash != p2->hash) return TRUE;
691 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
692 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
693 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
694 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
697 #if 0
698 static void walk_cache(void)
700 int i;
702 EnterCriticalSection(&xrender_cs);
703 for(i=mru; i >= 0; i = glyphsetCache[i].next)
704 TRACE("item %d\n", i);
705 LeaveCriticalSection(&xrender_cs);
707 #endif
709 static int LookupEntry(LFANDSIZE *plfsz)
711 int i, prev_i = -1;
713 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
714 TRACE("%d\n", i);
715 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
717 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
718 glyphsetCache[i].count++;
719 if(prev_i >= 0) {
720 glyphsetCache[prev_i].next = glyphsetCache[i].next;
721 glyphsetCache[i].next = mru;
722 mru = i;
724 TRACE("found font in cache %d\n", i);
725 return i;
727 prev_i = i;
729 TRACE("font not in cache\n");
730 return -1;
733 static void FreeEntry(int entry)
735 int format;
737 for(format = 0; format < AA_MAXVALUE; format++) {
738 gsCacheEntryFormat * formatEntry;
740 if( !glyphsetCache[entry].format[format] )
741 continue;
743 formatEntry = glyphsetCache[entry].format[format];
745 if(formatEntry->glyphset) {
746 wine_tsx11_lock();
747 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
748 wine_tsx11_unlock();
749 formatEntry->glyphset = 0;
751 if(formatEntry->nrealized) {
752 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
753 formatEntry->realized = NULL;
754 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
755 formatEntry->gis = NULL;
756 formatEntry->nrealized = 0;
759 HeapFree(GetProcessHeap(), 0, formatEntry);
760 glyphsetCache[entry].format[format] = NULL;
764 static int AllocEntry(void)
766 int best = -1, prev_best = -1, i, prev_i = -1;
768 if(lastfree >= 0) {
769 assert(glyphsetCache[lastfree].count == -1);
770 glyphsetCache[lastfree].count = 1;
771 best = lastfree;
772 lastfree = glyphsetCache[lastfree].next;
773 assert(best != mru);
774 glyphsetCache[best].next = mru;
775 mru = best;
777 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
778 return mru;
781 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
782 if(glyphsetCache[i].count == 0) {
783 best = i;
784 prev_best = prev_i;
786 prev_i = i;
789 if(best >= 0) {
790 TRACE("freeing unused glyphset at cache %d\n", best);
791 FreeEntry(best);
792 glyphsetCache[best].count = 1;
793 if(prev_best >= 0) {
794 glyphsetCache[prev_best].next = glyphsetCache[best].next;
795 glyphsetCache[best].next = mru;
796 mru = best;
797 } else {
798 assert(mru == best);
800 return mru;
803 TRACE("Growing cache\n");
805 if (glyphsetCache)
806 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
807 glyphsetCache,
808 (glyphsetCacheSize + INIT_CACHE_SIZE)
809 * sizeof(*glyphsetCache));
810 else
811 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
812 (glyphsetCacheSize + INIT_CACHE_SIZE)
813 * sizeof(*glyphsetCache));
815 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
816 i++) {
817 glyphsetCache[i].next = i + 1;
818 glyphsetCache[i].count = -1;
820 glyphsetCache[i-1].next = -1;
821 glyphsetCacheSize += INIT_CACHE_SIZE;
823 lastfree = glyphsetCache[best].next;
824 glyphsetCache[best].count = 1;
825 glyphsetCache[best].next = mru;
826 mru = best;
827 TRACE("new free cache slot at %d\n", mru);
828 return mru;
831 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
833 DWORD size;
834 WORD *gasp, *buffer;
835 WORD num_recs;
836 DWORD ppem;
837 TEXTMETRICW tm;
839 *flags = 0;
841 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
842 if(size == GDI_ERROR)
843 return FALSE;
845 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
846 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
848 GetTextMetricsW(hdc, &tm);
849 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
851 gasp++;
852 num_recs = get_be_word(*gasp);
853 gasp++;
854 while(num_recs--)
856 *flags = get_be_word(*(gasp + 1));
857 if(ppem <= get_be_word(*gasp))
858 break;
859 gasp += 2;
861 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
863 HeapFree(GetProcessHeap(), 0, buffer);
864 return TRUE;
867 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
869 AA_Type ret;
870 WORD flags;
871 UINT font_smoothing_type, font_smoothing_orientation;
873 if (subpixel &&
874 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
875 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
877 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
878 &font_smoothing_orientation, 0) &&
879 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
881 ret = AA_BGR;
883 else
884 ret = AA_RGB;
885 /*FIXME
886 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
887 But, Wine's subpixel rendering can support the portrait mode.
890 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
891 ret = AA_Grey;
892 else
893 ret = AA_None;
895 return ret;
898 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
900 int ret;
901 int format;
902 gsCacheEntry *entry;
903 static int hinter = -1;
904 static int subpixel = -1;
905 BOOL font_smoothing;
907 if((ret = LookupEntry(plfsz)) != -1) return ret;
909 ret = AllocEntry();
910 entry = glyphsetCache + ret;
911 entry->lfsz = *plfsz;
912 for( format = 0; format < AA_MAXVALUE; format++ ) {
913 assert( !entry->format[format] );
916 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
918 if(hinter == -1 || subpixel == -1)
920 RASTERIZER_STATUS status;
921 GetRasterizerCaps(&status, sizeof(status));
922 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
923 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
926 switch (plfsz->lf.lfQuality)
928 case ANTIALIASED_QUALITY:
929 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
930 return ret; /* ignore further configuration */
931 case CLEARTYPE_QUALITY:
932 case CLEARTYPE_NATURAL_QUALITY:
933 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
934 break;
935 case DEFAULT_QUALITY:
936 case DRAFT_QUALITY:
937 case PROOF_QUALITY:
938 default:
939 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
940 font_smoothing)
942 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
944 else
945 entry->aa_default = AA_None;
946 break;
949 font_smoothing = TRUE; /* default to enabled */
950 #ifdef SONAME_LIBFONTCONFIG
951 if (fontconfig_installed)
953 FcPattern *match, *pattern;
954 FcResult result;
955 char family[LF_FACESIZE * 4];
957 #if defined(__i386__) && defined(__GNUC__)
958 /* fontconfig generates floating point exceptions, mask them */
959 WORD cw, default_cw = 0x37f;
960 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
961 #endif
963 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
964 pattern = pFcPatternCreate();
965 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
966 if (plfsz->lf.lfWeight != FW_DONTCARE)
968 int weight;
969 switch (plfsz->lf.lfWeight)
971 case FW_THIN: weight = FC_WEIGHT_THIN; break;
972 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
973 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
974 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
975 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
976 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
977 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
978 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
979 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
980 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
982 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
984 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
985 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
986 pFcDefaultSubstitute( pattern );
987 if ((match = pFcFontMatch( NULL, pattern, &result )))
989 int rgba;
990 FcBool antialias;
992 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
993 antialias = TRUE;
994 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
996 FcChar8 *file;
997 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
999 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
1000 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
1002 switch (rgba)
1004 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1005 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1006 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1007 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1008 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1011 if (!antialias) font_smoothing = FALSE;
1012 pFcPatternDestroy( match );
1014 pFcPatternDestroy( pattern );
1016 #if defined(__i386__) && defined(__GNUC__)
1017 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
1018 #endif
1020 #endif /* SONAME_LIBFONTCONFIG */
1022 /* now check Xft resources */
1024 char *value;
1025 BOOL antialias = TRUE;
1027 wine_tsx11_lock();
1028 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1030 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1031 value[0] == '0' || !strcasecmp( value, "off" ))
1032 antialias = FALSE;
1034 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1036 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1037 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1038 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1039 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1040 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1041 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1043 wine_tsx11_unlock();
1044 if (!antialias) font_smoothing = FALSE;
1047 if (!font_smoothing) entry->aa_default = AA_None;
1049 else
1050 entry->aa_default = AA_None;
1052 return ret;
1055 static void dec_ref_cache(int index)
1057 assert(index >= 0);
1058 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1059 assert(glyphsetCache[index].count > 0);
1060 glyphsetCache[index].count--;
1063 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1065 DWORD hash = 0, *ptr, two_chars;
1066 WORD *pwc;
1067 int i;
1069 hash ^= plfsz->devsize.cx;
1070 hash ^= plfsz->devsize.cy;
1071 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1072 hash ^= *ptr;
1073 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1074 hash ^= *ptr;
1075 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1076 two_chars = *ptr;
1077 pwc = (WCHAR *)&two_chars;
1078 if(!*pwc) break;
1079 *pwc = toupperW(*pwc);
1080 pwc++;
1081 *pwc = toupperW(*pwc);
1082 hash ^= two_chars;
1083 if(!*pwc) break;
1085 plfsz->hash = hash;
1086 return;
1089 /***********************************************************************
1090 * X11DRV_XRender_Finalize
1092 void X11DRV_XRender_Finalize(void)
1094 int i;
1096 EnterCriticalSection(&xrender_cs);
1097 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1098 FreeEntry(i);
1099 LeaveCriticalSection(&xrender_cs);
1100 DeleteCriticalSection(&xrender_cs);
1103 /**********************************************************************
1104 * xrenderdrv_SelectFont
1106 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1108 LFANDSIZE lfsz;
1109 struct xrender_physdev *physdev = get_xrender_dev( dev );
1110 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1111 HFONT ret = next->funcs->pSelectFont( next, hfont );
1113 if (!ret) return 0;
1115 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1117 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1118 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1119 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1120 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1121 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1122 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1124 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1125 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1126 lfsz.xform.eM21, lfsz.xform.eM22);
1128 if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE && lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
1129 lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
1131 /* Not used fields, would break hashing */
1132 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1134 lfsz_calc_hash(&lfsz);
1136 EnterCriticalSection(&xrender_cs);
1137 if (physdev->cache_index != -1)
1138 dec_ref_cache( physdev->cache_index );
1139 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1140 LeaveCriticalSection(&xrender_cs);
1141 return ret;
1144 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1146 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1147 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1149 if (!physdev) return FALSE;
1150 physdev->x11dev = x11dev;
1151 physdev->cache_index = -1;
1152 physdev->format = format;
1153 physdev->pict_format = pict_formats[format];
1154 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1155 return TRUE;
1158 /* store the color mask data in the bitmap info structure */
1159 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1161 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1163 info->bmiHeader.biPlanes = 1;
1164 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1165 info->bmiHeader.biCompression = BI_RGB;
1166 info->bmiHeader.biClrUsed = 0;
1168 switch (info->bmiHeader.biBitCount)
1170 case 16:
1171 colors[0] = format->direct.redMask << format->direct.red;
1172 colors[1] = format->direct.greenMask << format->direct.green;
1173 colors[2] = format->direct.blueMask << format->direct.blue;
1174 info->bmiHeader.biCompression = BI_BITFIELDS;
1175 break;
1176 case 32:
1177 colors[0] = format->direct.redMask << format->direct.red;
1178 colors[1] = format->direct.greenMask << format->direct.green;
1179 colors[2] = format->direct.blueMask << format->direct.blue;
1180 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1181 info->bmiHeader.biCompression = BI_BITFIELDS;
1182 break;
1187 /**********************************************************************
1188 * xrenderdrv_CreateDC
1190 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1191 LPCWSTR output, const DEVMODEW* initData )
1193 return create_xrender_dc( pdev, default_format );
1196 /**********************************************************************
1197 * xrenderdrv_CreateCompatibleDC
1199 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1201 if (orig) /* chain to x11drv first */
1203 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1204 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1206 /* otherwise we have been called by x11drv */
1208 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1211 /**********************************************************************
1212 * xrenderdrv_DeleteDC
1214 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1216 struct xrender_physdev *physdev = get_xrender_dev( dev );
1218 free_xrender_picture( physdev );
1220 EnterCriticalSection( &xrender_cs );
1221 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1222 LeaveCriticalSection( &xrender_cs );
1224 HeapFree( GetProcessHeap(), 0, physdev );
1225 return TRUE;
1228 /**********************************************************************
1229 * xrenderdrv_ExtEscape
1231 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1232 INT out_count, LPVOID out_data )
1234 struct xrender_physdev *physdev = get_xrender_dev( dev );
1236 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1238 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1240 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1242 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1243 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1244 return ret;
1247 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1250 /****************************************************************************
1251 * xrenderdrv_CopyBitmap
1253 static BOOL xrenderdrv_CopyBitmap( HBITMAP src, HBITMAP dst )
1255 return X11DRV_CopyBitmap( src, dst );
1258 /****************************************************************************
1259 * xrenderdrv_CreateBitmap
1261 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1263 enum wxr_format format = WXR_INVALID_FORMAT;
1264 X_PHYSBITMAP *phys_bitmap;
1265 BITMAP bitmap;
1267 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1269 if (bitmap.bmBitsPixel == 1)
1271 if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, 1 ))) return FALSE;
1272 phys_bitmap->format = WXR_FORMAT_MONO;
1273 phys_bitmap->trueColor = FALSE;
1275 else
1277 format = get_bitmap_format( bitmap.bmBitsPixel );
1279 if (pict_formats[format])
1281 if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth )))
1282 return FALSE;
1283 phys_bitmap->format = format;
1284 phys_bitmap->trueColor = TRUE;
1285 phys_bitmap->color_shifts = wxr_color_shifts[format];
1287 else
1289 if (!(phys_bitmap = X11DRV_create_phys_bitmap( hbitmap, &bitmap, screen_depth )))
1290 return FALSE;
1291 phys_bitmap->format = WXR_INVALID_FORMAT;
1292 phys_bitmap->trueColor = (visual->class == TrueColor || visual->class == DirectColor);
1293 phys_bitmap->color_shifts = X11DRV_PALETTE_default_shifts;
1296 return TRUE;
1299 /****************************************************************************
1300 * xrenderdrv_DeleteBitmap
1302 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1304 return X11DRV_DeleteBitmap( hbitmap );
1307 /***********************************************************************
1308 * xrenderdrv_SelectBitmap
1310 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1312 HBITMAP ret;
1313 struct xrender_physdev *physdev = get_xrender_dev( dev );
1315 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1316 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1317 if (ret)
1319 free_xrender_picture( physdev );
1320 if (hbitmap == BITMAP_stock_phys_bitmap.hbitmap) physdev->format = WXR_FORMAT_MONO;
1321 else physdev->format = X11DRV_get_phys_bitmap(hbitmap)->format;
1322 physdev->pict_format = pict_formats[physdev->format];
1324 return ret;
1327 /***********************************************************************
1328 * xrenderdrv_GetImage
1330 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1331 struct gdi_image_bits *bits, struct bitblt_coords *src )
1333 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1334 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1335 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1338 /***********************************************************************
1339 * xrenderdrv_SetDeviceClipping
1341 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1343 struct xrender_physdev *physdev = get_xrender_dev( dev );
1345 physdev->region = rgn;
1346 physdev->update_clip = TRUE;
1348 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1349 dev->funcs->pSetDeviceClipping( dev, rgn );
1353 /************************************************************************
1354 * UploadGlyph
1356 * Helper to ExtTextOut. Must be called inside xrender_cs
1358 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1360 unsigned int buflen;
1361 char *buf;
1362 Glyph gid;
1363 GLYPHMETRICS gm;
1364 XGlyphInfo gi;
1365 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1366 gsCacheEntryFormat *formatEntry;
1367 UINT ggo_format = GGO_GLYPH_INDEX;
1368 enum wxr_format wxr_format;
1369 static const char zero[4];
1370 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1372 switch(format) {
1373 case AA_Grey:
1374 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1375 break;
1376 case AA_RGB:
1377 ggo_format |= WINE_GGO_HRGB_BITMAP;
1378 break;
1379 case AA_BGR:
1380 ggo_format |= WINE_GGO_HBGR_BITMAP;
1381 break;
1382 case AA_VRGB:
1383 ggo_format |= WINE_GGO_VRGB_BITMAP;
1384 break;
1385 case AA_VBGR:
1386 ggo_format |= WINE_GGO_VBGR_BITMAP;
1387 break;
1389 default:
1390 ERR("aa = %d - not implemented\n", format);
1391 case AA_None:
1392 ggo_format |= GGO_BITMAP;
1393 break;
1396 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1397 if(buflen == GDI_ERROR) {
1398 if(format != AA_None) {
1399 format = AA_None;
1400 entry->aa_default = AA_None;
1401 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1402 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1404 if(buflen == GDI_ERROR) {
1405 WARN("GetGlyphOutlineW failed using default glyph\n");
1406 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1407 if(buflen == GDI_ERROR) {
1408 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1409 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1410 if(buflen == GDI_ERROR) {
1411 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1412 return;
1416 TRACE("Turning off antialiasing for this monochrome font\n");
1419 /* If there is nothing for the current type, we create the entry. */
1420 if( !entry->format[format] ) {
1421 entry->format[format] = HeapAlloc(GetProcessHeap(),
1422 HEAP_ZERO_MEMORY,
1423 sizeof(gsCacheEntryFormat));
1425 formatEntry = entry->format[format];
1427 if(formatEntry->nrealized <= glyph) {
1428 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1430 if (formatEntry->realized)
1431 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1432 HEAP_ZERO_MEMORY,
1433 formatEntry->realized,
1434 formatEntry->nrealized * sizeof(BOOL));
1435 else
1436 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1437 HEAP_ZERO_MEMORY,
1438 formatEntry->nrealized * sizeof(BOOL));
1440 if (formatEntry->gis)
1441 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1442 HEAP_ZERO_MEMORY,
1443 formatEntry->gis,
1444 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1445 else
1446 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1447 HEAP_ZERO_MEMORY,
1448 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1452 if(formatEntry->glyphset == 0) {
1453 switch(format) {
1454 case AA_Grey:
1455 wxr_format = WXR_FORMAT_GRAY;
1456 break;
1458 case AA_RGB:
1459 case AA_BGR:
1460 case AA_VRGB:
1461 case AA_VBGR:
1462 wxr_format = WXR_FORMAT_A8R8G8B8;
1463 break;
1465 default:
1466 ERR("aa = %d - not implemented\n", format);
1467 case AA_None:
1468 wxr_format = WXR_FORMAT_MONO;
1469 break;
1472 wine_tsx11_lock();
1473 formatEntry->font_format = pict_formats[wxr_format];
1474 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1475 wine_tsx11_unlock();
1479 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1480 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1481 formatEntry->realized[glyph] = TRUE;
1483 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1484 buflen,
1485 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1486 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1488 gi.width = gm.gmBlackBoxX;
1489 gi.height = gm.gmBlackBoxY;
1490 gi.x = -gm.gmptGlyphOrigin.x;
1491 gi.y = gm.gmptGlyphOrigin.y;
1492 gi.xOff = gm.gmCellIncX;
1493 gi.yOff = gm.gmCellIncY;
1495 if(TRACE_ON(xrender)) {
1496 int pitch, i, j;
1497 char output[300];
1498 unsigned char *line;
1500 if(format == AA_None) {
1501 pitch = ((gi.width + 31) / 32) * 4;
1502 for(i = 0; i < gi.height; i++) {
1503 line = (unsigned char*) buf + i * pitch;
1504 output[0] = '\0';
1505 for(j = 0; j < pitch * 8; j++) {
1506 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1508 TRACE("%s\n", output);
1510 } else {
1511 static const char blks[] = " .:;!o*#";
1512 char str[2];
1514 str[1] = '\0';
1515 pitch = ((gi.width + 3) / 4) * 4;
1516 for(i = 0; i < gi.height; i++) {
1517 line = (unsigned char*) buf + i * pitch;
1518 output[0] = '\0';
1519 for(j = 0; j < pitch; j++) {
1520 str[0] = blks[line[j] >> 5];
1521 strcat(output, str);
1523 TRACE("%s\n", output);
1529 if(formatEntry->glyphset) {
1530 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1531 unsigned char *byte = (unsigned char*) buf, c;
1532 int i = buflen;
1534 while(i--) {
1535 c = *byte;
1537 /* magic to flip bit order */
1538 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1539 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1540 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1542 *byte++ = c;
1545 else if ( format != AA_Grey &&
1546 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1548 unsigned int i, *data = (unsigned int *)buf;
1549 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1551 gid = glyph;
1554 XRenderCompositeText seems to ignore 0x0 glyphs when
1555 AA_None, which means we lose the advance width of glyphs
1556 like the space. We'll pretend that such glyphs are 1x1
1557 bitmaps.
1560 if(buflen == 0)
1561 gi.width = gi.height = 1;
1563 wine_tsx11_lock();
1564 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1565 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1566 wine_tsx11_unlock();
1567 HeapFree(GetProcessHeap(), 0, buf);
1570 formatEntry->gis[glyph] = gi;
1573 /*************************************************************
1574 * get_tile_pict
1576 * Returns an appropriate Picture for tiling the text colour.
1577 * Call and use result within the xrender_cs
1579 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1581 static struct
1583 Pixmap xpm;
1584 Picture pict;
1585 XRenderColor current_color;
1586 } tiles[WXR_NB_FORMATS], *tile;
1588 tile = &tiles[wxr_format];
1590 if(!tile->xpm)
1592 XRenderPictureAttributes pa;
1593 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1595 wine_tsx11_lock();
1596 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1598 pa.repeat = RepeatNormal;
1599 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1600 wine_tsx11_unlock();
1602 /* init current_color to something different from text_pixel */
1603 tile->current_color = *color;
1604 tile->current_color.red ^= 0xffff;
1606 if (wxr_format == WXR_FORMAT_MONO)
1608 /* for a 1bpp bitmap we always need a 1 in the tile */
1609 XRenderColor col;
1610 col.red = col.green = col.blue = 0;
1611 col.alpha = 0xffff;
1612 wine_tsx11_lock();
1613 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1614 wine_tsx11_unlock();
1618 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1620 wine_tsx11_lock();
1621 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1622 wine_tsx11_unlock();
1623 tile->current_color = *color;
1625 return tile->pict;
1628 /*************************************************************
1629 * get_mask_pict
1631 * Returns an appropriate Picture for masking with the specified alpha.
1632 * Call and use result within the xrender_cs
1634 static Picture get_mask_pict( int alpha )
1636 static Pixmap pixmap;
1637 static Picture pict;
1638 static int current_alpha;
1640 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1642 if (!pixmap)
1644 XRenderPictureAttributes pa;
1646 wine_tsx11_lock();
1647 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1648 pa.repeat = RepeatNormal;
1649 pict = pXRenderCreatePicture( gdi_display, pixmap,
1650 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1651 wine_tsx11_unlock();
1652 current_alpha = -1;
1655 if (alpha != current_alpha)
1657 XRenderColor col;
1658 col.red = col.green = col.blue = 0;
1659 col.alpha = current_alpha = alpha;
1660 wine_tsx11_lock();
1661 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1662 wine_tsx11_unlock();
1664 return pict;
1667 /***********************************************************************
1668 * xrenderdrv_ExtTextOut
1670 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1671 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1673 struct xrender_physdev *physdev = get_xrender_dev( dev );
1674 gsCacheEntry *entry;
1675 gsCacheEntryFormat *formatEntry;
1676 AA_Type aa_type = AA_None;
1677 unsigned int idx;
1678 Picture pict, tile_pict = 0;
1679 XGlyphElt16 *elts;
1680 POINT offset, desired, current;
1681 int render_op = PictOpOver;
1682 XRenderColor col;
1683 RECT rect, bounds;
1685 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1686 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1688 if(flags & ETO_OPAQUE)
1690 XRenderColor bg;
1692 if (physdev->format == WXR_FORMAT_MONO)
1693 /* use the inverse of the text color */
1694 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1695 else
1696 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1698 wine_tsx11_lock();
1699 set_xrender_transformation( pict, 1, 1, 0, 0 );
1700 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1701 physdev->x11dev->dc_rect.left + lprect->left,
1702 physdev->x11dev->dc_rect.top + lprect->top,
1703 lprect->right - lprect->left,
1704 lprect->bottom - lprect->top );
1705 wine_tsx11_unlock();
1706 add_device_bounds( physdev->x11dev, lprect );
1709 if(count == 0) return TRUE;
1711 EnterCriticalSection(&xrender_cs);
1713 entry = glyphsetCache + physdev->cache_index;
1714 aa_type = entry->aa_default;
1715 formatEntry = entry->format[aa_type];
1717 for(idx = 0; idx < count; idx++) {
1718 if( !formatEntry ) {
1719 UploadGlyph(physdev, wstr[idx], aa_type);
1720 /* re-evaluate antialias since aa_default may have changed */
1721 aa_type = entry->aa_default;
1722 formatEntry = entry->format[aa_type];
1723 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1724 UploadGlyph(physdev, wstr[idx], aa_type);
1727 if (!formatEntry)
1729 WARN("could not upload requested glyphs\n");
1730 LeaveCriticalSection(&xrender_cs);
1731 return FALSE;
1734 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1735 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1737 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1739 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1740 So we pass zeros to the function and move to our starting position using the first
1741 element of the elts array. */
1743 desired.x = physdev->x11dev->dc_rect.left + x;
1744 desired.y = physdev->x11dev->dc_rect.top + y;
1745 offset.x = offset.y = 0;
1746 current.x = current.y = 0;
1748 tile_pict = get_tile_pict(physdev->format, &col);
1750 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1752 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1753 render_op = PictOpOutReverse; /* This gives us 'black' text */
1755 reset_bounds( &bounds );
1756 for(idx = 0; idx < count; idx++)
1758 elts[idx].glyphset = formatEntry->glyphset;
1759 elts[idx].chars = wstr + idx;
1760 elts[idx].nchars = 1;
1761 elts[idx].xOff = desired.x - current.x;
1762 elts[idx].yOff = desired.y - current.y;
1764 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1765 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1767 rect.left = desired.x - physdev->x11dev->dc_rect.left - formatEntry->gis[wstr[idx]].x;
1768 rect.top = desired.y - physdev->x11dev->dc_rect.top - formatEntry->gis[wstr[idx]].y;
1769 rect.right = rect.left + formatEntry->gis[wstr[idx]].width;
1770 rect.bottom = rect.top + formatEntry->gis[wstr[idx]].height;
1771 add_bounds_rect( &bounds, &rect );
1773 if(!lpDx)
1775 desired.x += formatEntry->gis[wstr[idx]].xOff;
1776 desired.y += formatEntry->gis[wstr[idx]].yOff;
1778 else
1780 if(flags & ETO_PDY)
1782 offset.x += lpDx[idx * 2];
1783 offset.y += lpDx[idx * 2 + 1];
1785 else
1786 offset.x += lpDx[idx];
1787 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1788 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1792 wine_tsx11_lock();
1793 /* Make sure we don't have any transforms set from a previous call */
1794 set_xrender_transformation(pict, 1, 1, 0, 0);
1795 pXRenderCompositeText16(gdi_display, render_op,
1796 tile_pict,
1797 pict,
1798 formatEntry->font_format,
1799 0, 0, 0, 0, elts, count);
1800 wine_tsx11_unlock();
1801 HeapFree(GetProcessHeap(), 0, elts);
1803 LeaveCriticalSection(&xrender_cs);
1804 add_device_bounds( physdev->x11dev, &bounds );
1805 return TRUE;
1808 /* multiply the alpha channel of a picture */
1809 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1810 int x, int y, int width, int height )
1812 XRenderPictureAttributes pa;
1813 Pixmap src_pixmap, mask_pixmap;
1814 Picture src_pict, mask_pict;
1815 XRenderColor color;
1817 wine_tsx11_lock();
1818 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1819 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1820 pa.repeat = RepeatNormal;
1821 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1822 pa.component_alpha = True;
1823 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1824 color.red = color.green = color.blue = color.alpha = 0xffff;
1825 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1826 color.alpha = alpha;
1827 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1828 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1829 0, 0, 0, 0, x, y, width, height );
1830 pXRenderFreePicture( gdi_display, src_pict );
1831 pXRenderFreePicture( gdi_display, mask_pict );
1832 XFreePixmap( gdi_display, src_pixmap );
1833 XFreePixmap( gdi_display, mask_pixmap );
1834 wine_tsx11_unlock();
1837 /* Helper function for (stretched) blitting using xrender */
1838 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1839 int x_src, int y_src, int width_src, int height_src,
1840 int x_dst, int y_dst, int width_dst, int height_dst,
1841 double xscale, double yscale )
1843 int x_offset, y_offset;
1845 if (width_src < 0)
1847 x_src += width_src + 1;
1848 width_src = -width_src;
1850 if (height_src < 0)
1852 y_src += height_src + 1;
1853 height_src = -height_src;
1855 if (width_dst < 0)
1857 x_dst += width_dst + 1;
1858 width_dst = -width_dst;
1860 if (height_dst < 0)
1862 y_dst += height_dst + 1;
1863 height_dst = -height_dst;
1866 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1867 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1868 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1869 wine_tsx11_lock();
1870 if(xscale != 1.0 || yscale != 1.0)
1872 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1873 * in the wrong quadrant of the x-y plane.
1875 x_offset = (xscale < 0) ? -width_dst : 0;
1876 y_offset = (yscale < 0) ? -height_dst : 0;
1877 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1879 else
1881 x_offset = x_src;
1882 y_offset = y_src;
1883 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1885 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1886 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1887 wine_tsx11_unlock();
1890 /* Helper function for (stretched) mono->color blitting using xrender */
1891 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1892 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1893 int x_src, int y_src, int width_src, int height_src,
1894 int x_dst, int y_dst, int width_dst, int height_dst,
1895 double xscale, double yscale )
1897 Picture tile_pict;
1898 int x_offset, y_offset;
1899 XRenderColor color;
1901 if (width_src < 0)
1903 x_src += width_src + 1;
1904 width_src = -width_src;
1906 if (height_src < 0)
1908 y_src += height_src + 1;
1909 height_src = -height_src;
1911 if (width_dst < 0)
1913 x_dst += width_dst + 1;
1914 width_dst = -width_dst;
1916 if (height_dst < 0)
1918 y_dst += height_dst + 1;
1919 height_dst = -height_dst;
1922 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1923 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1924 * the tile data.
1926 EnterCriticalSection( &xrender_cs );
1927 color = *bg;
1928 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1929 tile_pict = get_tile_pict( dst_format, &color );
1931 wine_tsx11_lock();
1932 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1934 if (xscale != 1.0 || yscale != 1.0)
1936 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1937 * in the wrong quadrant of the x-y plane.
1939 x_offset = (xscale < 0) ? -width_dst : 0;
1940 y_offset = (yscale < 0) ? -height_dst : 0;
1941 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1943 else
1945 x_offset = x_src;
1946 y_offset = y_src;
1947 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1949 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1950 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1951 wine_tsx11_unlock();
1952 LeaveCriticalSection( &xrender_cs );
1954 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1955 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1956 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1957 x_dst, y_dst, width_dst, height_dst );
1960 /* create a pixmap and render picture for an image */
1961 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1962 struct bitblt_coords *src, enum wxr_format format,
1963 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1965 DWORD ret;
1966 int width = src->visrect.right - src->visrect.left;
1967 int height = src->visrect.bottom - src->visrect.top;
1968 int depth = pict_formats[format]->depth;
1969 struct gdi_image_bits dst_bits;
1970 XRenderPictureAttributes pa;
1971 XImage *image;
1973 wine_tsx11_lock();
1974 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1975 info->bmiHeader.biWidth, height, 32, 0 );
1976 wine_tsx11_unlock();
1977 if (!image) return ERROR_OUTOFMEMORY;
1979 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1980 if (ret) return ret;
1982 image->data = dst_bits.ptr;
1984 *use_repeat = (width == 1 && height == 1);
1985 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1987 wine_tsx11_lock();
1988 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1989 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
1990 src->visrect.left, 0, 0, 0, width, height );
1991 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1992 wine_tsx11_unlock();
1994 /* make coordinates relative to the pixmap */
1995 src->x -= src->visrect.left;
1996 src->y -= src->visrect.top;
1997 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1999 image->data = NULL;
2000 wine_tsx11_lock();
2001 XDestroyImage( image );
2002 wine_tsx11_unlock();
2003 if (dst_bits.free) dst_bits.free( &dst_bits );
2004 return ret;
2007 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2008 Drawable drawable, const struct bitblt_coords *src,
2009 const struct bitblt_coords *dst )
2011 int x_dst, y_dst;
2012 Picture src_pict = 0, dst_pict, mask_pict = 0;
2013 BOOL use_repeat;
2014 double xscale, yscale;
2016 use_repeat = use_source_repeat( physdev_src );
2017 if (!use_repeat)
2019 xscale = src->width / (double)dst->width;
2020 yscale = src->height / (double)dst->height;
2022 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2024 if (drawable) /* using an intermediate pixmap */
2026 XRenderPictureAttributes pa;
2028 x_dst = dst->x;
2029 y_dst = dst->y;
2030 pa.repeat = RepeatNone;
2031 wine_tsx11_lock();
2032 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2033 wine_tsx11_unlock();
2035 else
2037 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2038 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2039 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2042 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2044 /* mono -> color */
2045 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2047 XRenderColor fg, bg;
2049 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
2050 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
2051 fg.alpha = bg.alpha = 0;
2053 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2054 physdev_src->x11dev->dc_rect.left + src->x,
2055 physdev_src->x11dev->dc_rect.top + src->y,
2056 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2058 else /* color -> color (can be at different depths) or mono -> mono */
2060 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
2061 mask_pict = get_no_alpha_mask();
2063 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2064 physdev_src->x11dev->dc_rect.left + src->x,
2065 physdev_src->x11dev->dc_rect.top + src->y,
2066 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2069 if (drawable)
2071 wine_tsx11_lock();
2072 pXRenderFreePicture( gdi_display, dst_pict );
2073 wine_tsx11_unlock();
2078 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2079 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2080 Drawable drawable, struct bitblt_coords *src,
2081 struct bitblt_coords *dst, BOOL use_repeat )
2083 int x_dst, y_dst;
2084 Picture dst_pict;
2085 XRenderPictureAttributes pa;
2086 double xscale, yscale;
2088 if (drawable) /* using an intermediate pixmap */
2090 RGNDATA *clip_data = NULL;
2092 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2093 x_dst = dst->x;
2094 y_dst = dst->y;
2095 pa.repeat = RepeatNone;
2096 wine_tsx11_lock();
2097 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2098 if (clip_data)
2099 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2100 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2101 wine_tsx11_unlock();
2102 HeapFree( GetProcessHeap(), 0, clip_data );
2104 else
2106 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2107 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2108 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2111 if (!use_repeat)
2113 xscale = src->width / (double)dst->width;
2114 yscale = src->height / (double)dst->height;
2116 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2118 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
2119 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
2121 if (drawable)
2123 wine_tsx11_lock();
2124 pXRenderFreePicture( gdi_display, dst_pict );
2125 wine_tsx11_unlock();
2130 /***********************************************************************
2131 * xrenderdrv_StretchBlt
2133 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2134 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2136 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2137 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2138 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2140 if (src_dev->funcs != dst_dev->funcs)
2142 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2143 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2146 /* XRender is of no use for color -> mono */
2147 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2148 goto x11drv_fallback;
2150 /* if not stretching, we only need to handle format conversion */
2151 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2153 if (rop != SRCCOPY)
2155 GC tmpGC;
2156 Pixmap tmp_pixmap;
2157 struct bitblt_coords tmp;
2159 /* make coordinates relative to tmp pixmap */
2160 tmp = *dst;
2161 tmp.x -= tmp.visrect.left;
2162 tmp.y -= tmp.visrect.top;
2163 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2165 wine_tsx11_lock();
2166 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2167 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2168 XSetGraphicsExposures( gdi_display, tmpGC, False );
2169 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2170 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
2171 wine_tsx11_unlock();
2173 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2174 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2176 wine_tsx11_lock();
2177 XFreePixmap( gdi_display, tmp_pixmap );
2178 XFreeGC( gdi_display, tmpGC );
2179 wine_tsx11_unlock();
2181 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2183 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2184 return TRUE;
2186 x11drv_fallback:
2187 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2191 /***********************************************************************
2192 * xrenderdrv_PutImage
2194 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2195 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2196 struct bitblt_coords *dst, DWORD rop )
2198 struct xrender_physdev *physdev;
2199 X_PHYSBITMAP *bitmap;
2200 DWORD ret;
2201 Pixmap tmp_pixmap;
2202 GC gc;
2203 enum wxr_format src_format, dst_format;
2204 XRenderPictFormat *pict_format;
2205 Pixmap src_pixmap;
2206 Picture src_pict, mask_pict = 0;
2207 BOOL use_repeat;
2209 if (hbitmap)
2211 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2212 physdev = NULL;
2213 dst_format = bitmap->format;
2215 else
2217 physdev = get_xrender_dev( dev );
2218 bitmap = NULL;
2219 dst_format = physdev->format;
2222 src_format = get_xrender_format_from_bitmapinfo( info );
2223 if (!(pict_format = pict_formats[src_format])) goto update_format;
2225 /* make sure we can create an image with the same bpp */
2226 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2227 goto update_format;
2229 /* mono <-> color conversions not supported */
2230 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2231 goto x11drv_fallback;
2233 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2235 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2237 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2238 if (!ret)
2240 struct bitblt_coords tmp;
2242 if (bitmap)
2244 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2245 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2247 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2248 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2249 DeleteObject( rgn );
2251 else
2253 if (rop != SRCCOPY)
2255 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2257 /* make coordinates relative to tmp pixmap */
2258 tmp = *dst;
2259 tmp.x -= tmp.visrect.left;
2260 tmp.y -= tmp.visrect.top;
2261 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2263 wine_tsx11_lock();
2264 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2265 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2266 XSetGraphicsExposures( gdi_display, gc, False );
2267 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2268 tmp.visrect.right - tmp.visrect.left,
2269 tmp.visrect.bottom - tmp.visrect.top,
2270 physdev->pict_format->depth );
2271 wine_tsx11_unlock();
2273 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2274 NULL, tmp_pixmap, src, &tmp, use_repeat );
2275 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2277 wine_tsx11_lock();
2278 XFreePixmap( gdi_display, tmp_pixmap );
2279 XFreeGC( gdi_display, gc );
2280 wine_tsx11_unlock();
2282 if (restore_region) restore_clipping_region( physdev->x11dev );
2284 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2285 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2287 add_device_bounds( physdev->x11dev, &dst->visrect );
2290 wine_tsx11_lock();
2291 pXRenderFreePicture( gdi_display, src_pict );
2292 XFreePixmap( gdi_display, src_pixmap );
2293 wine_tsx11_unlock();
2295 return ret;
2297 update_format:
2298 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2299 set_color_info( pict_formats[dst_format], info );
2300 return ERROR_BAD_FORMAT;
2302 x11drv_fallback:
2303 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2304 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2305 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2309 /***********************************************************************
2310 * xrenderdrv_BlendImage
2312 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2313 struct bitblt_coords *src, struct bitblt_coords *dst,
2314 BLENDFUNCTION func )
2316 struct xrender_physdev *physdev = get_xrender_dev( dev );
2317 DWORD ret;
2318 enum wxr_format format;
2319 XRenderPictFormat *pict_format;
2320 Picture dst_pict, src_pict, mask_pict;
2321 Pixmap src_pixmap;
2322 BOOL use_repeat;
2324 format = get_xrender_format_from_bitmapinfo( info );
2325 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2326 format = get_format_without_alpha( format );
2327 else if (format != WXR_FORMAT_A8R8G8B8)
2328 return ERROR_INVALID_PARAMETER;
2330 if (!(pict_format = pict_formats[format])) goto update_format;
2332 /* make sure we can create an image with the same bpp */
2333 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2334 goto update_format;
2336 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2337 goto update_format;
2339 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2341 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2342 if (!ret)
2344 double xscale, yscale;
2346 if (!use_repeat)
2348 xscale = src->width / (double)dst->width;
2349 yscale = src->height / (double)dst->height;
2351 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2353 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2355 EnterCriticalSection( &xrender_cs );
2356 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2358 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2359 src->x, src->y, src->width, src->height,
2360 physdev->x11dev->dc_rect.left + dst->x,
2361 physdev->x11dev->dc_rect.top + dst->y,
2362 dst->width, dst->height, xscale, yscale );
2364 wine_tsx11_lock();
2365 pXRenderFreePicture( gdi_display, src_pict );
2366 XFreePixmap( gdi_display, src_pixmap );
2367 wine_tsx11_unlock();
2369 LeaveCriticalSection( &xrender_cs );
2370 add_device_bounds( physdev->x11dev, &dst->visrect );
2372 return ret;
2374 update_format:
2375 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2376 set_color_info( physdev->pict_format, info );
2377 return ERROR_BAD_FORMAT;
2381 /***********************************************************************
2382 * xrenderdrv_AlphaBlend
2384 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2385 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2387 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2388 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2389 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2390 XRenderPictureAttributes pa;
2391 Pixmap tmp_pixmap = 0;
2392 double xscale, yscale;
2393 BOOL use_repeat;
2395 if (src_dev->funcs != dst_dev->funcs)
2397 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2398 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2401 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2403 SetLastError( ERROR_INVALID_PARAMETER );
2404 return FALSE;
2407 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2409 use_repeat = use_source_repeat( physdev_src );
2410 if (!use_repeat)
2412 xscale = src->width / (double)dst->width;
2413 yscale = src->height / (double)dst->height;
2415 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2417 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2419 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2421 /* mono -> color blending needs an intermediate color pixmap */
2422 XRenderColor fg, bg;
2423 int width = src->visrect.right - src->visrect.left;
2424 int height = src->visrect.bottom - src->visrect.top;
2426 /* blending doesn't use the destination DC colors */
2427 fg.red = fg.green = fg.blue = 0;
2428 bg.red = bg.green = bg.blue = 0xffff;
2429 fg.alpha = bg.alpha = 0xffff;
2431 wine_tsx11_lock();
2432 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2433 physdev_dst->pict_format->depth );
2434 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2435 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2436 CPRepeat, &pa );
2437 wine_tsx11_unlock();
2439 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2440 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
2442 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2444 /* we need a source picture with no alpha */
2445 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2446 if (format != physdev_src->format)
2448 wine_tsx11_lock();
2449 pa.subwindow_mode = IncludeInferiors;
2450 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2451 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2452 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2453 wine_tsx11_unlock();
2457 if (tmp_pict) src_pict = tmp_pict;
2459 EnterCriticalSection( &xrender_cs );
2460 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2462 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2463 physdev_src->x11dev->dc_rect.left + src->x,
2464 physdev_src->x11dev->dc_rect.top + src->y,
2465 src->width, src->height,
2466 physdev_dst->x11dev->dc_rect.left + dst->x,
2467 physdev_dst->x11dev->dc_rect.top + dst->y,
2468 dst->width, dst->height, xscale, yscale );
2470 wine_tsx11_lock();
2471 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2472 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2473 wine_tsx11_unlock();
2475 LeaveCriticalSection( &xrender_cs );
2476 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2477 return TRUE;
2480 /***********************************************************************
2481 * xrenderdrv_GradientFill
2483 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2484 void * grad_array, ULONG ngrad, ULONG mode )
2486 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2487 static const XFixed stops[2] = { 0, 1 << 16 };
2488 struct xrender_physdev *physdev = get_xrender_dev( dev );
2489 XLinearGradient gradient;
2490 XRenderColor colors[2];
2491 Picture src_pict, dst_pict;
2492 unsigned int i;
2493 const GRADIENT_RECT *rect = grad_array;
2494 RECT rc;
2495 POINT pt[2];
2497 if (!pXRenderCreateLinearGradient) goto fallback;
2499 /* <= 16-bpp uses dithering */
2500 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2502 switch (mode)
2504 case GRADIENT_FILL_RECT_H:
2505 case GRADIENT_FILL_RECT_V:
2506 for (i = 0; i < ngrad; i++, rect++)
2508 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2509 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2511 colors[0].red = v1->Red * 257 / 256;
2512 colors[0].green = v1->Green * 257 / 256;
2513 colors[0].blue = v1->Blue * 257 / 256;
2514 colors[1].red = v2->Red * 257 / 256;
2515 colors[1].green = v2->Green * 257 / 256;
2516 colors[1].blue = v2->Blue * 257 / 256;
2517 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2518 colors[0].alpha = colors[1].alpha = 65535;
2520 pt[0].x = v1->x;
2521 pt[0].y = v1->y;
2522 pt[1].x = v2->x;
2523 pt[1].y = v2->y;
2524 LPtoDP( dev->hdc, pt, 2 );
2525 if (mode == GRADIENT_FILL_RECT_H)
2527 gradient.p1.y = gradient.p2.y = 0;
2528 if (pt[1].x > pt[0].x)
2530 gradient.p1.x = 0;
2531 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2533 else
2535 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2536 gradient.p2.x = 0;
2539 else
2541 gradient.p1.x = gradient.p2.x = 0;
2542 if (pt[1].y > pt[0].y)
2544 gradient.p1.y = 0;
2545 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2547 else
2549 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2550 gradient.p2.y = 0;
2554 rc.left = min( pt[0].x, pt[1].x );
2555 rc.top = min( pt[0].y, pt[1].y );
2556 rc.right = max( pt[0].x, pt[1].x );
2557 rc.bottom = max( pt[0].y, pt[1].y );
2559 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2560 mode, wine_dbgstr_rect( &rc ),
2561 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2562 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2564 dst_pict = get_xrender_picture( physdev, 0, NULL );
2566 wine_tsx11_lock();
2567 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2568 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2569 0, 0, rc.right - rc.left, rc.bottom - rc.top,
2570 physdev->x11dev->dc_rect.left + rc.left,
2571 physdev->x11dev->dc_rect.top + rc.top,
2572 rc.right - rc.left, rc.bottom - rc.top, 1, 1 );
2573 pXRenderFreePicture( gdi_display, src_pict );
2574 wine_tsx11_unlock();
2575 add_device_bounds( physdev->x11dev, &rc );
2577 return TRUE;
2580 fallback:
2581 #endif
2582 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2583 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2586 /***********************************************************************
2587 * xrenderdrv_SelectBrush
2589 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2591 struct xrender_physdev *physdev = get_xrender_dev( dev );
2592 X_PHYSBITMAP *physbitmap;
2593 BOOL delete_bitmap = FALSE;
2594 BITMAP bm;
2595 HBITMAP bitmap;
2596 Pixmap pixmap;
2597 XRenderPictFormat *pict_format;
2598 Picture src_pict, dst_pict;
2599 XRenderPictureAttributes pa;
2601 if (!pattern) goto x11drv_fallback;
2602 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2604 bitmap = pattern->bitmap;
2605 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2607 if (!(bitmap = create_brush_bitmap( physdev->x11dev, pattern ))) return 0;
2608 physbitmap = X11DRV_get_phys_bitmap( bitmap );
2609 delete_bitmap = TRUE;
2612 if (physbitmap->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2613 if (!(pict_format = pict_formats[physbitmap->format])) goto x11drv_fallback;
2615 GetObjectW( bitmap, sizeof(bm), &bm );
2617 wine_tsx11_lock();
2618 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2619 physdev->pict_format->depth );
2621 pa.repeat = RepeatNone;
2622 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_format, CPRepeat, &pa);
2623 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2625 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, bm.bmWidth, bm.bmHeight,
2626 0, 0, bm.bmWidth, bm.bmHeight, 1.0, 1.0 );
2627 pXRenderFreePicture( gdi_display, src_pict );
2628 pXRenderFreePicture( gdi_display, dst_pict );
2630 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2631 physdev->x11dev->brush.pixmap = pixmap;
2632 physdev->x11dev->brush.fillStyle = FillTiled;
2633 physdev->x11dev->brush.pixel = 0; /* ignored */
2634 physdev->x11dev->brush.style = BS_PATTERN;
2635 wine_tsx11_unlock();
2637 if (delete_bitmap) DeleteObject( bitmap );
2638 return hbrush;
2640 x11drv_fallback:
2641 if (delete_bitmap) DeleteObject( bitmap );
2642 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2643 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2647 static const struct gdi_dc_funcs xrender_funcs =
2649 NULL, /* pAbortDoc */
2650 NULL, /* pAbortPath */
2651 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2652 NULL, /* pAngleArc */
2653 NULL, /* pArc */
2654 NULL, /* pArcTo */
2655 NULL, /* pBeginPath */
2656 xrenderdrv_BlendImage, /* pBlendImage */
2657 NULL, /* pChoosePixelFormat */
2658 NULL, /* pChord */
2659 NULL, /* pCloseFigure */
2660 xrenderdrv_CopyBitmap, /* pCopyBitmap */
2661 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2662 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2663 xrenderdrv_CreateDC, /* pCreateDC */
2664 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2665 xrenderdrv_DeleteDC, /* pDeleteDC */
2666 NULL, /* pDeleteObject */
2667 NULL, /* pDescribePixelFormat */
2668 NULL, /* pDeviceCapabilities */
2669 NULL, /* pEllipse */
2670 NULL, /* pEndDoc */
2671 NULL, /* pEndPage */
2672 NULL, /* pEndPath */
2673 NULL, /* pEnumFonts */
2674 NULL, /* pEnumICMProfiles */
2675 NULL, /* pExcludeClipRect */
2676 NULL, /* pExtDeviceMode */
2677 xrenderdrv_ExtEscape, /* pExtEscape */
2678 NULL, /* pExtFloodFill */
2679 NULL, /* pExtSelectClipRgn */
2680 xrenderdrv_ExtTextOut, /* pExtTextOut */
2681 NULL, /* pFillPath */
2682 NULL, /* pFillRgn */
2683 NULL, /* pFlattenPath */
2684 NULL, /* pFontIsLinked */
2685 NULL, /* pFrameRgn */
2686 NULL, /* pGdiComment */
2687 NULL, /* pGdiRealizationInfo */
2688 NULL, /* pGetBoundsRect */
2689 NULL, /* pGetCharABCWidths */
2690 NULL, /* pGetCharABCWidthsI */
2691 NULL, /* pGetCharWidth */
2692 NULL, /* pGetDeviceCaps */
2693 NULL, /* pGetDeviceGammaRamp */
2694 NULL, /* pGetFontData */
2695 NULL, /* pGetFontUnicodeRanges */
2696 NULL, /* pGetGlyphIndices */
2697 NULL, /* pGetGlyphOutline */
2698 NULL, /* pGetICMProfile */
2699 xrenderdrv_GetImage, /* pGetImage */
2700 NULL, /* pGetKerningPairs */
2701 NULL, /* pGetNearestColor */
2702 NULL, /* pGetOutlineTextMetrics */
2703 NULL, /* pGetPixel */
2704 NULL, /* pGetPixelFormat */
2705 NULL, /* pGetSystemPaletteEntries */
2706 NULL, /* pGetTextCharsetInfo */
2707 NULL, /* pGetTextExtentExPoint */
2708 NULL, /* pGetTextExtentExPointI */
2709 NULL, /* pGetTextFace */
2710 NULL, /* pGetTextMetrics */
2711 xrenderdrv_GradientFill, /* pGradientFill */
2712 NULL, /* pIntersectClipRect */
2713 NULL, /* pInvertRgn */
2714 NULL, /* pLineTo */
2715 NULL, /* pModifyWorldTransform */
2716 NULL, /* pMoveTo */
2717 NULL, /* pOffsetClipRgn */
2718 NULL, /* pOffsetViewportOrg */
2719 NULL, /* pOffsetWindowOrg */
2720 NULL, /* pPaintRgn */
2721 NULL, /* pPatBlt */
2722 NULL, /* pPie */
2723 NULL, /* pPolyBezier */
2724 NULL, /* pPolyBezierTo */
2725 NULL, /* pPolyDraw */
2726 NULL, /* pPolyPolygon */
2727 NULL, /* pPolyPolyline */
2728 NULL, /* pPolygon */
2729 NULL, /* pPolyline */
2730 NULL, /* pPolylineTo */
2731 xrenderdrv_PutImage, /* pPutImage */
2732 NULL, /* pRealizeDefaultPalette */
2733 NULL, /* pRealizePalette */
2734 NULL, /* pRectangle */
2735 NULL, /* pResetDC */
2736 NULL, /* pRestoreDC */
2737 NULL, /* pRoundRect */
2738 NULL, /* pSaveDC */
2739 NULL, /* pScaleViewportExt */
2740 NULL, /* pScaleWindowExt */
2741 xrenderdrv_SelectBitmap, /* pSelectBitmap */
2742 xrenderdrv_SelectBrush, /* pSelectBrush */
2743 NULL, /* pSelectClipPath */
2744 xrenderdrv_SelectFont, /* pSelectFont */
2745 NULL, /* pSelectPalette */
2746 NULL, /* pSelectPen */
2747 NULL, /* pSetArcDirection */
2748 NULL, /* pSetBkColor */
2749 NULL, /* pSetBkMode */
2750 NULL, /* pSetDCBrushColor */
2751 NULL, /* pSetDCPenColor */
2752 NULL, /* pSetDIBitsToDevice */
2753 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2754 NULL, /* pSetDeviceGammaRamp */
2755 NULL, /* pSetLayout */
2756 NULL, /* pSetMapMode */
2757 NULL, /* pSetMapperFlags */
2758 NULL, /* pSetPixel */
2759 NULL, /* pSetPixelFormat */
2760 NULL, /* pSetPolyFillMode */
2761 NULL, /* pSetROP2 */
2762 NULL, /* pSetRelAbs */
2763 NULL, /* pSetStretchBltMode */
2764 NULL, /* pSetTextAlign */
2765 NULL, /* pSetTextCharacterExtra */
2766 NULL, /* pSetTextColor */
2767 NULL, /* pSetTextJustification */
2768 NULL, /* pSetViewportExt */
2769 NULL, /* pSetViewportOrg */
2770 NULL, /* pSetWindowExt */
2771 NULL, /* pSetWindowOrg */
2772 NULL, /* pSetWorldTransform */
2773 NULL, /* pStartDoc */
2774 NULL, /* pStartPage */
2775 xrenderdrv_StretchBlt, /* pStretchBlt */
2776 NULL, /* pStretchDIBits */
2777 NULL, /* pStrokeAndFillPath */
2778 NULL, /* pStrokePath */
2779 NULL, /* pSwapBuffers */
2780 NULL, /* pUnrealizePalette */
2781 NULL, /* pWidenPath */
2782 /* OpenGL not supported */
2785 #else /* SONAME_LIBXRENDER */
2787 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2789 TRACE("XRender support not compiled in.\n");
2790 return NULL;
2793 void X11DRV_XRender_Finalize(void)
2797 #endif /* SONAME_LIBXRENDER */