winex11: Use the default anti-aliasing parameters from gdi32.
[wine.git] / dlls / winex11.drv / xrender.c
blobb9d27fa2792d23d9ab32cd3189d6a5c00a7ba0e6
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 void *xrender_handle;
184 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
185 MAKE_FUNCPTR(XRenderAddGlyphs)
186 MAKE_FUNCPTR(XRenderChangePicture)
187 MAKE_FUNCPTR(XRenderComposite)
188 MAKE_FUNCPTR(XRenderCompositeText16)
189 MAKE_FUNCPTR(XRenderCreateGlyphSet)
190 MAKE_FUNCPTR(XRenderCreatePicture)
191 MAKE_FUNCPTR(XRenderFillRectangle)
192 MAKE_FUNCPTR(XRenderFindFormat)
193 MAKE_FUNCPTR(XRenderFindVisualFormat)
194 MAKE_FUNCPTR(XRenderFreeGlyphSet)
195 MAKE_FUNCPTR(XRenderFreePicture)
196 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
197 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
198 MAKE_FUNCPTR(XRenderCreateLinearGradient)
199 #endif
200 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
201 MAKE_FUNCPTR(XRenderSetPictureTransform)
202 #endif
203 MAKE_FUNCPTR(XRenderQueryExtension)
205 #undef MAKE_FUNCPTR
207 static CRITICAL_SECTION xrender_cs;
208 static CRITICAL_SECTION_DEBUG critsect_debug =
210 0, 0, &xrender_cs,
211 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
212 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
214 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
216 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
217 ( ( (ULONG)_x4 << 24 ) | \
218 ( (ULONG)_x3 << 16 ) | \
219 ( (ULONG)_x2 << 8 ) | \
220 (ULONG)_x1 )
222 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
224 #define GASP_GRIDFIT 0x01
225 #define GASP_DOGRAY 0x02
227 #ifdef WORDS_BIGENDIAN
228 #define get_be_word(x) (x)
229 #define NATIVE_BYTE_ORDER MSBFirst
230 #else
231 #define get_be_word(x) RtlUshortByteSwap(x)
232 #define NATIVE_BYTE_ORDER LSBFirst
233 #endif
235 static BOOL has_alpha( enum wxr_format format )
237 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
240 static enum wxr_format get_format_without_alpha( enum wxr_format format )
242 switch (format)
244 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
245 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
246 default: return format;
250 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
252 templ->id = 0;
253 templ->type = PictTypeDirect;
254 templ->depth = fmt->depth;
255 templ->direct.alpha = fmt->alpha;
256 templ->direct.alphaMask = fmt->alphaMask;
257 templ->direct.red = fmt->red;
258 templ->direct.redMask = fmt->redMask;
259 templ->direct.green = fmt->green;
260 templ->direct.greenMask = fmt->greenMask;
261 templ->direct.blue = fmt->blue;
262 templ->direct.blueMask = fmt->blueMask;
263 templ->colormap = 0;
265 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
267 return TRUE;
270 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
272 if(fmt->depth != default_visual.depth) return FALSE;
273 if( (fmt->redMask << fmt->red) != default_visual.red_mask) return FALSE;
274 if( (fmt->greenMask << fmt->green) != default_visual.green_mask) return FALSE;
275 if( (fmt->blueMask << fmt->blue) != default_visual.blue_mask) return FALSE;
277 /* We never select a default ARGB visual */
278 if(fmt->alphaMask) return FALSE;
279 return TRUE;
282 static int load_xrender_formats(void)
284 int count = 0;
285 unsigned int i;
287 for (i = 0; i < WXR_NB_FORMATS; i++)
289 XRenderPictFormat templ;
291 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
293 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, default_visual.visual);
294 if (!pict_formats[i])
296 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
297 if (default_visual.class == DirectColor)
299 XVisualInfo info;
300 if (XMatchVisualInfo( gdi_display, default_visual.screen,
301 default_visual.depth, TrueColor, &info ))
303 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
304 if (pict_formats[i]) default_visual = info;
308 if (pict_formats[i]) default_format = i;
310 else
312 unsigned long mask = 0;
313 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
314 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
316 if (pict_formats[i])
318 count++;
319 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
322 return count;
325 /***********************************************************************
326 * X11DRV_XRender_Init
328 * Let's see if our XServer has the extension available
331 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
333 int event_base, i;
335 if (!client_side_with_render) return NULL;
336 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
338 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
339 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
340 LOAD_FUNCPTR(XRenderAddGlyphs);
341 LOAD_FUNCPTR(XRenderChangePicture);
342 LOAD_FUNCPTR(XRenderComposite);
343 LOAD_FUNCPTR(XRenderCompositeText16);
344 LOAD_FUNCPTR(XRenderCreateGlyphSet);
345 LOAD_FUNCPTR(XRenderCreatePicture);
346 LOAD_FUNCPTR(XRenderFillRectangle);
347 LOAD_FUNCPTR(XRenderFindFormat);
348 LOAD_FUNCPTR(XRenderFindVisualFormat);
349 LOAD_FUNCPTR(XRenderFreeGlyphSet);
350 LOAD_FUNCPTR(XRenderFreePicture);
351 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
352 LOAD_FUNCPTR(XRenderQueryExtension);
353 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
354 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
355 #endif
356 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
357 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
358 #endif
359 #undef LOAD_OPTIONAL_FUNCPTR
360 #undef LOAD_FUNCPTR
362 if (!pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) return NULL;
364 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
365 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
367 ERR_(winediag)("Wine has detected that you probably have a buggy version "
368 "of libXrender. Because of this client side font rendering "
369 "will be disabled. Please upgrade this library.\n");
370 return NULL;
373 if (!default_visual.red_mask || !default_visual.green_mask || !default_visual.blue_mask)
375 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
376 return NULL;
379 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
380 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
382 glyphsetCacheSize = INIT_CACHE_SIZE;
383 lastfree = 0;
384 for(i = 0; i < INIT_CACHE_SIZE; i++) {
385 glyphsetCache[i].next = i + 1;
386 glyphsetCache[i].count = -1;
388 glyphsetCache[i-1].next = -1;
390 return &xrender_funcs;
393 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
394 static void get_xrender_color( struct xrender_physdev *physdev, COLORREF src_color, XRenderColor *dst_color )
396 if (src_color & (1 << 24)) /* PALETTEINDEX */
398 HPALETTE pal = GetCurrentObject( physdev->dev.hdc, OBJ_PAL );
399 PALETTEENTRY pal_ent;
401 if (!GetPaletteEntries( pal, LOWORD(src_color), 1, &pal_ent ))
402 GetPaletteEntries( pal, 0, 1, &pal_ent );
403 dst_color->red = pal_ent.peRed * 257;
404 dst_color->green = pal_ent.peGreen * 257;
405 dst_color->blue = pal_ent.peBlue * 257;
407 else
409 if (src_color >> 16 == 0x10ff) src_color = 0; /* DIBINDEX */
411 dst_color->red = GetRValue( src_color ) * 257;
412 dst_color->green = GetGValue( src_color ) * 257;
413 dst_color->blue = GetBValue( src_color ) * 257;
416 if (physdev->format == WXR_FORMAT_MONO && !dst_color->red && !dst_color->green && !dst_color->blue)
417 dst_color->alpha = 0;
418 else
419 dst_color->alpha = 0xffff;
422 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
424 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
426 switch (info->bmiHeader.biBitCount)
428 case 1:
429 return WXR_FORMAT_MONO;
430 case 4:
431 case 8:
432 break;
433 case 24:
434 if (info->bmiHeader.biCompression != BI_RGB) break;
435 return WXR_FORMAT_R8G8B8;
436 case 16:
437 case 32:
438 if (info->bmiHeader.biCompression == BI_BITFIELDS)
440 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
441 unsigned int i;
443 for (i = 0; i < WXR_NB_FORMATS; i++)
445 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
446 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
447 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
448 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
449 return i;
451 break;
453 if (info->bmiHeader.biCompression != BI_RGB) break;
454 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
456 return WXR_INVALID_FORMAT;
459 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
460 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
462 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
463 XTransform xform = {{
464 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
465 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
466 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
469 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
470 #endif
473 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
475 XRenderPictureAttributes pa;
476 RGNDATA *data;
478 if (!rgn)
480 pa.clip_mask = None;
481 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
483 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
485 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
486 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
487 (XRectangle *)data->Buffer, data->rdh.nCount );
488 HeapFree( GetProcessHeap(), 0, data );
493 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
495 if (!dev->pict && dev->pict_format)
497 XRenderPictureAttributes pa;
499 pa.subwindow_mode = IncludeInferiors;
500 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
501 dev->pict_format, CPSubwindowMode, &pa );
502 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
503 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
504 dev->update_clip = (dev->region != 0);
507 if (clip_rect)
509 HRGN rgn = CreateRectRgnIndirect( clip_rect );
510 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
511 if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
512 update_xrender_clipping( dev, rgn );
513 DeleteObject( rgn );
515 else if (clip_rgn)
517 if (dev->region)
519 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
520 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
521 update_xrender_clipping( dev, rgn );
522 DeleteObject( rgn );
524 else update_xrender_clipping( dev, clip_rgn );
526 else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
528 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
529 return dev->pict;
532 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
534 if (!dev->pict_src && dev->pict_format)
536 XRenderPictureAttributes pa;
538 pa.subwindow_mode = IncludeInferiors;
539 pa.repeat = repeat ? RepeatNormal : RepeatNone;
540 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
541 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
543 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
544 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
547 return dev->pict_src;
550 static void free_xrender_picture( struct xrender_physdev *dev )
552 if (dev->pict || dev->pict_src)
554 XFlush( gdi_display );
555 if (dev->pict)
557 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
558 pXRenderFreePicture(gdi_display, dev->pict);
559 dev->pict = 0;
561 if(dev->pict_src)
563 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
564 pXRenderFreePicture(gdi_display, dev->pict_src);
565 dev->pict_src = 0;
570 /* return a mask picture used to force alpha to 0 */
571 static Picture get_no_alpha_mask(void)
573 static Pixmap pixmap;
574 static Picture pict;
576 EnterCriticalSection( &xrender_cs );
577 if (!pict)
579 XRenderPictureAttributes pa;
580 XRenderColor col;
582 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
583 pa.repeat = RepeatNormal;
584 pa.component_alpha = True;
585 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
586 CPRepeat|CPComponentAlpha, &pa );
587 col.red = col.green = col.blue = 0xffff;
588 col.alpha = 0;
589 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
591 LeaveCriticalSection( &xrender_cs );
592 return pict;
595 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
597 if(p1->hash != p2->hash) return TRUE;
598 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
599 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
600 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
601 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
604 #if 0
605 static void walk_cache(void)
607 int i;
609 EnterCriticalSection(&xrender_cs);
610 for(i=mru; i >= 0; i = glyphsetCache[i].next)
611 TRACE("item %d\n", i);
612 LeaveCriticalSection(&xrender_cs);
614 #endif
616 static int LookupEntry(LFANDSIZE *plfsz)
618 int i, prev_i = -1;
620 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
621 TRACE("%d\n", i);
622 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
624 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
625 glyphsetCache[i].count++;
626 if(prev_i >= 0) {
627 glyphsetCache[prev_i].next = glyphsetCache[i].next;
628 glyphsetCache[i].next = mru;
629 mru = i;
631 TRACE("found font in cache %d\n", i);
632 return i;
634 prev_i = i;
636 TRACE("font not in cache\n");
637 return -1;
640 static void FreeEntry(int entry)
642 int format;
644 for(format = 0; format < AA_MAXVALUE; format++) {
645 gsCacheEntryFormat * formatEntry;
647 if( !glyphsetCache[entry].format[format] )
648 continue;
650 formatEntry = glyphsetCache[entry].format[format];
652 if(formatEntry->glyphset) {
653 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
654 formatEntry->glyphset = 0;
656 if(formatEntry->nrealized) {
657 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
658 formatEntry->realized = NULL;
659 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
660 formatEntry->gis = NULL;
661 formatEntry->nrealized = 0;
664 HeapFree(GetProcessHeap(), 0, formatEntry);
665 glyphsetCache[entry].format[format] = NULL;
669 static int AllocEntry(void)
671 int best = -1, prev_best = -1, i, prev_i = -1;
673 if(lastfree >= 0) {
674 assert(glyphsetCache[lastfree].count == -1);
675 glyphsetCache[lastfree].count = 1;
676 best = lastfree;
677 lastfree = glyphsetCache[lastfree].next;
678 assert(best != mru);
679 glyphsetCache[best].next = mru;
680 mru = best;
682 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
683 return mru;
686 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
687 if(glyphsetCache[i].count == 0) {
688 best = i;
689 prev_best = prev_i;
691 prev_i = i;
694 if(best >= 0) {
695 TRACE("freeing unused glyphset at cache %d\n", best);
696 FreeEntry(best);
697 glyphsetCache[best].count = 1;
698 if(prev_best >= 0) {
699 glyphsetCache[prev_best].next = glyphsetCache[best].next;
700 glyphsetCache[best].next = mru;
701 mru = best;
702 } else {
703 assert(mru == best);
705 return mru;
708 TRACE("Growing cache\n");
710 if (glyphsetCache)
711 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
712 glyphsetCache,
713 (glyphsetCacheSize + INIT_CACHE_SIZE)
714 * sizeof(*glyphsetCache));
715 else
716 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
717 (glyphsetCacheSize + INIT_CACHE_SIZE)
718 * sizeof(*glyphsetCache));
720 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
721 i++) {
722 glyphsetCache[i].next = i + 1;
723 glyphsetCache[i].count = -1;
725 glyphsetCache[i-1].next = -1;
726 glyphsetCacheSize += INIT_CACHE_SIZE;
728 lastfree = glyphsetCache[best].next;
729 glyphsetCache[best].count = 1;
730 glyphsetCache[best].next = mru;
731 mru = best;
732 TRACE("new free cache slot at %d\n", mru);
733 return mru;
736 static int GetCacheEntry( LFANDSIZE *plfsz )
738 int ret;
739 int format;
740 gsCacheEntry *entry;
742 if((ret = LookupEntry(plfsz)) != -1) return ret;
744 ret = AllocEntry();
745 entry = glyphsetCache + ret;
746 entry->lfsz = *plfsz;
747 for( format = 0; format < AA_MAXVALUE; format++ ) {
748 assert( !entry->format[format] );
751 return ret;
754 static void dec_ref_cache(int index)
756 assert(index >= 0);
757 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
758 assert(glyphsetCache[index].count > 0);
759 glyphsetCache[index].count--;
762 static void lfsz_calc_hash(LFANDSIZE *plfsz)
764 DWORD hash = 0, *ptr, two_chars;
765 WORD *pwc;
766 int i;
768 hash ^= plfsz->devsize.cx;
769 hash ^= plfsz->devsize.cy;
770 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
771 hash ^= *ptr;
772 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
773 hash ^= *ptr;
774 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
775 two_chars = *ptr;
776 pwc = (WCHAR *)&two_chars;
777 if(!*pwc) break;
778 *pwc = toupperW(*pwc);
779 pwc++;
780 *pwc = toupperW(*pwc);
781 hash ^= two_chars;
782 if(!*pwc) break;
784 plfsz->hash = hash;
785 return;
788 static AA_Type aa_type_from_flags( UINT aa_flags )
790 switch (aa_flags & 0x7f)
792 case 0:
793 case GGO_BITMAP:
794 return AA_None;
795 case GGO_GRAY4_BITMAP:
796 case WINE_GGO_GRAY16_BITMAP:
797 return AA_Grey;
798 case WINE_GGO_HRGB_BITMAP:
799 return AA_RGB;
800 case WINE_GGO_HBGR_BITMAP:
801 return AA_BGR;
802 case WINE_GGO_VRGB_BITMAP:
803 return AA_VRGB;
804 case WINE_GGO_VBGR_BITMAP:
805 return AA_VBGR;
806 default:
807 FIXME( "unknown flags %x\n", aa_flags );
808 return AA_None;
812 static UINT get_xft_aa_flags( const LOGFONTW *lf )
814 char *value;
815 UINT ret = 0;
817 switch (lf->lfQuality)
819 case NONANTIALIASED_QUALITY:
820 case ANTIALIASED_QUALITY:
821 break;
822 default:
823 if (!(value = XGetDefault( gdi_display, "Xft", "antialias" ))) break;
824 TRACE( "got antialias '%s'\n", value );
825 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
826 value[0] == '0' || !strcasecmp( value, "off" ))
828 ret = GGO_BITMAP;
829 break;
831 ret = GGO_GRAY4_BITMAP;
832 /* fall through */
833 case CLEARTYPE_QUALITY:
834 case CLEARTYPE_NATURAL_QUALITY:
835 if (!(value = XGetDefault( gdi_display, "Xft", "rgba" ))) break;
836 TRACE( "got rgba '%s'\n", value );
837 if (!strcmp( value, "rgb" )) ret = WINE_GGO_HRGB_BITMAP;
838 else if (!strcmp( value, "bgr" )) ret = WINE_GGO_HBGR_BITMAP;
839 else if (!strcmp( value, "vrgb" )) ret = WINE_GGO_VRGB_BITMAP;
840 else if (!strcmp( value, "vbgr" )) ret = WINE_GGO_VBGR_BITMAP;
841 else if (!strcmp( value, "none" )) ret = GGO_GRAY4_BITMAP;
842 break;
844 return ret;
847 /**********************************************************************
848 * xrenderdrv_SelectFont
850 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
852 LFANDSIZE lfsz;
853 struct xrender_physdev *physdev = get_xrender_dev( dev );
854 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
855 HFONT ret;
857 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
858 if (!*aa_flags) *aa_flags = get_xft_aa_flags( &lfsz.lf );
860 ret = next->funcs->pSelectFont( next, hfont, aa_flags );
861 if (!ret) return 0;
863 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
864 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
865 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
866 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
867 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
868 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
870 GetTransform( dev->hdc, 0x204, &lfsz.xform );
871 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
872 lfsz.xform.eM21, lfsz.xform.eM22);
874 if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE && lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
875 lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
877 /* Not used fields, would break hashing */
878 lfsz.xform.eDx = lfsz.xform.eDy = 0;
880 lfsz_calc_hash(&lfsz);
882 EnterCriticalSection(&xrender_cs);
883 if (physdev->cache_index != -1)
884 dec_ref_cache( physdev->cache_index );
885 physdev->cache_index = GetCacheEntry( &lfsz );
886 glyphsetCache[physdev->cache_index].aa_default = aa_type_from_flags( *aa_flags );
887 LeaveCriticalSection(&xrender_cs);
888 return ret;
891 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
893 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
894 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
896 if (!physdev) return FALSE;
897 physdev->x11dev = x11dev;
898 physdev->cache_index = -1;
899 physdev->format = format;
900 physdev->pict_format = pict_formats[format];
901 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
902 return TRUE;
905 /* store the color mask data in the bitmap info structure */
906 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
908 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
910 info->bmiHeader.biPlanes = 1;
911 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
912 info->bmiHeader.biCompression = BI_RGB;
913 info->bmiHeader.biClrUsed = 0;
915 switch (info->bmiHeader.biBitCount)
917 case 16:
918 colors[0] = format->direct.redMask << format->direct.red;
919 colors[1] = format->direct.greenMask << format->direct.green;
920 colors[2] = format->direct.blueMask << format->direct.blue;
921 info->bmiHeader.biCompression = BI_BITFIELDS;
922 break;
923 case 32:
924 colors[0] = format->direct.redMask << format->direct.red;
925 colors[1] = format->direct.greenMask << format->direct.green;
926 colors[2] = format->direct.blueMask << format->direct.blue;
927 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
928 info->bmiHeader.biCompression = BI_BITFIELDS;
929 break;
934 /**********************************************************************
935 * xrenderdrv_CreateDC
937 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
938 LPCWSTR output, const DEVMODEW* initData )
940 return create_xrender_dc( pdev, default_format );
943 /**********************************************************************
944 * xrenderdrv_CreateCompatibleDC
946 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
948 if (orig) /* chain to x11drv first */
950 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
951 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
953 /* otherwise we have been called by x11drv */
955 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
958 /**********************************************************************
959 * xrenderdrv_DeleteDC
961 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
963 struct xrender_physdev *physdev = get_xrender_dev( dev );
965 free_xrender_picture( physdev );
967 EnterCriticalSection( &xrender_cs );
968 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
969 LeaveCriticalSection( &xrender_cs );
971 HeapFree( GetProcessHeap(), 0, physdev );
972 return TRUE;
975 /**********************************************************************
976 * xrenderdrv_ExtEscape
978 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
979 INT out_count, LPVOID out_data )
981 struct xrender_physdev *physdev = get_xrender_dev( dev );
983 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
985 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
987 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
989 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
990 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
991 return ret;
994 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
997 /***********************************************************************
998 * xrenderdrv_SetDeviceClipping
1000 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1002 struct xrender_physdev *physdev = get_xrender_dev( dev );
1004 physdev->region = rgn;
1005 physdev->update_clip = TRUE;
1007 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1008 dev->funcs->pSetDeviceClipping( dev, rgn );
1012 /************************************************************************
1013 * UploadGlyph
1015 * Helper to ExtTextOut. Must be called inside xrender_cs
1017 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1019 unsigned int buflen;
1020 char *buf;
1021 Glyph gid;
1022 GLYPHMETRICS gm;
1023 XGlyphInfo gi;
1024 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1025 gsCacheEntryFormat *formatEntry;
1026 UINT ggo_format = GGO_GLYPH_INDEX;
1027 enum wxr_format wxr_format;
1028 static const char zero[4];
1029 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1031 switch(format) {
1032 case AA_Grey:
1033 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1034 break;
1035 case AA_RGB:
1036 ggo_format |= WINE_GGO_HRGB_BITMAP;
1037 break;
1038 case AA_BGR:
1039 ggo_format |= WINE_GGO_HBGR_BITMAP;
1040 break;
1041 case AA_VRGB:
1042 ggo_format |= WINE_GGO_VRGB_BITMAP;
1043 break;
1044 case AA_VBGR:
1045 ggo_format |= WINE_GGO_VBGR_BITMAP;
1046 break;
1048 default:
1049 ERR("aa = %d - not implemented\n", format);
1050 case AA_None:
1051 ggo_format |= GGO_BITMAP;
1052 break;
1055 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1056 if(buflen == GDI_ERROR) {
1057 if(format != AA_None) {
1058 format = AA_None;
1059 entry->aa_default = AA_None;
1060 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1061 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1063 if(buflen == GDI_ERROR) {
1064 WARN("GetGlyphOutlineW failed using default glyph\n");
1065 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1066 if(buflen == GDI_ERROR) {
1067 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1068 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1069 if(buflen == GDI_ERROR) {
1070 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1071 return;
1075 TRACE("Turning off antialiasing for this monochrome font\n");
1078 /* If there is nothing for the current type, we create the entry. */
1079 if( !entry->format[format] ) {
1080 entry->format[format] = HeapAlloc(GetProcessHeap(),
1081 HEAP_ZERO_MEMORY,
1082 sizeof(gsCacheEntryFormat));
1084 formatEntry = entry->format[format];
1086 if(formatEntry->nrealized <= glyph) {
1087 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1089 if (formatEntry->realized)
1090 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1091 HEAP_ZERO_MEMORY,
1092 formatEntry->realized,
1093 formatEntry->nrealized * sizeof(BOOL));
1094 else
1095 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1096 HEAP_ZERO_MEMORY,
1097 formatEntry->nrealized * sizeof(BOOL));
1099 if (formatEntry->gis)
1100 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1101 HEAP_ZERO_MEMORY,
1102 formatEntry->gis,
1103 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1104 else
1105 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1106 HEAP_ZERO_MEMORY,
1107 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1111 if(formatEntry->glyphset == 0) {
1112 switch(format) {
1113 case AA_Grey:
1114 wxr_format = WXR_FORMAT_GRAY;
1115 break;
1117 case AA_RGB:
1118 case AA_BGR:
1119 case AA_VRGB:
1120 case AA_VBGR:
1121 wxr_format = WXR_FORMAT_A8R8G8B8;
1122 break;
1124 default:
1125 ERR("aa = %d - not implemented\n", format);
1126 case AA_None:
1127 wxr_format = WXR_FORMAT_MONO;
1128 break;
1131 formatEntry->font_format = pict_formats[wxr_format];
1132 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1136 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1137 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1138 formatEntry->realized[glyph] = TRUE;
1140 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1141 buflen,
1142 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1143 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1145 gi.width = gm.gmBlackBoxX;
1146 gi.height = gm.gmBlackBoxY;
1147 gi.x = -gm.gmptGlyphOrigin.x;
1148 gi.y = gm.gmptGlyphOrigin.y;
1149 gi.xOff = gm.gmCellIncX;
1150 gi.yOff = gm.gmCellIncY;
1152 if(TRACE_ON(xrender)) {
1153 int pitch, i, j;
1154 char output[300];
1155 unsigned char *line;
1157 if(format == AA_None) {
1158 pitch = ((gi.width + 31) / 32) * 4;
1159 for(i = 0; i < gi.height; i++) {
1160 line = (unsigned char*) buf + i * pitch;
1161 output[0] = '\0';
1162 for(j = 0; j < pitch * 8; j++) {
1163 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1165 TRACE("%s\n", output);
1167 } else {
1168 static const char blks[] = " .:;!o*#";
1169 char str[2];
1171 str[1] = '\0';
1172 pitch = ((gi.width + 3) / 4) * 4;
1173 for(i = 0; i < gi.height; i++) {
1174 line = (unsigned char*) buf + i * pitch;
1175 output[0] = '\0';
1176 for(j = 0; j < pitch; j++) {
1177 str[0] = blks[line[j] >> 5];
1178 strcat(output, str);
1180 TRACE("%s\n", output);
1186 if(formatEntry->glyphset) {
1187 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1188 unsigned char *byte = (unsigned char*) buf, c;
1189 int i = buflen;
1191 while(i--) {
1192 c = *byte;
1194 /* magic to flip bit order */
1195 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1196 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1197 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1199 *byte++ = c;
1202 else if ( format != AA_Grey &&
1203 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1205 unsigned int i, *data = (unsigned int *)buf;
1206 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1208 gid = glyph;
1211 XRenderCompositeText seems to ignore 0x0 glyphs when
1212 AA_None, which means we lose the advance width of glyphs
1213 like the space. We'll pretend that such glyphs are 1x1
1214 bitmaps.
1217 if(buflen == 0)
1218 gi.width = gi.height = 1;
1220 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1221 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1224 HeapFree(GetProcessHeap(), 0, buf);
1225 formatEntry->gis[glyph] = gi;
1228 /*************************************************************
1229 * get_tile_pict
1231 * Returns an appropriate Picture for tiling the text colour.
1232 * Call and use result within the xrender_cs
1234 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1236 static struct
1238 Pixmap xpm;
1239 Picture pict;
1240 XRenderColor current_color;
1241 } tiles[WXR_NB_FORMATS], *tile;
1243 tile = &tiles[wxr_format];
1245 if(!tile->xpm)
1247 XRenderPictureAttributes pa;
1248 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1250 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1252 pa.repeat = RepeatNormal;
1253 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1255 /* init current_color to something different from text_pixel */
1256 tile->current_color = *color;
1257 tile->current_color.red ^= 0xffff;
1259 if (wxr_format == WXR_FORMAT_MONO)
1261 /* for a 1bpp bitmap we always need a 1 in the tile */
1262 XRenderColor col;
1263 col.red = col.green = col.blue = 0;
1264 col.alpha = 0xffff;
1265 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1269 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1271 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1272 tile->current_color = *color;
1274 return tile->pict;
1277 /*************************************************************
1278 * get_mask_pict
1280 * Returns an appropriate Picture for masking with the specified alpha.
1281 * Call and use result within the xrender_cs
1283 static Picture get_mask_pict( int alpha )
1285 static Pixmap pixmap;
1286 static Picture pict;
1287 static int current_alpha;
1289 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1291 if (!pixmap)
1293 XRenderPictureAttributes pa;
1295 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1296 pa.repeat = RepeatNormal;
1297 pict = pXRenderCreatePicture( gdi_display, pixmap,
1298 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1299 current_alpha = -1;
1302 if (alpha != current_alpha)
1304 XRenderColor col;
1305 col.red = col.green = col.blue = 0;
1306 col.alpha = current_alpha = alpha;
1307 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1309 return pict;
1312 /***********************************************************************
1313 * xrenderdrv_ExtTextOut
1315 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1316 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1318 struct xrender_physdev *physdev = get_xrender_dev( dev );
1319 gsCacheEntry *entry;
1320 gsCacheEntryFormat *formatEntry;
1321 AA_Type aa_type = AA_None;
1322 unsigned int idx;
1323 Picture pict, tile_pict = 0;
1324 XGlyphElt16 *elts;
1325 POINT offset, desired, current;
1326 int render_op = PictOpOver;
1327 XRenderColor col;
1328 RECT rect, bounds;
1330 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1331 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1333 if(flags & ETO_OPAQUE)
1335 XRenderColor bg;
1337 if (physdev->format == WXR_FORMAT_MONO)
1338 /* use the inverse of the text color */
1339 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1340 else
1341 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1343 set_xrender_transformation( pict, 1, 1, 0, 0 );
1344 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1345 physdev->x11dev->dc_rect.left + lprect->left,
1346 physdev->x11dev->dc_rect.top + lprect->top,
1347 lprect->right - lprect->left,
1348 lprect->bottom - lprect->top );
1349 add_device_bounds( physdev->x11dev, lprect );
1352 if(count == 0) return TRUE;
1354 EnterCriticalSection(&xrender_cs);
1356 entry = glyphsetCache + physdev->cache_index;
1357 aa_type = entry->aa_default;
1358 formatEntry = entry->format[aa_type];
1360 for(idx = 0; idx < count; idx++) {
1361 if( !formatEntry ) {
1362 UploadGlyph(physdev, wstr[idx], aa_type);
1363 /* re-evaluate antialias since aa_default may have changed */
1364 aa_type = entry->aa_default;
1365 formatEntry = entry->format[aa_type];
1366 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1367 UploadGlyph(physdev, wstr[idx], aa_type);
1370 if (!formatEntry)
1372 WARN("could not upload requested glyphs\n");
1373 LeaveCriticalSection(&xrender_cs);
1374 return FALSE;
1377 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1378 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1380 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1382 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1383 So we pass zeros to the function and move to our starting position using the first
1384 element of the elts array. */
1386 desired.x = physdev->x11dev->dc_rect.left + x;
1387 desired.y = physdev->x11dev->dc_rect.top + y;
1388 offset.x = offset.y = 0;
1389 current.x = current.y = 0;
1391 tile_pict = get_tile_pict(physdev->format, &col);
1393 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1395 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1396 render_op = PictOpOutReverse; /* This gives us 'black' text */
1398 reset_bounds( &bounds );
1399 for(idx = 0; idx < count; idx++)
1401 elts[idx].glyphset = formatEntry->glyphset;
1402 elts[idx].chars = wstr + idx;
1403 elts[idx].nchars = 1;
1404 elts[idx].xOff = desired.x - current.x;
1405 elts[idx].yOff = desired.y - current.y;
1407 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1408 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1410 rect.left = desired.x - physdev->x11dev->dc_rect.left - formatEntry->gis[wstr[idx]].x;
1411 rect.top = desired.y - physdev->x11dev->dc_rect.top - formatEntry->gis[wstr[idx]].y;
1412 rect.right = rect.left + formatEntry->gis[wstr[idx]].width;
1413 rect.bottom = rect.top + formatEntry->gis[wstr[idx]].height;
1414 add_bounds_rect( &bounds, &rect );
1416 if(!lpDx)
1418 desired.x += formatEntry->gis[wstr[idx]].xOff;
1419 desired.y += formatEntry->gis[wstr[idx]].yOff;
1421 else
1423 if(flags & ETO_PDY)
1425 offset.x += lpDx[idx * 2];
1426 offset.y += lpDx[idx * 2 + 1];
1428 else
1429 offset.x += lpDx[idx];
1430 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1431 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1435 /* Make sure we don't have any transforms set from a previous call */
1436 set_xrender_transformation(pict, 1, 1, 0, 0);
1437 pXRenderCompositeText16(gdi_display, render_op,
1438 tile_pict,
1439 pict,
1440 formatEntry->font_format,
1441 0, 0, 0, 0, elts, count);
1442 HeapFree(GetProcessHeap(), 0, elts);
1444 LeaveCriticalSection(&xrender_cs);
1445 add_device_bounds( physdev->x11dev, &bounds );
1446 return TRUE;
1449 /* multiply the alpha channel of a picture */
1450 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1451 int x, int y, int width, int height )
1453 XRenderPictureAttributes pa;
1454 Pixmap src_pixmap, mask_pixmap;
1455 Picture src_pict, mask_pict;
1456 XRenderColor color;
1458 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1459 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1460 pa.repeat = RepeatNormal;
1461 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1462 pa.component_alpha = True;
1463 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1464 color.red = color.green = color.blue = color.alpha = 0xffff;
1465 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1466 color.alpha = alpha;
1467 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1468 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1469 0, 0, 0, 0, x, y, width, height );
1470 pXRenderFreePicture( gdi_display, src_pict );
1471 pXRenderFreePicture( gdi_display, mask_pict );
1472 XFreePixmap( gdi_display, src_pixmap );
1473 XFreePixmap( gdi_display, mask_pixmap );
1476 /* Helper function for (stretched) blitting using xrender */
1477 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1478 int x_src, int y_src, int width_src, int height_src,
1479 int x_dst, int y_dst, int width_dst, int height_dst,
1480 double xscale, double yscale )
1482 int x_offset, y_offset;
1484 if (width_src < 0)
1486 x_src += width_src + 1;
1487 width_src = -width_src;
1489 if (height_src < 0)
1491 y_src += height_src + 1;
1492 height_src = -height_src;
1494 if (width_dst < 0)
1496 x_dst += width_dst + 1;
1497 width_dst = -width_dst;
1499 if (height_dst < 0)
1501 y_dst += height_dst + 1;
1502 height_dst = -height_dst;
1505 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1506 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1507 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1508 if(xscale != 1.0 || yscale != 1.0)
1510 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1511 * in the wrong quadrant of the x-y plane.
1513 x_offset = (xscale < 0) ? -width_dst : 0;
1514 y_offset = (yscale < 0) ? -height_dst : 0;
1515 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1517 else
1519 x_offset = x_src;
1520 y_offset = y_src;
1521 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1523 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1524 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1527 /* Helper function for (stretched) mono->color blitting using xrender */
1528 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1529 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1530 int x_src, int y_src, int width_src, int height_src,
1531 int x_dst, int y_dst, int width_dst, int height_dst,
1532 double xscale, double yscale )
1534 Picture tile_pict;
1535 int x_offset, y_offset;
1536 XRenderColor color;
1538 if (width_src < 0)
1540 x_src += width_src + 1;
1541 width_src = -width_src;
1543 if (height_src < 0)
1545 y_src += height_src + 1;
1546 height_src = -height_src;
1548 if (width_dst < 0)
1550 x_dst += width_dst + 1;
1551 width_dst = -width_dst;
1553 if (height_dst < 0)
1555 y_dst += height_dst + 1;
1556 height_dst = -height_dst;
1559 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1560 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1561 * the tile data.
1563 EnterCriticalSection( &xrender_cs );
1564 color = *bg;
1565 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1566 tile_pict = get_tile_pict( dst_format, &color );
1568 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1570 if (xscale != 1.0 || yscale != 1.0)
1572 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1573 * in the wrong quadrant of the x-y plane.
1575 x_offset = (xscale < 0) ? -width_dst : 0;
1576 y_offset = (yscale < 0) ? -height_dst : 0;
1577 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1579 else
1581 x_offset = x_src;
1582 y_offset = y_src;
1583 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1585 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1586 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1587 LeaveCriticalSection( &xrender_cs );
1589 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1590 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1591 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1592 x_dst, y_dst, width_dst, height_dst );
1595 /* create a pixmap and render picture for an image */
1596 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1597 struct bitblt_coords *src, enum wxr_format format,
1598 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1600 DWORD ret;
1601 int width = src->visrect.right - src->visrect.left;
1602 int height = src->visrect.bottom - src->visrect.top;
1603 int depth = pict_formats[format]->depth;
1604 struct gdi_image_bits dst_bits;
1605 XRenderPictureAttributes pa;
1606 GC gc;
1607 XImage *image;
1609 image = XCreateImage( gdi_display, default_visual.visual, depth, ZPixmap, 0, NULL,
1610 info->bmiHeader.biWidth, height, 32, 0 );
1611 if (!image) return ERROR_OUTOFMEMORY;
1613 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1614 if (ret) return ret;
1616 image->data = dst_bits.ptr;
1618 *use_repeat = (width == 1 && height == 1);
1619 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1621 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1622 gc = XCreateGC( gdi_display, *pixmap, 0, NULL );
1623 XPutImage( gdi_display, *pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1624 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1625 XFreeGC( gdi_display, gc );
1627 /* make coordinates relative to the pixmap */
1628 src->x -= src->visrect.left;
1629 src->y -= src->visrect.top;
1630 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1632 image->data = NULL;
1633 XDestroyImage( image );
1634 if (dst_bits.free) dst_bits.free( &dst_bits );
1635 return ret;
1638 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1639 Drawable drawable, const struct bitblt_coords *src,
1640 const struct bitblt_coords *dst )
1642 int x_dst, y_dst;
1643 Picture src_pict = 0, dst_pict, mask_pict = 0;
1644 double xscale = src->width / (double)dst->width;
1645 double yscale = src->height / (double)dst->height;
1647 if (drawable) /* using an intermediate pixmap */
1649 x_dst = dst->x;
1650 y_dst = dst->y;
1651 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, 0, NULL );
1653 else
1655 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
1656 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
1657 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1660 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1662 /* mono -> color */
1663 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1665 XRenderColor fg, bg;
1667 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
1668 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
1669 fg.alpha = bg.alpha = 0;
1671 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
1672 physdev_src->x11dev->dc_rect.left + src->x,
1673 physdev_src->x11dev->dc_rect.top + src->y,
1674 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1676 else /* color -> color (can be at different depths) or mono -> mono */
1678 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
1679 mask_pict = get_no_alpha_mask();
1681 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
1682 physdev_src->x11dev->dc_rect.left + src->x,
1683 physdev_src->x11dev->dc_rect.top + src->y,
1684 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1687 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1691 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
1692 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
1693 Drawable drawable, struct bitblt_coords *src,
1694 struct bitblt_coords *dst, BOOL use_repeat )
1696 int x_dst, y_dst;
1697 Picture dst_pict;
1698 double xscale, yscale;
1700 if (drawable) /* using an intermediate pixmap */
1702 RGNDATA *clip_data = NULL;
1704 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1705 x_dst = dst->x;
1706 y_dst = dst->y;
1707 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL );
1708 if (clip_data)
1709 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
1710 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
1711 HeapFree( GetProcessHeap(), 0, clip_data );
1713 else
1715 x_dst = physdev->x11dev->dc_rect.left + dst->x;
1716 y_dst = physdev->x11dev->dc_rect.top + dst->y;
1717 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
1720 if (!use_repeat)
1722 xscale = src->width / (double)dst->width;
1723 yscale = src->height / (double)dst->height;
1725 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1727 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
1728 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1730 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1734 /***********************************************************************
1735 * xrenderdrv_StretchBlt
1737 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1738 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1740 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1741 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1742 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
1744 if (src_dev->funcs != dst_dev->funcs)
1746 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
1747 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
1750 /* XRender is of no use for color -> mono */
1751 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
1752 goto x11drv_fallback;
1754 /* if not stretching, we only need to handle format conversion */
1755 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
1757 if (rop != SRCCOPY)
1759 GC tmpGC;
1760 Pixmap tmp_pixmap;
1761 struct bitblt_coords tmp;
1763 /* make coordinates relative to tmp pixmap */
1764 tmp = *dst;
1765 tmp.x -= tmp.visrect.left;
1766 tmp.y -= tmp.visrect.top;
1767 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1769 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
1770 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1771 XSetGraphicsExposures( gdi_display, tmpGC, False );
1772 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
1773 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
1775 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
1776 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
1778 XFreePixmap( gdi_display, tmp_pixmap );
1779 XFreeGC( gdi_display, tmpGC );
1781 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
1783 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
1784 return TRUE;
1786 x11drv_fallback:
1787 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
1791 /***********************************************************************
1792 * xrenderdrv_PutImage
1794 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1795 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1796 struct bitblt_coords *dst, DWORD rop )
1798 struct xrender_physdev *physdev = get_xrender_dev( dev );
1799 DWORD ret;
1800 Pixmap tmp_pixmap;
1801 GC gc;
1802 enum wxr_format src_format, dst_format;
1803 XRenderPictFormat *pict_format;
1804 Pixmap src_pixmap;
1805 Picture src_pict, mask_pict = 0;
1806 BOOL use_repeat;
1808 dst_format = physdev->format;
1809 src_format = get_xrender_format_from_bitmapinfo( info );
1810 if (!(pict_format = pict_formats[src_format])) goto update_format;
1812 /* make sure we can create an image with the same bpp */
1813 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
1814 goto update_format;
1816 /* mono <-> color conversions not supported */
1817 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
1818 goto x11drv_fallback;
1820 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1822 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
1824 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
1825 if (!ret)
1827 struct bitblt_coords tmp;
1829 if (rop != SRCCOPY)
1831 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
1833 /* make coordinates relative to tmp pixmap */
1834 tmp = *dst;
1835 tmp.x -= tmp.visrect.left;
1836 tmp.y -= tmp.visrect.top;
1837 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1839 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
1840 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1841 XSetGraphicsExposures( gdi_display, gc, False );
1842 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
1843 tmp.visrect.right - tmp.visrect.left,
1844 tmp.visrect.bottom - tmp.visrect.top,
1845 physdev->pict_format->depth );
1847 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
1848 NULL, tmp_pixmap, src, &tmp, use_repeat );
1849 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
1851 XFreePixmap( gdi_display, tmp_pixmap );
1852 XFreeGC( gdi_display, gc );
1853 if (restore_region) restore_clipping_region( physdev->x11dev );
1855 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
1856 physdev->pict_format, physdev, 0, src, dst, use_repeat );
1858 add_device_bounds( physdev->x11dev, &dst->visrect );
1860 pXRenderFreePicture( gdi_display, src_pict );
1861 XFreePixmap( gdi_display, src_pixmap );
1863 return ret;
1865 update_format:
1866 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1867 set_color_info( pict_formats[dst_format], info );
1868 return ERROR_BAD_FORMAT;
1870 x11drv_fallback:
1871 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
1872 return dev->funcs->pPutImage( dev, clip, info, bits, src, dst, rop );
1876 /***********************************************************************
1877 * xrenderdrv_BlendImage
1879 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
1880 struct bitblt_coords *src, struct bitblt_coords *dst,
1881 BLENDFUNCTION func )
1883 struct xrender_physdev *physdev = get_xrender_dev( dev );
1884 DWORD ret;
1885 enum wxr_format format;
1886 XRenderPictFormat *pict_format;
1887 Picture dst_pict, src_pict, mask_pict;
1888 Pixmap src_pixmap;
1889 BOOL use_repeat;
1891 format = get_xrender_format_from_bitmapinfo( info );
1892 if (!(func.AlphaFormat & AC_SRC_ALPHA))
1893 format = get_format_without_alpha( format );
1894 else if (format != WXR_FORMAT_A8R8G8B8 || info->bmiHeader.biCompression != BI_RGB)
1895 return ERROR_INVALID_PARAMETER;
1897 if (!(pict_format = pict_formats[format])) goto update_format;
1899 /* make sure we can create an image with the same bpp */
1900 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
1901 goto update_format;
1903 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
1904 goto update_format;
1906 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1908 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
1909 if (!ret)
1911 double xscale, yscale;
1913 if (!use_repeat)
1915 xscale = src->width / (double)dst->width;
1916 yscale = src->height / (double)dst->height;
1918 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1920 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
1922 EnterCriticalSection( &xrender_cs );
1923 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
1925 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
1926 src->x, src->y, src->width, src->height,
1927 physdev->x11dev->dc_rect.left + dst->x,
1928 physdev->x11dev->dc_rect.top + dst->y,
1929 dst->width, dst->height, xscale, yscale );
1931 pXRenderFreePicture( gdi_display, src_pict );
1932 XFreePixmap( gdi_display, src_pixmap );
1934 LeaveCriticalSection( &xrender_cs );
1935 add_device_bounds( physdev->x11dev, &dst->visrect );
1937 return ret;
1939 update_format:
1940 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1941 set_color_info( physdev->pict_format, info );
1942 return ERROR_BAD_FORMAT;
1946 /***********************************************************************
1947 * xrenderdrv_AlphaBlend
1949 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
1950 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
1952 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1953 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1954 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
1955 XRenderPictureAttributes pa;
1956 Pixmap tmp_pixmap = 0;
1957 double xscale, yscale;
1959 if (src_dev->funcs != dst_dev->funcs)
1961 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
1962 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
1965 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
1967 SetLastError( ERROR_INVALID_PARAMETER );
1968 return FALSE;
1971 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1973 xscale = src->width / (double)dst->width;
1974 yscale = src->height / (double)dst->height;
1976 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1978 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1980 /* mono -> color blending needs an intermediate color pixmap */
1981 XRenderColor fg, bg;
1982 int width = src->visrect.right - src->visrect.left;
1983 int height = src->visrect.bottom - src->visrect.top;
1985 /* blending doesn't use the destination DC colors */
1986 fg.red = fg.green = fg.blue = 0;
1987 bg.red = bg.green = bg.blue = 0xffff;
1988 fg.alpha = bg.alpha = 0xffff;
1990 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
1991 physdev_dst->pict_format->depth );
1992 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format, 0, NULL );
1994 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
1995 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
1997 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
1999 /* we need a source picture with no alpha */
2000 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2001 if (format != physdev_src->format)
2003 pa.subwindow_mode = IncludeInferiors;
2004 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2005 pict_formats[format], CPSubwindowMode, &pa );
2009 if (tmp_pict) src_pict = tmp_pict;
2011 EnterCriticalSection( &xrender_cs );
2012 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2014 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2015 physdev_src->x11dev->dc_rect.left + src->x,
2016 physdev_src->x11dev->dc_rect.top + src->y,
2017 src->width, src->height,
2018 physdev_dst->x11dev->dc_rect.left + dst->x,
2019 physdev_dst->x11dev->dc_rect.top + dst->y,
2020 dst->width, dst->height, xscale, yscale );
2022 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2023 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2025 LeaveCriticalSection( &xrender_cs );
2026 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2027 return TRUE;
2030 /***********************************************************************
2031 * xrenderdrv_GradientFill
2033 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2034 void * grad_array, ULONG ngrad, ULONG mode )
2036 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2037 static const XFixed stops[2] = { 0, 1 << 16 };
2038 struct xrender_physdev *physdev = get_xrender_dev( dev );
2039 XLinearGradient gradient;
2040 XRenderColor colors[2];
2041 Picture src_pict, dst_pict;
2042 unsigned int i;
2043 const GRADIENT_RECT *rect = grad_array;
2044 RECT rc;
2045 POINT pt[2];
2047 if (!pXRenderCreateLinearGradient) goto fallback;
2049 /* <= 16-bpp uses dithering */
2050 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2052 switch (mode)
2054 case GRADIENT_FILL_RECT_H:
2055 case GRADIENT_FILL_RECT_V:
2056 for (i = 0; i < ngrad; i++, rect++)
2058 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2059 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2061 colors[0].red = v1->Red * 257 / 256;
2062 colors[0].green = v1->Green * 257 / 256;
2063 colors[0].blue = v1->Blue * 257 / 256;
2064 colors[1].red = v2->Red * 257 / 256;
2065 colors[1].green = v2->Green * 257 / 256;
2066 colors[1].blue = v2->Blue * 257 / 256;
2067 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2068 colors[0].alpha = colors[1].alpha = 65535;
2070 pt[0].x = v1->x;
2071 pt[0].y = v1->y;
2072 pt[1].x = v2->x;
2073 pt[1].y = v2->y;
2074 LPtoDP( dev->hdc, pt, 2 );
2075 if (mode == GRADIENT_FILL_RECT_H)
2077 gradient.p1.y = gradient.p2.y = 0;
2078 if (pt[1].x > pt[0].x)
2080 gradient.p1.x = 0;
2081 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2083 else
2085 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2086 gradient.p2.x = 0;
2089 else
2091 gradient.p1.x = gradient.p2.x = 0;
2092 if (pt[1].y > pt[0].y)
2094 gradient.p1.y = 0;
2095 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2097 else
2099 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2100 gradient.p2.y = 0;
2104 rc.left = min( pt[0].x, pt[1].x );
2105 rc.top = min( pt[0].y, pt[1].y );
2106 rc.right = max( pt[0].x, pt[1].x );
2107 rc.bottom = max( pt[0].y, pt[1].y );
2109 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2110 mode, wine_dbgstr_rect( &rc ),
2111 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2112 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2114 dst_pict = get_xrender_picture( physdev, 0, NULL );
2116 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2117 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2118 0, 0, rc.right - rc.left, rc.bottom - rc.top,
2119 physdev->x11dev->dc_rect.left + rc.left,
2120 physdev->x11dev->dc_rect.top + rc.top,
2121 rc.right - rc.left, rc.bottom - rc.top, 1, 1 );
2122 pXRenderFreePicture( gdi_display, src_pict );
2123 add_device_bounds( physdev->x11dev, &rc );
2125 return TRUE;
2128 fallback:
2129 #endif
2130 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2131 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2134 /***********************************************************************
2135 * xrenderdrv_SelectBrush
2137 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2139 struct xrender_physdev *physdev = get_xrender_dev( dev );
2140 Pixmap pixmap;
2141 XVisualInfo vis = default_visual;
2142 XRenderPictFormat *format = physdev->pict_format;
2144 if (!pattern) goto x11drv_fallback;
2145 if (pattern->info->bmiHeader.biBitCount == 1) goto x11drv_fallback;
2146 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2148 vis.depth = format->depth;
2149 vis.red_mask = format->direct.redMask << format->direct.red;
2150 vis.green_mask = format->direct.greenMask << format->direct.green;
2151 vis.blue_mask = format->direct.blueMask << format->direct.blue;
2153 pixmap = create_pixmap_from_image( physdev->dev.hdc, &vis, pattern->info,
2154 &pattern->bits, pattern->usage );
2155 if (!pixmap) return 0;
2157 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2158 physdev->x11dev->brush.pixmap = pixmap;
2159 physdev->x11dev->brush.fillStyle = FillTiled;
2160 physdev->x11dev->brush.pixel = 0; /* ignored */
2161 physdev->x11dev->brush.style = BS_PATTERN;
2162 return hbrush;
2164 x11drv_fallback:
2165 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2166 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2170 static const struct gdi_dc_funcs xrender_funcs =
2172 NULL, /* pAbortDoc */
2173 NULL, /* pAbortPath */
2174 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2175 NULL, /* pAngleArc */
2176 NULL, /* pArc */
2177 NULL, /* pArcTo */
2178 NULL, /* pBeginPath */
2179 xrenderdrv_BlendImage, /* pBlendImage */
2180 NULL, /* pChord */
2181 NULL, /* pCloseFigure */
2182 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2183 xrenderdrv_CreateDC, /* pCreateDC */
2184 xrenderdrv_DeleteDC, /* pDeleteDC */
2185 NULL, /* pDeleteObject */
2186 NULL, /* pDeviceCapabilities */
2187 NULL, /* pEllipse */
2188 NULL, /* pEndDoc */
2189 NULL, /* pEndPage */
2190 NULL, /* pEndPath */
2191 NULL, /* pEnumFonts */
2192 NULL, /* pEnumICMProfiles */
2193 NULL, /* pExcludeClipRect */
2194 NULL, /* pExtDeviceMode */
2195 xrenderdrv_ExtEscape, /* pExtEscape */
2196 NULL, /* pExtFloodFill */
2197 NULL, /* pExtSelectClipRgn */
2198 xrenderdrv_ExtTextOut, /* pExtTextOut */
2199 NULL, /* pFillPath */
2200 NULL, /* pFillRgn */
2201 NULL, /* pFlattenPath */
2202 NULL, /* pFontIsLinked */
2203 NULL, /* pFrameRgn */
2204 NULL, /* pGdiComment */
2205 NULL, /* pGdiRealizationInfo */
2206 NULL, /* pGetBoundsRect */
2207 NULL, /* pGetCharABCWidths */
2208 NULL, /* pGetCharABCWidthsI */
2209 NULL, /* pGetCharWidth */
2210 NULL, /* pGetDeviceCaps */
2211 NULL, /* pGetDeviceGammaRamp */
2212 NULL, /* pGetFontData */
2213 NULL, /* pGetFontUnicodeRanges */
2214 NULL, /* pGetGlyphIndices */
2215 NULL, /* pGetGlyphOutline */
2216 NULL, /* pGetICMProfile */
2217 NULL, /* pGetImage */
2218 NULL, /* pGetKerningPairs */
2219 NULL, /* pGetNearestColor */
2220 NULL, /* pGetOutlineTextMetrics */
2221 NULL, /* pGetPixel */
2222 NULL, /* pGetSystemPaletteEntries */
2223 NULL, /* pGetTextCharsetInfo */
2224 NULL, /* pGetTextExtentExPoint */
2225 NULL, /* pGetTextExtentExPointI */
2226 NULL, /* pGetTextFace */
2227 NULL, /* pGetTextMetrics */
2228 xrenderdrv_GradientFill, /* pGradientFill */
2229 NULL, /* pIntersectClipRect */
2230 NULL, /* pInvertRgn */
2231 NULL, /* pLineTo */
2232 NULL, /* pModifyWorldTransform */
2233 NULL, /* pMoveTo */
2234 NULL, /* pOffsetClipRgn */
2235 NULL, /* pOffsetViewportOrg */
2236 NULL, /* pOffsetWindowOrg */
2237 NULL, /* pPaintRgn */
2238 NULL, /* pPatBlt */
2239 NULL, /* pPie */
2240 NULL, /* pPolyBezier */
2241 NULL, /* pPolyBezierTo */
2242 NULL, /* pPolyDraw */
2243 NULL, /* pPolyPolygon */
2244 NULL, /* pPolyPolyline */
2245 NULL, /* pPolygon */
2246 NULL, /* pPolyline */
2247 NULL, /* pPolylineTo */
2248 xrenderdrv_PutImage, /* pPutImage */
2249 NULL, /* pRealizeDefaultPalette */
2250 NULL, /* pRealizePalette */
2251 NULL, /* pRectangle */
2252 NULL, /* pResetDC */
2253 NULL, /* pRestoreDC */
2254 NULL, /* pRoundRect */
2255 NULL, /* pSaveDC */
2256 NULL, /* pScaleViewportExt */
2257 NULL, /* pScaleWindowExt */
2258 NULL, /* pSelectBitmap */
2259 xrenderdrv_SelectBrush, /* pSelectBrush */
2260 NULL, /* pSelectClipPath */
2261 xrenderdrv_SelectFont, /* pSelectFont */
2262 NULL, /* pSelectPalette */
2263 NULL, /* pSelectPen */
2264 NULL, /* pSetArcDirection */
2265 NULL, /* pSetBkColor */
2266 NULL, /* pSetBkMode */
2267 NULL, /* pSetBoundsRect */
2268 NULL, /* pSetDCBrushColor */
2269 NULL, /* pSetDCPenColor */
2270 NULL, /* pSetDIBitsToDevice */
2271 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2272 NULL, /* pSetDeviceGammaRamp */
2273 NULL, /* pSetLayout */
2274 NULL, /* pSetMapMode */
2275 NULL, /* pSetMapperFlags */
2276 NULL, /* pSetPixel */
2277 NULL, /* pSetPolyFillMode */
2278 NULL, /* pSetROP2 */
2279 NULL, /* pSetRelAbs */
2280 NULL, /* pSetStretchBltMode */
2281 NULL, /* pSetTextAlign */
2282 NULL, /* pSetTextCharacterExtra */
2283 NULL, /* pSetTextColor */
2284 NULL, /* pSetTextJustification */
2285 NULL, /* pSetViewportExt */
2286 NULL, /* pSetViewportOrg */
2287 NULL, /* pSetWindowExt */
2288 NULL, /* pSetWindowOrg */
2289 NULL, /* pSetWorldTransform */
2290 NULL, /* pStartDoc */
2291 NULL, /* pStartPage */
2292 xrenderdrv_StretchBlt, /* pStretchBlt */
2293 NULL, /* pStretchDIBits */
2294 NULL, /* pStrokeAndFillPath */
2295 NULL, /* pStrokePath */
2296 NULL, /* pUnrealizePalette */
2297 NULL, /* pWidenPath */
2298 NULL, /* wine_get_wgl_driver */
2299 GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
2302 #else /* SONAME_LIBXRENDER */
2304 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2306 TRACE("XRender support not compiled in.\n");
2307 return NULL;
2310 #endif /* SONAME_LIBXRENDER */