msi/tests: Avoid a TRUE:FALSE conditional expression.
[wine/multimedia.git] / dlls / winex11.drv / xrender.c
blob2ad6f15daf46f0436822f8c299905a6dae845e27
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 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
319 if (!pict_formats[i])
321 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
322 if (visual->class == DirectColor)
324 XVisualInfo info;
325 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
326 screen_depth, TrueColor, &info ))
328 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
329 if (pict_formats[i]) visual = info.visual;
333 if (pict_formats[i]) default_format = i;
335 else
337 unsigned long mask = 0;
338 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
339 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
341 if (pict_formats[i])
343 count++;
344 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
347 return count;
350 /***********************************************************************
351 * X11DRV_XRender_Init
353 * Let's see if our XServer has the extension available
356 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
358 int event_base, i;
360 if (!client_side_with_render) return NULL;
361 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
363 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
364 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
365 LOAD_FUNCPTR(XRenderAddGlyphs);
366 LOAD_FUNCPTR(XRenderChangePicture);
367 LOAD_FUNCPTR(XRenderComposite);
368 LOAD_FUNCPTR(XRenderCompositeText16);
369 LOAD_FUNCPTR(XRenderCreateGlyphSet);
370 LOAD_FUNCPTR(XRenderCreatePicture);
371 LOAD_FUNCPTR(XRenderFillRectangle);
372 LOAD_FUNCPTR(XRenderFindFormat);
373 LOAD_FUNCPTR(XRenderFindVisualFormat);
374 LOAD_FUNCPTR(XRenderFreeGlyphSet);
375 LOAD_FUNCPTR(XRenderFreePicture);
376 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
377 LOAD_FUNCPTR(XRenderQueryExtension);
378 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
379 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
380 #endif
381 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
382 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
383 #endif
384 #undef LOAD_OPTIONAL_FUNCPTR
385 #undef LOAD_FUNCPTR
387 if (!pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) return NULL;
389 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
390 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
392 ERR_(winediag)("Wine has detected that you probably have a buggy version "
393 "of libXrender. Because of this client side font rendering "
394 "will be disabled. Please upgrade this library.\n");
395 return NULL;
398 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask)
400 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
401 return NULL;
404 #ifdef SONAME_LIBFONTCONFIG
405 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
407 #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;}
408 LOAD_FUNCPTR(FcConfigSubstitute);
409 LOAD_FUNCPTR(FcDefaultSubstitute);
410 LOAD_FUNCPTR(FcFontMatch);
411 LOAD_FUNCPTR(FcInit);
412 LOAD_FUNCPTR(FcPatternCreate);
413 LOAD_FUNCPTR(FcPatternDestroy);
414 LOAD_FUNCPTR(FcPatternAddInteger);
415 LOAD_FUNCPTR(FcPatternAddString);
416 LOAD_FUNCPTR(FcPatternGetBool);
417 LOAD_FUNCPTR(FcPatternGetInteger);
418 LOAD_FUNCPTR(FcPatternGetString);
419 #undef LOAD_FUNCPTR
420 fontconfig_installed = pFcInit();
422 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
424 sym_not_found:
425 #endif
427 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
428 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
430 glyphsetCacheSize = INIT_CACHE_SIZE;
431 lastfree = 0;
432 for(i = 0; i < INIT_CACHE_SIZE; i++) {
433 glyphsetCache[i].next = i + 1;
434 glyphsetCache[i].count = -1;
436 glyphsetCache[i-1].next = -1;
438 if(screen_depth <= 8 || !client_side_antialias_with_render) antialias = 0;
440 return &xrender_funcs;
443 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
444 static void get_xrender_color( struct xrender_physdev *physdev, COLORREF src_color, XRenderColor *dst_color )
446 if (src_color & (1 << 24)) /* PALETTEINDEX */
448 HPALETTE pal = GetCurrentObject( physdev->dev.hdc, OBJ_PAL );
449 PALETTEENTRY pal_ent;
451 if (!GetPaletteEntries( pal, LOWORD(src_color), 1, &pal_ent ))
452 GetPaletteEntries( pal, 0, 1, &pal_ent );
453 dst_color->red = pal_ent.peRed * 257;
454 dst_color->green = pal_ent.peGreen * 257;
455 dst_color->blue = pal_ent.peBlue * 257;
457 else
459 if (src_color >> 16 == 0x10ff) src_color = 0; /* DIBINDEX */
461 dst_color->red = GetRValue( src_color ) * 257;
462 dst_color->green = GetGValue( src_color ) * 257;
463 dst_color->blue = GetBValue( src_color ) * 257;
466 if (physdev->format == WXR_FORMAT_MONO && !dst_color->red && !dst_color->green && !dst_color->blue)
467 dst_color->alpha = 0;
468 else
469 dst_color->alpha = 0xffff;
472 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
474 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
476 switch (info->bmiHeader.biBitCount)
478 case 1:
479 return WXR_FORMAT_MONO;
480 case 4:
481 case 8:
482 break;
483 case 24:
484 if (info->bmiHeader.biCompression != BI_RGB) break;
485 return WXR_FORMAT_R8G8B8;
486 case 16:
487 case 32:
488 if (info->bmiHeader.biCompression == BI_BITFIELDS)
490 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
491 unsigned int i;
493 for (i = 0; i < WXR_NB_FORMATS; i++)
495 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
496 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
497 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
498 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
499 return i;
501 break;
503 if (info->bmiHeader.biCompression != BI_RGB) break;
504 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
506 return WXR_INVALID_FORMAT;
509 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
510 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
512 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
513 XTransform xform = {{
514 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
515 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
516 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
519 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
520 #endif
523 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
525 XRenderPictureAttributes pa;
526 RGNDATA *data;
528 if (!rgn)
530 pa.clip_mask = None;
531 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
533 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
535 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
536 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
537 (XRectangle *)data->Buffer, data->rdh.nCount );
538 HeapFree( GetProcessHeap(), 0, data );
543 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
545 if (!dev->pict && dev->pict_format)
547 XRenderPictureAttributes pa;
549 pa.subwindow_mode = IncludeInferiors;
550 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
551 dev->pict_format, CPSubwindowMode, &pa );
552 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
553 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
554 dev->update_clip = (dev->region != 0);
557 if (clip_rect)
559 HRGN rgn = CreateRectRgnIndirect( clip_rect );
560 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
561 if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
562 update_xrender_clipping( dev, rgn );
563 DeleteObject( rgn );
565 else if (clip_rgn)
567 if (dev->region)
569 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
570 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
571 update_xrender_clipping( dev, rgn );
572 DeleteObject( rgn );
574 else update_xrender_clipping( dev, clip_rgn );
576 else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
578 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
579 return dev->pict;
582 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
584 if (!dev->pict_src && dev->pict_format)
586 XRenderPictureAttributes pa;
588 pa.subwindow_mode = IncludeInferiors;
589 pa.repeat = repeat ? RepeatNormal : RepeatNone;
590 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
591 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
593 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
594 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
597 return dev->pict_src;
600 static void free_xrender_picture( struct xrender_physdev *dev )
602 if (dev->pict || dev->pict_src)
604 XFlush( gdi_display );
605 if (dev->pict)
607 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
608 pXRenderFreePicture(gdi_display, dev->pict);
609 dev->pict = 0;
611 if(dev->pict_src)
613 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
614 pXRenderFreePicture(gdi_display, dev->pict_src);
615 dev->pict_src = 0;
620 /* return a mask picture used to force alpha to 0 */
621 static Picture get_no_alpha_mask(void)
623 static Pixmap pixmap;
624 static Picture pict;
626 EnterCriticalSection( &xrender_cs );
627 if (!pict)
629 XRenderPictureAttributes pa;
630 XRenderColor col;
632 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
633 pa.repeat = RepeatNormal;
634 pa.component_alpha = True;
635 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
636 CPRepeat|CPComponentAlpha, &pa );
637 col.red = col.green = col.blue = 0xffff;
638 col.alpha = 0;
639 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
641 LeaveCriticalSection( &xrender_cs );
642 return pict;
645 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
647 if(p1->hash != p2->hash) return TRUE;
648 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
649 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
650 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
651 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
654 #if 0
655 static void walk_cache(void)
657 int i;
659 EnterCriticalSection(&xrender_cs);
660 for(i=mru; i >= 0; i = glyphsetCache[i].next)
661 TRACE("item %d\n", i);
662 LeaveCriticalSection(&xrender_cs);
664 #endif
666 static int LookupEntry(LFANDSIZE *plfsz)
668 int i, prev_i = -1;
670 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
671 TRACE("%d\n", i);
672 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
674 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
675 glyphsetCache[i].count++;
676 if(prev_i >= 0) {
677 glyphsetCache[prev_i].next = glyphsetCache[i].next;
678 glyphsetCache[i].next = mru;
679 mru = i;
681 TRACE("found font in cache %d\n", i);
682 return i;
684 prev_i = i;
686 TRACE("font not in cache\n");
687 return -1;
690 static void FreeEntry(int entry)
692 int format;
694 for(format = 0; format < AA_MAXVALUE; format++) {
695 gsCacheEntryFormat * formatEntry;
697 if( !glyphsetCache[entry].format[format] )
698 continue;
700 formatEntry = glyphsetCache[entry].format[format];
702 if(formatEntry->glyphset) {
703 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
704 formatEntry->glyphset = 0;
706 if(formatEntry->nrealized) {
707 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
708 formatEntry->realized = NULL;
709 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
710 formatEntry->gis = NULL;
711 formatEntry->nrealized = 0;
714 HeapFree(GetProcessHeap(), 0, formatEntry);
715 glyphsetCache[entry].format[format] = NULL;
719 static int AllocEntry(void)
721 int best = -1, prev_best = -1, i, prev_i = -1;
723 if(lastfree >= 0) {
724 assert(glyphsetCache[lastfree].count == -1);
725 glyphsetCache[lastfree].count = 1;
726 best = lastfree;
727 lastfree = glyphsetCache[lastfree].next;
728 assert(best != mru);
729 glyphsetCache[best].next = mru;
730 mru = best;
732 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
733 return mru;
736 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
737 if(glyphsetCache[i].count == 0) {
738 best = i;
739 prev_best = prev_i;
741 prev_i = i;
744 if(best >= 0) {
745 TRACE("freeing unused glyphset at cache %d\n", best);
746 FreeEntry(best);
747 glyphsetCache[best].count = 1;
748 if(prev_best >= 0) {
749 glyphsetCache[prev_best].next = glyphsetCache[best].next;
750 glyphsetCache[best].next = mru;
751 mru = best;
752 } else {
753 assert(mru == best);
755 return mru;
758 TRACE("Growing cache\n");
760 if (glyphsetCache)
761 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
762 glyphsetCache,
763 (glyphsetCacheSize + INIT_CACHE_SIZE)
764 * sizeof(*glyphsetCache));
765 else
766 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
767 (glyphsetCacheSize + INIT_CACHE_SIZE)
768 * sizeof(*glyphsetCache));
770 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
771 i++) {
772 glyphsetCache[i].next = i + 1;
773 glyphsetCache[i].count = -1;
775 glyphsetCache[i-1].next = -1;
776 glyphsetCacheSize += INIT_CACHE_SIZE;
778 lastfree = glyphsetCache[best].next;
779 glyphsetCache[best].count = 1;
780 glyphsetCache[best].next = mru;
781 mru = best;
782 TRACE("new free cache slot at %d\n", mru);
783 return mru;
786 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
788 DWORD size;
789 WORD *gasp, *buffer;
790 WORD num_recs;
791 DWORD ppem;
792 TEXTMETRICW tm;
794 *flags = 0;
796 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
797 if(size == GDI_ERROR)
798 return FALSE;
800 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
801 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
803 GetTextMetricsW(hdc, &tm);
804 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
806 gasp++;
807 num_recs = get_be_word(*gasp);
808 gasp++;
809 while(num_recs--)
811 *flags = get_be_word(*(gasp + 1));
812 if(ppem <= get_be_word(*gasp))
813 break;
814 gasp += 2;
816 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
818 HeapFree(GetProcessHeap(), 0, buffer);
819 return TRUE;
822 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
824 AA_Type ret;
825 WORD flags;
826 UINT font_smoothing_type, font_smoothing_orientation;
828 if (subpixel &&
829 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
830 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
832 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
833 &font_smoothing_orientation, 0) &&
834 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
836 ret = AA_BGR;
838 else
839 ret = AA_RGB;
840 /*FIXME
841 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
842 But, Wine's subpixel rendering can support the portrait mode.
845 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
846 ret = AA_Grey;
847 else
848 ret = AA_None;
850 return ret;
853 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
855 int ret;
856 int format;
857 gsCacheEntry *entry;
858 static int hinter = -1;
859 static int subpixel = -1;
860 BOOL font_smoothing;
862 if((ret = LookupEntry(plfsz)) != -1) return ret;
864 ret = AllocEntry();
865 entry = glyphsetCache + ret;
866 entry->lfsz = *plfsz;
867 for( format = 0; format < AA_MAXVALUE; format++ ) {
868 assert( !entry->format[format] );
871 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
873 if(hinter == -1 || subpixel == -1)
875 RASTERIZER_STATUS status;
876 GetRasterizerCaps(&status, sizeof(status));
877 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
878 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
881 switch (plfsz->lf.lfQuality)
883 case ANTIALIASED_QUALITY:
884 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
885 return ret; /* ignore further configuration */
886 case CLEARTYPE_QUALITY:
887 case CLEARTYPE_NATURAL_QUALITY:
888 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
889 break;
890 case DEFAULT_QUALITY:
891 case DRAFT_QUALITY:
892 case PROOF_QUALITY:
893 default:
894 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
895 font_smoothing)
897 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
899 else
900 entry->aa_default = AA_None;
901 break;
904 font_smoothing = TRUE; /* default to enabled */
905 #ifdef SONAME_LIBFONTCONFIG
906 if (fontconfig_installed)
908 FcPattern *match, *pattern;
909 FcResult result;
910 char family[LF_FACESIZE * 4];
912 #if defined(__i386__) && defined(__GNUC__)
913 /* fontconfig generates floating point exceptions, mask them */
914 WORD cw, default_cw = 0x37f;
915 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
916 #endif
918 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
919 pattern = pFcPatternCreate();
920 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
921 if (plfsz->lf.lfWeight != FW_DONTCARE)
923 int weight;
924 switch (plfsz->lf.lfWeight)
926 case FW_THIN: weight = FC_WEIGHT_THIN; break;
927 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
928 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
929 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
930 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
931 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
932 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
933 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
934 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
935 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
937 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
939 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
940 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
941 pFcDefaultSubstitute( pattern );
942 if ((match = pFcFontMatch( NULL, pattern, &result )))
944 int rgba;
945 FcBool antialias;
947 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
948 antialias = TRUE;
949 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
951 FcChar8 *file;
952 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
954 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
955 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
957 switch (rgba)
959 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
960 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
961 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
962 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
963 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
966 if (!antialias) font_smoothing = FALSE;
967 pFcPatternDestroy( match );
969 pFcPatternDestroy( pattern );
971 #if defined(__i386__) && defined(__GNUC__)
972 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
973 #endif
975 #endif /* SONAME_LIBFONTCONFIG */
977 /* now check Xft resources */
979 char *value;
980 BOOL antialias = TRUE;
982 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
984 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
985 value[0] == '0' || !strcasecmp( value, "off" ))
986 antialias = FALSE;
988 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
990 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
991 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
992 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
993 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
994 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
995 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
997 if (!antialias) font_smoothing = FALSE;
1000 if (!font_smoothing) entry->aa_default = AA_None;
1002 else
1003 entry->aa_default = AA_None;
1005 return ret;
1008 static void dec_ref_cache(int index)
1010 assert(index >= 0);
1011 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1012 assert(glyphsetCache[index].count > 0);
1013 glyphsetCache[index].count--;
1016 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1018 DWORD hash = 0, *ptr, two_chars;
1019 WORD *pwc;
1020 int i;
1022 hash ^= plfsz->devsize.cx;
1023 hash ^= plfsz->devsize.cy;
1024 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1025 hash ^= *ptr;
1026 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1027 hash ^= *ptr;
1028 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1029 two_chars = *ptr;
1030 pwc = (WCHAR *)&two_chars;
1031 if(!*pwc) break;
1032 *pwc = toupperW(*pwc);
1033 pwc++;
1034 *pwc = toupperW(*pwc);
1035 hash ^= two_chars;
1036 if(!*pwc) break;
1038 plfsz->hash = hash;
1039 return;
1042 /***********************************************************************
1043 * X11DRV_XRender_Finalize
1045 void X11DRV_XRender_Finalize(void)
1047 int i;
1049 EnterCriticalSection(&xrender_cs);
1050 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1051 FreeEntry(i);
1052 LeaveCriticalSection(&xrender_cs);
1053 DeleteCriticalSection(&xrender_cs);
1056 /**********************************************************************
1057 * xrenderdrv_SelectFont
1059 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1061 LFANDSIZE lfsz;
1062 struct xrender_physdev *physdev = get_xrender_dev( dev );
1063 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1064 HFONT ret = next->funcs->pSelectFont( next, hfont );
1066 if (!ret) return 0;
1068 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1070 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1071 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1072 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1073 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1074 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1075 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1077 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1078 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1079 lfsz.xform.eM21, lfsz.xform.eM22);
1081 if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE && lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
1082 lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
1084 /* Not used fields, would break hashing */
1085 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1087 lfsz_calc_hash(&lfsz);
1089 EnterCriticalSection(&xrender_cs);
1090 if (physdev->cache_index != -1)
1091 dec_ref_cache( physdev->cache_index );
1092 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1093 LeaveCriticalSection(&xrender_cs);
1094 return ret;
1097 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1099 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1100 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1102 if (!physdev) return FALSE;
1103 physdev->x11dev = x11dev;
1104 physdev->cache_index = -1;
1105 physdev->format = format;
1106 physdev->pict_format = pict_formats[format];
1107 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1108 return TRUE;
1111 /* store the color mask data in the bitmap info structure */
1112 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1114 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1116 info->bmiHeader.biPlanes = 1;
1117 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1118 info->bmiHeader.biCompression = BI_RGB;
1119 info->bmiHeader.biClrUsed = 0;
1121 switch (info->bmiHeader.biBitCount)
1123 case 16:
1124 colors[0] = format->direct.redMask << format->direct.red;
1125 colors[1] = format->direct.greenMask << format->direct.green;
1126 colors[2] = format->direct.blueMask << format->direct.blue;
1127 info->bmiHeader.biCompression = BI_BITFIELDS;
1128 break;
1129 case 32:
1130 colors[0] = format->direct.redMask << format->direct.red;
1131 colors[1] = format->direct.greenMask << format->direct.green;
1132 colors[2] = format->direct.blueMask << format->direct.blue;
1133 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1134 info->bmiHeader.biCompression = BI_BITFIELDS;
1135 break;
1140 /**********************************************************************
1141 * xrenderdrv_CreateDC
1143 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1144 LPCWSTR output, const DEVMODEW* initData )
1146 return create_xrender_dc( pdev, default_format );
1149 /**********************************************************************
1150 * xrenderdrv_CreateCompatibleDC
1152 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1154 if (orig) /* chain to x11drv first */
1156 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1157 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1159 /* otherwise we have been called by x11drv */
1161 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1164 /**********************************************************************
1165 * xrenderdrv_DeleteDC
1167 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1169 struct xrender_physdev *physdev = get_xrender_dev( dev );
1171 free_xrender_picture( physdev );
1173 EnterCriticalSection( &xrender_cs );
1174 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1175 LeaveCriticalSection( &xrender_cs );
1177 HeapFree( GetProcessHeap(), 0, physdev );
1178 return TRUE;
1181 /**********************************************************************
1182 * xrenderdrv_ExtEscape
1184 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1185 INT out_count, LPVOID out_data )
1187 struct xrender_physdev *physdev = get_xrender_dev( dev );
1189 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1191 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1193 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1195 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1196 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1197 return ret;
1200 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1203 /***********************************************************************
1204 * xrenderdrv_SetDeviceClipping
1206 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1208 struct xrender_physdev *physdev = get_xrender_dev( dev );
1210 physdev->region = rgn;
1211 physdev->update_clip = TRUE;
1213 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1214 dev->funcs->pSetDeviceClipping( dev, rgn );
1218 /************************************************************************
1219 * UploadGlyph
1221 * Helper to ExtTextOut. Must be called inside xrender_cs
1223 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1225 unsigned int buflen;
1226 char *buf;
1227 Glyph gid;
1228 GLYPHMETRICS gm;
1229 XGlyphInfo gi;
1230 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1231 gsCacheEntryFormat *formatEntry;
1232 UINT ggo_format = GGO_GLYPH_INDEX;
1233 enum wxr_format wxr_format;
1234 static const char zero[4];
1235 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1237 switch(format) {
1238 case AA_Grey:
1239 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1240 break;
1241 case AA_RGB:
1242 ggo_format |= WINE_GGO_HRGB_BITMAP;
1243 break;
1244 case AA_BGR:
1245 ggo_format |= WINE_GGO_HBGR_BITMAP;
1246 break;
1247 case AA_VRGB:
1248 ggo_format |= WINE_GGO_VRGB_BITMAP;
1249 break;
1250 case AA_VBGR:
1251 ggo_format |= WINE_GGO_VBGR_BITMAP;
1252 break;
1254 default:
1255 ERR("aa = %d - not implemented\n", format);
1256 case AA_None:
1257 ggo_format |= GGO_BITMAP;
1258 break;
1261 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1262 if(buflen == GDI_ERROR) {
1263 if(format != AA_None) {
1264 format = AA_None;
1265 entry->aa_default = AA_None;
1266 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1267 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1269 if(buflen == GDI_ERROR) {
1270 WARN("GetGlyphOutlineW failed using default glyph\n");
1271 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1272 if(buflen == GDI_ERROR) {
1273 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1274 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1275 if(buflen == GDI_ERROR) {
1276 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1277 return;
1281 TRACE("Turning off antialiasing for this monochrome font\n");
1284 /* If there is nothing for the current type, we create the entry. */
1285 if( !entry->format[format] ) {
1286 entry->format[format] = HeapAlloc(GetProcessHeap(),
1287 HEAP_ZERO_MEMORY,
1288 sizeof(gsCacheEntryFormat));
1290 formatEntry = entry->format[format];
1292 if(formatEntry->nrealized <= glyph) {
1293 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1295 if (formatEntry->realized)
1296 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1297 HEAP_ZERO_MEMORY,
1298 formatEntry->realized,
1299 formatEntry->nrealized * sizeof(BOOL));
1300 else
1301 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1302 HEAP_ZERO_MEMORY,
1303 formatEntry->nrealized * sizeof(BOOL));
1305 if (formatEntry->gis)
1306 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1307 HEAP_ZERO_MEMORY,
1308 formatEntry->gis,
1309 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1310 else
1311 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1312 HEAP_ZERO_MEMORY,
1313 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1317 if(formatEntry->glyphset == 0) {
1318 switch(format) {
1319 case AA_Grey:
1320 wxr_format = WXR_FORMAT_GRAY;
1321 break;
1323 case AA_RGB:
1324 case AA_BGR:
1325 case AA_VRGB:
1326 case AA_VBGR:
1327 wxr_format = WXR_FORMAT_A8R8G8B8;
1328 break;
1330 default:
1331 ERR("aa = %d - not implemented\n", format);
1332 case AA_None:
1333 wxr_format = WXR_FORMAT_MONO;
1334 break;
1337 formatEntry->font_format = pict_formats[wxr_format];
1338 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1342 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1343 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1344 formatEntry->realized[glyph] = TRUE;
1346 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1347 buflen,
1348 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1349 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1351 gi.width = gm.gmBlackBoxX;
1352 gi.height = gm.gmBlackBoxY;
1353 gi.x = -gm.gmptGlyphOrigin.x;
1354 gi.y = gm.gmptGlyphOrigin.y;
1355 gi.xOff = gm.gmCellIncX;
1356 gi.yOff = gm.gmCellIncY;
1358 if(TRACE_ON(xrender)) {
1359 int pitch, i, j;
1360 char output[300];
1361 unsigned char *line;
1363 if(format == AA_None) {
1364 pitch = ((gi.width + 31) / 32) * 4;
1365 for(i = 0; i < gi.height; i++) {
1366 line = (unsigned char*) buf + i * pitch;
1367 output[0] = '\0';
1368 for(j = 0; j < pitch * 8; j++) {
1369 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1371 TRACE("%s\n", output);
1373 } else {
1374 static const char blks[] = " .:;!o*#";
1375 char str[2];
1377 str[1] = '\0';
1378 pitch = ((gi.width + 3) / 4) * 4;
1379 for(i = 0; i < gi.height; i++) {
1380 line = (unsigned char*) buf + i * pitch;
1381 output[0] = '\0';
1382 for(j = 0; j < pitch; j++) {
1383 str[0] = blks[line[j] >> 5];
1384 strcat(output, str);
1386 TRACE("%s\n", output);
1392 if(formatEntry->glyphset) {
1393 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1394 unsigned char *byte = (unsigned char*) buf, c;
1395 int i = buflen;
1397 while(i--) {
1398 c = *byte;
1400 /* magic to flip bit order */
1401 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1402 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1403 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1405 *byte++ = c;
1408 else if ( format != AA_Grey &&
1409 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1411 unsigned int i, *data = (unsigned int *)buf;
1412 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1414 gid = glyph;
1417 XRenderCompositeText seems to ignore 0x0 glyphs when
1418 AA_None, which means we lose the advance width of glyphs
1419 like the space. We'll pretend that such glyphs are 1x1
1420 bitmaps.
1423 if(buflen == 0)
1424 gi.width = gi.height = 1;
1426 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1427 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1428 HeapFree(GetProcessHeap(), 0, buf);
1431 formatEntry->gis[glyph] = gi;
1434 /*************************************************************
1435 * get_tile_pict
1437 * Returns an appropriate Picture for tiling the text colour.
1438 * Call and use result within the xrender_cs
1440 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1442 static struct
1444 Pixmap xpm;
1445 Picture pict;
1446 XRenderColor current_color;
1447 } tiles[WXR_NB_FORMATS], *tile;
1449 tile = &tiles[wxr_format];
1451 if(!tile->xpm)
1453 XRenderPictureAttributes pa;
1454 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1456 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1458 pa.repeat = RepeatNormal;
1459 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1461 /* init current_color to something different from text_pixel */
1462 tile->current_color = *color;
1463 tile->current_color.red ^= 0xffff;
1465 if (wxr_format == WXR_FORMAT_MONO)
1467 /* for a 1bpp bitmap we always need a 1 in the tile */
1468 XRenderColor col;
1469 col.red = col.green = col.blue = 0;
1470 col.alpha = 0xffff;
1471 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1475 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1477 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1478 tile->current_color = *color;
1480 return tile->pict;
1483 /*************************************************************
1484 * get_mask_pict
1486 * Returns an appropriate Picture for masking with the specified alpha.
1487 * Call and use result within the xrender_cs
1489 static Picture get_mask_pict( int alpha )
1491 static Pixmap pixmap;
1492 static Picture pict;
1493 static int current_alpha;
1495 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1497 if (!pixmap)
1499 XRenderPictureAttributes pa;
1501 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1502 pa.repeat = RepeatNormal;
1503 pict = pXRenderCreatePicture( gdi_display, pixmap,
1504 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1505 current_alpha = -1;
1508 if (alpha != current_alpha)
1510 XRenderColor col;
1511 col.red = col.green = col.blue = 0;
1512 col.alpha = current_alpha = alpha;
1513 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1515 return pict;
1518 /***********************************************************************
1519 * xrenderdrv_ExtTextOut
1521 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1522 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1524 struct xrender_physdev *physdev = get_xrender_dev( dev );
1525 gsCacheEntry *entry;
1526 gsCacheEntryFormat *formatEntry;
1527 AA_Type aa_type = AA_None;
1528 unsigned int idx;
1529 Picture pict, tile_pict = 0;
1530 XGlyphElt16 *elts;
1531 POINT offset, desired, current;
1532 int render_op = PictOpOver;
1533 XRenderColor col;
1534 RECT rect, bounds;
1536 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1537 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1539 if(flags & ETO_OPAQUE)
1541 XRenderColor bg;
1543 if (physdev->format == WXR_FORMAT_MONO)
1544 /* use the inverse of the text color */
1545 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1546 else
1547 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1549 set_xrender_transformation( pict, 1, 1, 0, 0 );
1550 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1551 physdev->x11dev->dc_rect.left + lprect->left,
1552 physdev->x11dev->dc_rect.top + lprect->top,
1553 lprect->right - lprect->left,
1554 lprect->bottom - lprect->top );
1555 add_device_bounds( physdev->x11dev, lprect );
1558 if(count == 0) return TRUE;
1560 EnterCriticalSection(&xrender_cs);
1562 entry = glyphsetCache + physdev->cache_index;
1563 aa_type = entry->aa_default;
1564 formatEntry = entry->format[aa_type];
1566 for(idx = 0; idx < count; idx++) {
1567 if( !formatEntry ) {
1568 UploadGlyph(physdev, wstr[idx], aa_type);
1569 /* re-evaluate antialias since aa_default may have changed */
1570 aa_type = entry->aa_default;
1571 formatEntry = entry->format[aa_type];
1572 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1573 UploadGlyph(physdev, wstr[idx], aa_type);
1576 if (!formatEntry)
1578 WARN("could not upload requested glyphs\n");
1579 LeaveCriticalSection(&xrender_cs);
1580 return FALSE;
1583 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1584 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1586 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1588 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1589 So we pass zeros to the function and move to our starting position using the first
1590 element of the elts array. */
1592 desired.x = physdev->x11dev->dc_rect.left + x;
1593 desired.y = physdev->x11dev->dc_rect.top + y;
1594 offset.x = offset.y = 0;
1595 current.x = current.y = 0;
1597 tile_pict = get_tile_pict(physdev->format, &col);
1599 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1601 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1602 render_op = PictOpOutReverse; /* This gives us 'black' text */
1604 reset_bounds( &bounds );
1605 for(idx = 0; idx < count; idx++)
1607 elts[idx].glyphset = formatEntry->glyphset;
1608 elts[idx].chars = wstr + idx;
1609 elts[idx].nchars = 1;
1610 elts[idx].xOff = desired.x - current.x;
1611 elts[idx].yOff = desired.y - current.y;
1613 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1614 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1616 rect.left = desired.x - physdev->x11dev->dc_rect.left - formatEntry->gis[wstr[idx]].x;
1617 rect.top = desired.y - physdev->x11dev->dc_rect.top - formatEntry->gis[wstr[idx]].y;
1618 rect.right = rect.left + formatEntry->gis[wstr[idx]].width;
1619 rect.bottom = rect.top + formatEntry->gis[wstr[idx]].height;
1620 add_bounds_rect( &bounds, &rect );
1622 if(!lpDx)
1624 desired.x += formatEntry->gis[wstr[idx]].xOff;
1625 desired.y += formatEntry->gis[wstr[idx]].yOff;
1627 else
1629 if(flags & ETO_PDY)
1631 offset.x += lpDx[idx * 2];
1632 offset.y += lpDx[idx * 2 + 1];
1634 else
1635 offset.x += lpDx[idx];
1636 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1637 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1641 /* Make sure we don't have any transforms set from a previous call */
1642 set_xrender_transformation(pict, 1, 1, 0, 0);
1643 pXRenderCompositeText16(gdi_display, render_op,
1644 tile_pict,
1645 pict,
1646 formatEntry->font_format,
1647 0, 0, 0, 0, elts, count);
1648 HeapFree(GetProcessHeap(), 0, elts);
1650 LeaveCriticalSection(&xrender_cs);
1651 add_device_bounds( physdev->x11dev, &bounds );
1652 return TRUE;
1655 /* multiply the alpha channel of a picture */
1656 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1657 int x, int y, int width, int height )
1659 XRenderPictureAttributes pa;
1660 Pixmap src_pixmap, mask_pixmap;
1661 Picture src_pict, mask_pict;
1662 XRenderColor color;
1664 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1665 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1666 pa.repeat = RepeatNormal;
1667 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1668 pa.component_alpha = True;
1669 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1670 color.red = color.green = color.blue = color.alpha = 0xffff;
1671 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1672 color.alpha = alpha;
1673 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1674 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1675 0, 0, 0, 0, x, y, width, height );
1676 pXRenderFreePicture( gdi_display, src_pict );
1677 pXRenderFreePicture( gdi_display, mask_pict );
1678 XFreePixmap( gdi_display, src_pixmap );
1679 XFreePixmap( gdi_display, mask_pixmap );
1682 /* Helper function for (stretched) blitting using xrender */
1683 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1684 int x_src, int y_src, int width_src, int height_src,
1685 int x_dst, int y_dst, int width_dst, int height_dst,
1686 double xscale, double yscale )
1688 int x_offset, y_offset;
1690 if (width_src < 0)
1692 x_src += width_src + 1;
1693 width_src = -width_src;
1695 if (height_src < 0)
1697 y_src += height_src + 1;
1698 height_src = -height_src;
1700 if (width_dst < 0)
1702 x_dst += width_dst + 1;
1703 width_dst = -width_dst;
1705 if (height_dst < 0)
1707 y_dst += height_dst + 1;
1708 height_dst = -height_dst;
1711 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1712 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1713 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1714 if(xscale != 1.0 || yscale != 1.0)
1716 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1717 * in the wrong quadrant of the x-y plane.
1719 x_offset = (xscale < 0) ? -width_dst : 0;
1720 y_offset = (yscale < 0) ? -height_dst : 0;
1721 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1723 else
1725 x_offset = x_src;
1726 y_offset = y_src;
1727 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1729 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1730 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1733 /* Helper function for (stretched) mono->color blitting using xrender */
1734 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1735 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1736 int x_src, int y_src, int width_src, int height_src,
1737 int x_dst, int y_dst, int width_dst, int height_dst,
1738 double xscale, double yscale )
1740 Picture tile_pict;
1741 int x_offset, y_offset;
1742 XRenderColor color;
1744 if (width_src < 0)
1746 x_src += width_src + 1;
1747 width_src = -width_src;
1749 if (height_src < 0)
1751 y_src += height_src + 1;
1752 height_src = -height_src;
1754 if (width_dst < 0)
1756 x_dst += width_dst + 1;
1757 width_dst = -width_dst;
1759 if (height_dst < 0)
1761 y_dst += height_dst + 1;
1762 height_dst = -height_dst;
1765 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1766 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1767 * the tile data.
1769 EnterCriticalSection( &xrender_cs );
1770 color = *bg;
1771 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1772 tile_pict = get_tile_pict( dst_format, &color );
1774 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1776 if (xscale != 1.0 || yscale != 1.0)
1778 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1779 * in the wrong quadrant of the x-y plane.
1781 x_offset = (xscale < 0) ? -width_dst : 0;
1782 y_offset = (yscale < 0) ? -height_dst : 0;
1783 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1785 else
1787 x_offset = x_src;
1788 y_offset = y_src;
1789 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1791 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1792 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1793 LeaveCriticalSection( &xrender_cs );
1795 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1796 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1797 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1798 x_dst, y_dst, width_dst, height_dst );
1801 /* create a pixmap and render picture for an image */
1802 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1803 struct bitblt_coords *src, enum wxr_format format,
1804 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1806 DWORD ret;
1807 int width = src->visrect.right - src->visrect.left;
1808 int height = src->visrect.bottom - src->visrect.top;
1809 int depth = pict_formats[format]->depth;
1810 struct gdi_image_bits dst_bits;
1811 XRenderPictureAttributes pa;
1812 GC gc;
1813 XImage *image;
1815 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1816 info->bmiHeader.biWidth, height, 32, 0 );
1817 if (!image) return ERROR_OUTOFMEMORY;
1819 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1820 if (ret) return ret;
1822 image->data = dst_bits.ptr;
1824 *use_repeat = (width == 1 && height == 1);
1825 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1827 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1828 gc = XCreateGC( gdi_display, *pixmap, 0, NULL );
1829 XPutImage( gdi_display, *pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1830 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1831 XFreeGC( gdi_display, gc );
1833 /* make coordinates relative to the pixmap */
1834 src->x -= src->visrect.left;
1835 src->y -= src->visrect.top;
1836 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1838 image->data = NULL;
1839 XDestroyImage( image );
1840 if (dst_bits.free) dst_bits.free( &dst_bits );
1841 return ret;
1844 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1845 Drawable drawable, const struct bitblt_coords *src,
1846 const struct bitblt_coords *dst )
1848 int x_dst, y_dst;
1849 Picture src_pict = 0, dst_pict, mask_pict = 0;
1850 double xscale = src->width / (double)dst->width;
1851 double yscale = src->height / (double)dst->height;
1853 if (drawable) /* using an intermediate pixmap */
1855 x_dst = dst->x;
1856 y_dst = dst->y;
1857 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, 0, NULL );
1859 else
1861 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
1862 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
1863 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1866 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1868 /* mono -> color */
1869 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1871 XRenderColor fg, bg;
1873 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
1874 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
1875 fg.alpha = bg.alpha = 0;
1877 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
1878 physdev_src->x11dev->dc_rect.left + src->x,
1879 physdev_src->x11dev->dc_rect.top + src->y,
1880 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1882 else /* color -> color (can be at different depths) or mono -> mono */
1884 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
1885 mask_pict = get_no_alpha_mask();
1887 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
1888 physdev_src->x11dev->dc_rect.left + src->x,
1889 physdev_src->x11dev->dc_rect.top + src->y,
1890 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1893 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1897 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
1898 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
1899 Drawable drawable, struct bitblt_coords *src,
1900 struct bitblt_coords *dst, BOOL use_repeat )
1902 int x_dst, y_dst;
1903 Picture dst_pict;
1904 double xscale, yscale;
1906 if (drawable) /* using an intermediate pixmap */
1908 RGNDATA *clip_data = NULL;
1910 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1911 x_dst = dst->x;
1912 y_dst = dst->y;
1913 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL );
1914 if (clip_data)
1915 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
1916 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
1917 HeapFree( GetProcessHeap(), 0, clip_data );
1919 else
1921 x_dst = physdev->x11dev->dc_rect.left + dst->x;
1922 y_dst = physdev->x11dev->dc_rect.top + dst->y;
1923 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
1926 if (!use_repeat)
1928 xscale = src->width / (double)dst->width;
1929 yscale = src->height / (double)dst->height;
1931 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1933 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
1934 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1936 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1940 /***********************************************************************
1941 * xrenderdrv_StretchBlt
1943 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1944 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1946 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1947 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1948 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
1950 if (src_dev->funcs != dst_dev->funcs)
1952 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
1953 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
1956 /* XRender is of no use for color -> mono */
1957 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
1958 goto x11drv_fallback;
1960 /* if not stretching, we only need to handle format conversion */
1961 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
1963 if (rop != SRCCOPY)
1965 GC tmpGC;
1966 Pixmap tmp_pixmap;
1967 struct bitblt_coords tmp;
1969 /* make coordinates relative to tmp pixmap */
1970 tmp = *dst;
1971 tmp.x -= tmp.visrect.left;
1972 tmp.y -= tmp.visrect.top;
1973 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1975 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
1976 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1977 XSetGraphicsExposures( gdi_display, tmpGC, False );
1978 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
1979 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
1981 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
1982 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
1984 XFreePixmap( gdi_display, tmp_pixmap );
1985 XFreeGC( gdi_display, tmpGC );
1987 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
1989 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
1990 return TRUE;
1992 x11drv_fallback:
1993 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
1997 /***********************************************************************
1998 * xrenderdrv_PutImage
2000 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
2001 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2002 struct bitblt_coords *dst, DWORD rop )
2004 struct xrender_physdev *physdev = get_xrender_dev( dev );
2005 DWORD ret;
2006 Pixmap tmp_pixmap;
2007 GC gc;
2008 enum wxr_format src_format, dst_format;
2009 XRenderPictFormat *pict_format;
2010 Pixmap src_pixmap;
2011 Picture src_pict, mask_pict = 0;
2012 BOOL use_repeat;
2014 dst_format = physdev->format;
2015 src_format = get_xrender_format_from_bitmapinfo( info );
2016 if (!(pict_format = pict_formats[src_format])) goto update_format;
2018 /* make sure we can create an image with the same bpp */
2019 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2020 goto update_format;
2022 /* mono <-> color conversions not supported */
2023 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2024 goto x11drv_fallback;
2026 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2028 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2030 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2031 if (!ret)
2033 struct bitblt_coords tmp;
2035 if (rop != SRCCOPY)
2037 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2039 /* make coordinates relative to tmp pixmap */
2040 tmp = *dst;
2041 tmp.x -= tmp.visrect.left;
2042 tmp.y -= tmp.visrect.top;
2043 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2045 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2046 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2047 XSetGraphicsExposures( gdi_display, gc, False );
2048 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2049 tmp.visrect.right - tmp.visrect.left,
2050 tmp.visrect.bottom - tmp.visrect.top,
2051 physdev->pict_format->depth );
2053 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2054 NULL, tmp_pixmap, src, &tmp, use_repeat );
2055 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2057 XFreePixmap( gdi_display, tmp_pixmap );
2058 XFreeGC( gdi_display, gc );
2059 if (restore_region) restore_clipping_region( physdev->x11dev );
2061 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2062 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2064 add_device_bounds( physdev->x11dev, &dst->visrect );
2066 pXRenderFreePicture( gdi_display, src_pict );
2067 XFreePixmap( gdi_display, src_pixmap );
2069 return ret;
2071 update_format:
2072 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2073 set_color_info( pict_formats[dst_format], info );
2074 return ERROR_BAD_FORMAT;
2076 x11drv_fallback:
2077 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2078 return dev->funcs->pPutImage( dev, clip, info, bits, src, dst, rop );
2082 /***********************************************************************
2083 * xrenderdrv_BlendImage
2085 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2086 struct bitblt_coords *src, struct bitblt_coords *dst,
2087 BLENDFUNCTION func )
2089 struct xrender_physdev *physdev = get_xrender_dev( dev );
2090 DWORD ret;
2091 enum wxr_format format;
2092 XRenderPictFormat *pict_format;
2093 Picture dst_pict, src_pict, mask_pict;
2094 Pixmap src_pixmap;
2095 BOOL use_repeat;
2097 format = get_xrender_format_from_bitmapinfo( info );
2098 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2099 format = get_format_without_alpha( format );
2100 else if (format != WXR_FORMAT_A8R8G8B8)
2101 return ERROR_INVALID_PARAMETER;
2103 if (!(pict_format = pict_formats[format])) goto update_format;
2105 /* make sure we can create an image with the same bpp */
2106 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2107 goto update_format;
2109 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2110 goto update_format;
2112 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2114 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2115 if (!ret)
2117 double xscale, yscale;
2119 if (!use_repeat)
2121 xscale = src->width / (double)dst->width;
2122 yscale = src->height / (double)dst->height;
2124 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2126 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2128 EnterCriticalSection( &xrender_cs );
2129 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2131 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2132 src->x, src->y, src->width, src->height,
2133 physdev->x11dev->dc_rect.left + dst->x,
2134 physdev->x11dev->dc_rect.top + dst->y,
2135 dst->width, dst->height, xscale, yscale );
2137 pXRenderFreePicture( gdi_display, src_pict );
2138 XFreePixmap( gdi_display, src_pixmap );
2140 LeaveCriticalSection( &xrender_cs );
2141 add_device_bounds( physdev->x11dev, &dst->visrect );
2143 return ret;
2145 update_format:
2146 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2147 set_color_info( physdev->pict_format, info );
2148 return ERROR_BAD_FORMAT;
2152 /***********************************************************************
2153 * xrenderdrv_AlphaBlend
2155 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2156 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2158 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2159 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2160 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2161 XRenderPictureAttributes pa;
2162 Pixmap tmp_pixmap = 0;
2163 double xscale, yscale;
2165 if (src_dev->funcs != dst_dev->funcs)
2167 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2168 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2171 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2173 SetLastError( ERROR_INVALID_PARAMETER );
2174 return FALSE;
2177 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2179 xscale = src->width / (double)dst->width;
2180 yscale = src->height / (double)dst->height;
2182 src_pict = get_xrender_picture_source( physdev_src, FALSE );
2184 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2186 /* mono -> color blending needs an intermediate color pixmap */
2187 XRenderColor fg, bg;
2188 int width = src->visrect.right - src->visrect.left;
2189 int height = src->visrect.bottom - src->visrect.top;
2191 /* blending doesn't use the destination DC colors */
2192 fg.red = fg.green = fg.blue = 0;
2193 bg.red = bg.green = bg.blue = 0xffff;
2194 fg.alpha = bg.alpha = 0xffff;
2196 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2197 physdev_dst->pict_format->depth );
2198 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format, 0, NULL );
2200 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2201 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
2203 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2205 /* we need a source picture with no alpha */
2206 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2207 if (format != physdev_src->format)
2209 pa.subwindow_mode = IncludeInferiors;
2210 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2211 pict_formats[format], CPSubwindowMode, &pa );
2215 if (tmp_pict) src_pict = tmp_pict;
2217 EnterCriticalSection( &xrender_cs );
2218 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2220 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2221 physdev_src->x11dev->dc_rect.left + src->x,
2222 physdev_src->x11dev->dc_rect.top + src->y,
2223 src->width, src->height,
2224 physdev_dst->x11dev->dc_rect.left + dst->x,
2225 physdev_dst->x11dev->dc_rect.top + dst->y,
2226 dst->width, dst->height, xscale, yscale );
2228 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2229 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2231 LeaveCriticalSection( &xrender_cs );
2232 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2233 return TRUE;
2236 /***********************************************************************
2237 * xrenderdrv_GradientFill
2239 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2240 void * grad_array, ULONG ngrad, ULONG mode )
2242 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2243 static const XFixed stops[2] = { 0, 1 << 16 };
2244 struct xrender_physdev *physdev = get_xrender_dev( dev );
2245 XLinearGradient gradient;
2246 XRenderColor colors[2];
2247 Picture src_pict, dst_pict;
2248 unsigned int i;
2249 const GRADIENT_RECT *rect = grad_array;
2250 RECT rc;
2251 POINT pt[2];
2253 if (!pXRenderCreateLinearGradient) goto fallback;
2255 /* <= 16-bpp uses dithering */
2256 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2258 switch (mode)
2260 case GRADIENT_FILL_RECT_H:
2261 case GRADIENT_FILL_RECT_V:
2262 for (i = 0; i < ngrad; i++, rect++)
2264 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2265 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2267 colors[0].red = v1->Red * 257 / 256;
2268 colors[0].green = v1->Green * 257 / 256;
2269 colors[0].blue = v1->Blue * 257 / 256;
2270 colors[1].red = v2->Red * 257 / 256;
2271 colors[1].green = v2->Green * 257 / 256;
2272 colors[1].blue = v2->Blue * 257 / 256;
2273 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2274 colors[0].alpha = colors[1].alpha = 65535;
2276 pt[0].x = v1->x;
2277 pt[0].y = v1->y;
2278 pt[1].x = v2->x;
2279 pt[1].y = v2->y;
2280 LPtoDP( dev->hdc, pt, 2 );
2281 if (mode == GRADIENT_FILL_RECT_H)
2283 gradient.p1.y = gradient.p2.y = 0;
2284 if (pt[1].x > pt[0].x)
2286 gradient.p1.x = 0;
2287 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2289 else
2291 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2292 gradient.p2.x = 0;
2295 else
2297 gradient.p1.x = gradient.p2.x = 0;
2298 if (pt[1].y > pt[0].y)
2300 gradient.p1.y = 0;
2301 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2303 else
2305 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2306 gradient.p2.y = 0;
2310 rc.left = min( pt[0].x, pt[1].x );
2311 rc.top = min( pt[0].y, pt[1].y );
2312 rc.right = max( pt[0].x, pt[1].x );
2313 rc.bottom = max( pt[0].y, pt[1].y );
2315 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2316 mode, wine_dbgstr_rect( &rc ),
2317 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2318 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2320 dst_pict = get_xrender_picture( physdev, 0, NULL );
2322 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2323 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2324 0, 0, rc.right - rc.left, rc.bottom - rc.top,
2325 physdev->x11dev->dc_rect.left + rc.left,
2326 physdev->x11dev->dc_rect.top + rc.top,
2327 rc.right - rc.left, rc.bottom - rc.top, 1, 1 );
2328 pXRenderFreePicture( gdi_display, src_pict );
2329 add_device_bounds( physdev->x11dev, &rc );
2331 return TRUE;
2334 fallback:
2335 #endif
2336 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2337 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2340 /***********************************************************************
2341 * xrenderdrv_SelectBrush
2343 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2345 struct xrender_physdev *physdev = get_xrender_dev( dev );
2346 Pixmap pixmap;
2347 XVisualInfo vis;
2348 XRenderPictFormat *format = physdev->pict_format;
2350 if (!pattern) goto x11drv_fallback;
2351 if (pattern->info->bmiHeader.biBitCount == 1) goto x11drv_fallback;
2352 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2354 memset( &vis, 0, sizeof(vis) );
2355 vis.depth = format->depth;
2356 vis.red_mask = format->direct.redMask << format->direct.red;
2357 vis.green_mask = format->direct.greenMask << format->direct.green;
2358 vis.blue_mask = format->direct.blueMask << format->direct.blue;
2360 pixmap = create_pixmap_from_image( physdev->dev.hdc, &vis, pattern->info,
2361 &pattern->bits, pattern->usage );
2362 if (!pixmap) return 0;
2364 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2365 physdev->x11dev->brush.pixmap = pixmap;
2366 physdev->x11dev->brush.fillStyle = FillTiled;
2367 physdev->x11dev->brush.pixel = 0; /* ignored */
2368 physdev->x11dev->brush.style = BS_PATTERN;
2369 return hbrush;
2371 x11drv_fallback:
2372 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2373 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2377 static const struct gdi_dc_funcs xrender_funcs =
2379 NULL, /* pAbortDoc */
2380 NULL, /* pAbortPath */
2381 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2382 NULL, /* pAngleArc */
2383 NULL, /* pArc */
2384 NULL, /* pArcTo */
2385 NULL, /* pBeginPath */
2386 xrenderdrv_BlendImage, /* pBlendImage */
2387 NULL, /* pChord */
2388 NULL, /* pCloseFigure */
2389 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2390 xrenderdrv_CreateDC, /* pCreateDC */
2391 xrenderdrv_DeleteDC, /* pDeleteDC */
2392 NULL, /* pDeleteObject */
2393 NULL, /* pDeviceCapabilities */
2394 NULL, /* pEllipse */
2395 NULL, /* pEndDoc */
2396 NULL, /* pEndPage */
2397 NULL, /* pEndPath */
2398 NULL, /* pEnumFonts */
2399 NULL, /* pEnumICMProfiles */
2400 NULL, /* pExcludeClipRect */
2401 NULL, /* pExtDeviceMode */
2402 xrenderdrv_ExtEscape, /* pExtEscape */
2403 NULL, /* pExtFloodFill */
2404 NULL, /* pExtSelectClipRgn */
2405 xrenderdrv_ExtTextOut, /* pExtTextOut */
2406 NULL, /* pFillPath */
2407 NULL, /* pFillRgn */
2408 NULL, /* pFlattenPath */
2409 NULL, /* pFontIsLinked */
2410 NULL, /* pFrameRgn */
2411 NULL, /* pGdiComment */
2412 NULL, /* pGdiRealizationInfo */
2413 NULL, /* pGetBoundsRect */
2414 NULL, /* pGetCharABCWidths */
2415 NULL, /* pGetCharABCWidthsI */
2416 NULL, /* pGetCharWidth */
2417 NULL, /* pGetDeviceCaps */
2418 NULL, /* pGetDeviceGammaRamp */
2419 NULL, /* pGetFontData */
2420 NULL, /* pGetFontUnicodeRanges */
2421 NULL, /* pGetGlyphIndices */
2422 NULL, /* pGetGlyphOutline */
2423 NULL, /* pGetICMProfile */
2424 NULL, /* pGetImage */
2425 NULL, /* pGetKerningPairs */
2426 NULL, /* pGetNearestColor */
2427 NULL, /* pGetOutlineTextMetrics */
2428 NULL, /* pGetPixel */
2429 NULL, /* pGetSystemPaletteEntries */
2430 NULL, /* pGetTextCharsetInfo */
2431 NULL, /* pGetTextExtentExPoint */
2432 NULL, /* pGetTextExtentExPointI */
2433 NULL, /* pGetTextFace */
2434 NULL, /* pGetTextMetrics */
2435 xrenderdrv_GradientFill, /* pGradientFill */
2436 NULL, /* pIntersectClipRect */
2437 NULL, /* pInvertRgn */
2438 NULL, /* pLineTo */
2439 NULL, /* pModifyWorldTransform */
2440 NULL, /* pMoveTo */
2441 NULL, /* pOffsetClipRgn */
2442 NULL, /* pOffsetViewportOrg */
2443 NULL, /* pOffsetWindowOrg */
2444 NULL, /* pPaintRgn */
2445 NULL, /* pPatBlt */
2446 NULL, /* pPie */
2447 NULL, /* pPolyBezier */
2448 NULL, /* pPolyBezierTo */
2449 NULL, /* pPolyDraw */
2450 NULL, /* pPolyPolygon */
2451 NULL, /* pPolyPolyline */
2452 NULL, /* pPolygon */
2453 NULL, /* pPolyline */
2454 NULL, /* pPolylineTo */
2455 xrenderdrv_PutImage, /* pPutImage */
2456 NULL, /* pRealizeDefaultPalette */
2457 NULL, /* pRealizePalette */
2458 NULL, /* pRectangle */
2459 NULL, /* pResetDC */
2460 NULL, /* pRestoreDC */
2461 NULL, /* pRoundRect */
2462 NULL, /* pSaveDC */
2463 NULL, /* pScaleViewportExt */
2464 NULL, /* pScaleWindowExt */
2465 NULL, /* pSelectBitmap */
2466 xrenderdrv_SelectBrush, /* pSelectBrush */
2467 NULL, /* pSelectClipPath */
2468 xrenderdrv_SelectFont, /* pSelectFont */
2469 NULL, /* pSelectPalette */
2470 NULL, /* pSelectPen */
2471 NULL, /* pSetArcDirection */
2472 NULL, /* pSetBkColor */
2473 NULL, /* pSetBkMode */
2474 NULL, /* pSetBoundsRect */
2475 NULL, /* pSetDCBrushColor */
2476 NULL, /* pSetDCPenColor */
2477 NULL, /* pSetDIBitsToDevice */
2478 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2479 NULL, /* pSetDeviceGammaRamp */
2480 NULL, /* pSetLayout */
2481 NULL, /* pSetMapMode */
2482 NULL, /* pSetMapperFlags */
2483 NULL, /* pSetPixel */
2484 NULL, /* pSetPolyFillMode */
2485 NULL, /* pSetROP2 */
2486 NULL, /* pSetRelAbs */
2487 NULL, /* pSetStretchBltMode */
2488 NULL, /* pSetTextAlign */
2489 NULL, /* pSetTextCharacterExtra */
2490 NULL, /* pSetTextColor */
2491 NULL, /* pSetTextJustification */
2492 NULL, /* pSetViewportExt */
2493 NULL, /* pSetViewportOrg */
2494 NULL, /* pSetWindowExt */
2495 NULL, /* pSetWindowOrg */
2496 NULL, /* pSetWorldTransform */
2497 NULL, /* pStartDoc */
2498 NULL, /* pStartPage */
2499 xrenderdrv_StretchBlt, /* pStretchBlt */
2500 NULL, /* pStretchDIBits */
2501 NULL, /* pStrokeAndFillPath */
2502 NULL, /* pStrokePath */
2503 NULL, /* pSwapBuffers */
2504 NULL, /* pUnrealizePalette */
2505 NULL, /* pWidenPath */
2506 NULL, /* wine_get_wgl_driver */
2507 GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
2510 #else /* SONAME_LIBXRENDER */
2512 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2514 TRACE("XRender support not compiled in.\n");
2515 return NULL;
2518 void X11DRV_XRender_Finalize(void)
2522 #endif /* SONAME_LIBXRENDER */