widl: Generate helper macros for WinRT implementation.
[wine/zf.git] / dlls / winex11.drv / xrender.c
blob3376cee517d4163e88baf5b05f114987fc9ffe93
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/unicode.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
42 #ifdef SONAME_LIBXRENDER
44 WINE_DECLARE_DEBUG_CHANNEL(winediag);
46 #include <X11/Xlib.h>
47 #include <X11/extensions/Xrender.h>
49 #ifndef RepeatNone /* added in 0.10 */
50 #define RepeatNone 0
51 #define RepeatNormal 1
52 #define RepeatPad 2
53 #define RepeatReflect 3
54 #endif
56 enum wxr_format
58 WXR_FORMAT_MONO,
59 WXR_FORMAT_GRAY,
60 WXR_FORMAT_X1R5G5B5,
61 WXR_FORMAT_X1B5G5R5,
62 WXR_FORMAT_R5G6B5,
63 WXR_FORMAT_B5G6R5,
64 WXR_FORMAT_R8G8B8,
65 WXR_FORMAT_B8G8R8,
66 WXR_FORMAT_A8R8G8B8,
67 WXR_FORMAT_B8G8R8A8,
68 WXR_FORMAT_X8R8G8B8,
69 WXR_FORMAT_B8G8R8X8,
70 WXR_FORMAT_ROOT, /* placeholder for the format to use on the root window */
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 enum wxr_format default_format = WXR_INVALID_FORMAT;
106 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
108 typedef struct
110 LOGFONTW lf;
111 XFORM xform;
112 SIZE devsize; /* size in device coords */
113 DWORD hash;
114 } LFANDSIZE;
116 #define INITIAL_REALIZED_BUF_SIZE 128
118 enum glyph_type { GLYPH_INDEX, GLYPH_WCHAR, GLYPH_NBTYPES };
120 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
122 typedef struct
124 GlyphSet glyphset;
125 XRenderPictFormat *font_format;
126 int nrealized;
127 BOOL *realized;
128 XGlyphInfo *gis;
129 } gsCacheEntryFormat;
131 typedef struct
133 LFANDSIZE lfsz;
134 gsCacheEntryFormat *format[GLYPH_NBTYPES][AA_MAXVALUE];
135 INT count;
136 INT next;
137 } gsCacheEntry;
139 struct xrender_physdev
141 struct gdi_physdev dev;
142 X11DRV_PDEVICE *x11dev;
143 HRGN region;
144 enum wxr_format format;
145 UINT aa_flags;
146 int cache_index;
147 BOOL update_clip;
148 Picture pict;
149 Picture pict_src;
150 XRenderPictFormat *pict_format;
153 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
155 return (struct xrender_physdev *)dev;
158 static const struct gdi_dc_funcs xrender_funcs;
160 static gsCacheEntry *glyphsetCache = NULL;
161 static DWORD glyphsetCacheSize = 0;
162 static INT lastfree = -1;
163 static INT mru = -1;
165 #define INIT_CACHE_SIZE 10
167 static void *xrender_handle;
169 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
170 MAKE_FUNCPTR(XRenderAddGlyphs)
171 MAKE_FUNCPTR(XRenderChangePicture)
172 MAKE_FUNCPTR(XRenderComposite)
173 MAKE_FUNCPTR(XRenderCompositeText16)
174 MAKE_FUNCPTR(XRenderCreateGlyphSet)
175 MAKE_FUNCPTR(XRenderCreatePicture)
176 MAKE_FUNCPTR(XRenderFillRectangle)
177 MAKE_FUNCPTR(XRenderFindFormat)
178 MAKE_FUNCPTR(XRenderFindVisualFormat)
179 MAKE_FUNCPTR(XRenderFreeGlyphSet)
180 MAKE_FUNCPTR(XRenderFreePicture)
181 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
182 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
183 MAKE_FUNCPTR(XRenderCreateLinearGradient)
184 #endif
185 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
186 MAKE_FUNCPTR(XRenderSetPictureTransform)
187 #endif
188 MAKE_FUNCPTR(XRenderQueryExtension)
190 #undef MAKE_FUNCPTR
192 static CRITICAL_SECTION xrender_cs;
193 static CRITICAL_SECTION_DEBUG critsect_debug =
195 0, 0, &xrender_cs,
196 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
197 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
199 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
201 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
202 ( ( (ULONG)_x4 << 24 ) | \
203 ( (ULONG)_x3 << 16 ) | \
204 ( (ULONG)_x2 << 8 ) | \
205 (ULONG)_x1 )
207 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
209 #define GASP_GRIDFIT 0x01
210 #define GASP_DOGRAY 0x02
212 #ifdef WORDS_BIGENDIAN
213 #define get_be_word(x) (x)
214 #define NATIVE_BYTE_ORDER MSBFirst
215 #else
216 #define get_be_word(x) RtlUshortByteSwap(x)
217 #define NATIVE_BYTE_ORDER LSBFirst
218 #endif
220 static BOOL has_alpha( enum wxr_format format )
222 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
225 static enum wxr_format get_format_without_alpha( enum wxr_format format )
227 switch (format)
229 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
230 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
231 default: return format;
235 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
237 templ->id = 0;
238 templ->type = PictTypeDirect;
239 templ->depth = fmt->depth;
240 templ->direct.alpha = fmt->alpha;
241 templ->direct.alphaMask = fmt->alphaMask;
242 templ->direct.red = fmt->red;
243 templ->direct.redMask = fmt->redMask;
244 templ->direct.green = fmt->green;
245 templ->direct.greenMask = fmt->greenMask;
246 templ->direct.blue = fmt->blue;
247 templ->direct.blueMask = fmt->blueMask;
248 templ->colormap = 0;
250 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
252 return TRUE;
255 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
257 if(fmt->depth != default_visual.depth) return FALSE;
258 if( (fmt->redMask << fmt->red) != default_visual.red_mask) return FALSE;
259 if( (fmt->greenMask << fmt->green) != default_visual.green_mask) return FALSE;
260 if( (fmt->blueMask << fmt->blue) != default_visual.blue_mask) return FALSE;
262 /* We never select a default ARGB visual */
263 if(fmt->alphaMask) return FALSE;
264 return TRUE;
267 static int load_xrender_formats(void)
269 int count = 0;
270 unsigned int i;
272 for (i = 0; i < WXR_NB_FORMATS; i++)
274 XRenderPictFormat templ;
276 if (i == WXR_FORMAT_ROOT)
278 pict_formats[i] = pXRenderFindVisualFormat(gdi_display,
279 DefaultVisual( gdi_display, DefaultScreen(gdi_display) ));
280 TRACE( "Loaded root pict_format with id=%#lx\n", pict_formats[i]->id );
281 continue;
283 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
285 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, default_visual.visual);
286 if (!pict_formats[i])
288 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
289 if (default_visual.class == DirectColor)
291 XVisualInfo info;
292 if (XMatchVisualInfo( gdi_display, default_visual.screen,
293 default_visual.depth, TrueColor, &info ))
295 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
296 if (pict_formats[i]) default_visual = info;
300 if (pict_formats[i]) default_format = i;
302 else
304 unsigned long mask = 0;
305 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
306 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
308 if (pict_formats[i])
310 count++;
311 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
314 return count;
317 /***********************************************************************
318 * X11DRV_XRender_Init
320 * Let's see if our XServer has the extension available
323 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
325 int event_base, i;
327 if (!client_side_with_render) return NULL;
328 if (!(xrender_handle = dlopen(SONAME_LIBXRENDER, RTLD_NOW))) return NULL;
330 #define LOAD_FUNCPTR(f) if((p##f = dlsym(xrender_handle, #f)) == NULL) return NULL
331 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = dlsym(xrender_handle, #f)
332 LOAD_FUNCPTR(XRenderAddGlyphs);
333 LOAD_FUNCPTR(XRenderChangePicture);
334 LOAD_FUNCPTR(XRenderComposite);
335 LOAD_FUNCPTR(XRenderCompositeText16);
336 LOAD_FUNCPTR(XRenderCreateGlyphSet);
337 LOAD_FUNCPTR(XRenderCreatePicture);
338 LOAD_FUNCPTR(XRenderFillRectangle);
339 LOAD_FUNCPTR(XRenderFindFormat);
340 LOAD_FUNCPTR(XRenderFindVisualFormat);
341 LOAD_FUNCPTR(XRenderFreeGlyphSet);
342 LOAD_FUNCPTR(XRenderFreePicture);
343 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
344 LOAD_FUNCPTR(XRenderQueryExtension);
345 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
346 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
347 #endif
348 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
349 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
350 #endif
351 #undef LOAD_OPTIONAL_FUNCPTR
352 #undef LOAD_FUNCPTR
354 if (!pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) return NULL;
356 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
357 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
359 ERR_(winediag)("Wine has detected that you probably have a buggy version "
360 "of libXrender. Because of this client side font rendering "
361 "will be disabled. Please upgrade this library.\n");
362 return NULL;
365 if (!default_visual.red_mask || !default_visual.green_mask || !default_visual.blue_mask)
367 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
368 return NULL;
371 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
372 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
374 glyphsetCacheSize = INIT_CACHE_SIZE;
375 lastfree = 0;
376 for(i = 0; i < INIT_CACHE_SIZE; i++) {
377 glyphsetCache[i].next = i + 1;
378 glyphsetCache[i].count = -1;
380 glyphsetCache[i-1].next = -1;
382 return &xrender_funcs;
385 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
386 static void get_xrender_color( struct xrender_physdev *physdev, COLORREF src_color, XRenderColor *dst_color )
388 if (src_color & (1 << 24)) /* PALETTEINDEX */
390 HPALETTE pal = GetCurrentObject( physdev->dev.hdc, OBJ_PAL );
391 PALETTEENTRY pal_ent;
393 if (!GetPaletteEntries( pal, LOWORD(src_color), 1, &pal_ent ))
394 GetPaletteEntries( pal, 0, 1, &pal_ent );
395 dst_color->red = pal_ent.peRed * 257;
396 dst_color->green = pal_ent.peGreen * 257;
397 dst_color->blue = pal_ent.peBlue * 257;
399 else
401 if (src_color >> 16 == 0x10ff) src_color = 0; /* DIBINDEX */
403 dst_color->red = GetRValue( src_color ) * 257;
404 dst_color->green = GetGValue( src_color ) * 257;
405 dst_color->blue = GetBValue( src_color ) * 257;
408 if (physdev->format == WXR_FORMAT_MONO && !dst_color->red && !dst_color->green && !dst_color->blue)
409 dst_color->alpha = 0;
410 else
411 dst_color->alpha = 0xffff;
414 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
416 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
418 switch (info->bmiHeader.biBitCount)
420 case 1:
421 return WXR_FORMAT_MONO;
422 case 4:
423 case 8:
424 break;
425 case 24:
426 if (info->bmiHeader.biCompression != BI_RGB) break;
427 return WXR_FORMAT_R8G8B8;
428 case 16:
429 case 32:
430 if (info->bmiHeader.biCompression == BI_BITFIELDS)
432 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
433 unsigned int i;
435 for (i = 0; i < WXR_NB_FORMATS; i++)
437 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
438 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
439 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
440 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
441 return i;
443 break;
445 if (info->bmiHeader.biCompression != BI_RGB) break;
446 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
448 return WXR_INVALID_FORMAT;
451 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
452 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
454 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
455 XTransform xform = {{
456 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
457 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
458 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
461 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
462 #endif
465 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
467 XRenderPictureAttributes pa;
468 RGNDATA *data;
470 if (!rgn)
472 pa.clip_mask = None;
473 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
475 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
477 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
478 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
479 (XRectangle *)data->Buffer, data->rdh.nCount );
480 HeapFree( GetProcessHeap(), 0, data );
485 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
487 if (!dev->pict && dev->pict_format)
489 XRenderPictureAttributes pa;
491 pa.subwindow_mode = IncludeInferiors;
492 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
493 dev->pict_format, CPSubwindowMode, &pa );
494 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
495 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
496 dev->update_clip = (dev->region != 0);
499 if (clip_rect)
501 HRGN rgn = CreateRectRgnIndirect( clip_rect );
502 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
503 if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
504 update_xrender_clipping( dev, rgn );
505 DeleteObject( rgn );
507 else if (clip_rgn)
509 if (dev->region)
511 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
512 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
513 update_xrender_clipping( dev, rgn );
514 DeleteObject( rgn );
516 else update_xrender_clipping( dev, clip_rgn );
518 else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
520 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
521 return dev->pict;
524 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
526 if (!dev->pict_src && dev->pict_format)
528 XRenderPictureAttributes pa;
530 pa.subwindow_mode = IncludeInferiors;
531 pa.repeat = repeat ? RepeatNormal : RepeatNone;
532 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
533 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
535 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
536 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
539 return dev->pict_src;
542 static void free_xrender_picture( struct xrender_physdev *dev )
544 if (dev->pict || dev->pict_src)
546 XFlush( gdi_display );
547 if (dev->pict)
549 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
550 pXRenderFreePicture(gdi_display, dev->pict);
551 dev->pict = 0;
553 if(dev->pict_src)
555 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
556 pXRenderFreePicture(gdi_display, dev->pict_src);
557 dev->pict_src = 0;
562 /* return a mask picture used to force alpha to 0 */
563 static Picture get_no_alpha_mask(void)
565 static Pixmap pixmap;
566 static Picture pict;
568 EnterCriticalSection( &xrender_cs );
569 if (!pict)
571 XRenderPictureAttributes pa;
572 XRenderColor col;
574 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
575 pa.repeat = RepeatNormal;
576 pa.component_alpha = True;
577 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
578 CPRepeat|CPComponentAlpha, &pa );
579 col.red = col.green = col.blue = 0xffff;
580 col.alpha = 0;
581 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
583 LeaveCriticalSection( &xrender_cs );
584 return pict;
587 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
589 if(p1->hash != p2->hash) return TRUE;
590 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
591 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
592 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
593 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
596 static int LookupEntry(LFANDSIZE *plfsz)
598 int i, prev_i = -1;
600 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
601 TRACE("%d\n", i);
602 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
604 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
605 glyphsetCache[i].count++;
606 if(prev_i >= 0) {
607 glyphsetCache[prev_i].next = glyphsetCache[i].next;
608 glyphsetCache[i].next = mru;
609 mru = i;
611 TRACE("found font in cache %d\n", i);
612 return i;
614 prev_i = i;
616 TRACE("font not in cache\n");
617 return -1;
620 static void FreeEntry(int entry)
622 int type, format;
624 for (type = 0; type < GLYPH_NBTYPES; type++)
626 for(format = 0; format < AA_MAXVALUE; format++) {
627 gsCacheEntryFormat * formatEntry;
629 if( !glyphsetCache[entry].format[type][format] )
630 continue;
632 formatEntry = glyphsetCache[entry].format[type][format];
634 if(formatEntry->glyphset) {
635 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
636 formatEntry->glyphset = 0;
638 if(formatEntry->nrealized) {
639 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
640 formatEntry->realized = NULL;
641 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
642 formatEntry->gis = NULL;
643 formatEntry->nrealized = 0;
646 HeapFree(GetProcessHeap(), 0, formatEntry);
647 glyphsetCache[entry].format[type][format] = NULL;
652 static int AllocEntry(void)
654 int best = -1, prev_best = -1, i, prev_i = -1;
656 if(lastfree >= 0) {
657 assert(glyphsetCache[lastfree].count == -1);
658 glyphsetCache[lastfree].count = 1;
659 best = lastfree;
660 lastfree = glyphsetCache[lastfree].next;
661 assert(best != mru);
662 glyphsetCache[best].next = mru;
663 mru = best;
665 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
666 return mru;
669 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
670 if(glyphsetCache[i].count == 0) {
671 best = i;
672 prev_best = prev_i;
674 prev_i = i;
677 if(best >= 0) {
678 TRACE("freeing unused glyphset at cache %d\n", best);
679 FreeEntry(best);
680 glyphsetCache[best].count = 1;
681 if(prev_best >= 0) {
682 glyphsetCache[prev_best].next = glyphsetCache[best].next;
683 glyphsetCache[best].next = mru;
684 mru = best;
685 } else {
686 assert(mru == best);
688 return mru;
691 TRACE("Growing cache\n");
693 if (glyphsetCache)
694 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
695 glyphsetCache,
696 (glyphsetCacheSize + INIT_CACHE_SIZE)
697 * sizeof(*glyphsetCache));
698 else
699 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
700 (glyphsetCacheSize + INIT_CACHE_SIZE)
701 * sizeof(*glyphsetCache));
703 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
704 i++) {
705 glyphsetCache[i].next = i + 1;
706 glyphsetCache[i].count = -1;
708 glyphsetCache[i-1].next = -1;
709 glyphsetCacheSize += INIT_CACHE_SIZE;
711 lastfree = glyphsetCache[best].next;
712 glyphsetCache[best].count = 1;
713 glyphsetCache[best].next = mru;
714 mru = best;
715 TRACE("new free cache slot at %d\n", mru);
716 return mru;
719 static int GetCacheEntry( LFANDSIZE *plfsz )
721 int ret;
722 gsCacheEntry *entry;
724 if((ret = LookupEntry(plfsz)) != -1) return ret;
726 ret = AllocEntry();
727 entry = glyphsetCache + ret;
728 entry->lfsz = *plfsz;
729 return ret;
732 static void dec_ref_cache(int index)
734 assert(index >= 0);
735 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
736 assert(glyphsetCache[index].count > 0);
737 glyphsetCache[index].count--;
740 static void lfsz_calc_hash(LFANDSIZE *plfsz)
742 DWORD hash = 0, *ptr, two_chars;
743 WORD *pwc;
744 unsigned int i;
746 hash ^= plfsz->devsize.cx;
747 hash ^= plfsz->devsize.cy;
748 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
749 hash ^= *ptr;
750 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
751 hash ^= *ptr;
752 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
753 two_chars = *ptr;
754 pwc = (WCHAR *)&two_chars;
755 if(!*pwc) break;
756 *pwc = toupperW(*pwc);
757 pwc++;
758 *pwc = toupperW(*pwc);
759 hash ^= two_chars;
760 if(!*pwc) break;
762 plfsz->hash = hash;
763 return;
766 static AA_Type aa_type_from_flags( UINT aa_flags )
768 switch (aa_flags & 0x7f)
770 case GGO_BITMAP:
771 return AA_None;
772 case WINE_GGO_GRAY16_BITMAP:
773 return AA_Grey;
774 case WINE_GGO_HRGB_BITMAP:
775 return AA_RGB;
776 case WINE_GGO_HBGR_BITMAP:
777 return AA_BGR;
778 case WINE_GGO_VRGB_BITMAP:
779 return AA_VRGB;
780 case WINE_GGO_VBGR_BITMAP:
781 return AA_VBGR;
782 default:
783 FIXME( "unknown flags %x\n", aa_flags );
784 return AA_None;
788 static UINT get_xft_aa_flags( const LOGFONTW *lf )
790 char *value;
791 UINT ret = 0;
793 switch (lf->lfQuality)
795 case NONANTIALIASED_QUALITY:
796 case ANTIALIASED_QUALITY:
797 break;
798 default:
799 if (!(value = XGetDefault( gdi_display, "Xft", "antialias" ))) break;
800 TRACE( "got antialias '%s'\n", value );
801 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
802 value[0] == '0' || !_strnicmp( value, "off", -1 ))
804 ret = GGO_BITMAP;
805 break;
807 ret = GGO_GRAY4_BITMAP;
808 /* fall through */
809 case CLEARTYPE_QUALITY:
810 case CLEARTYPE_NATURAL_QUALITY:
811 if (!(value = XGetDefault( gdi_display, "Xft", "rgba" ))) break;
812 TRACE( "got rgba '%s'\n", value );
813 if (!strcmp( value, "rgb" )) ret = WINE_GGO_HRGB_BITMAP;
814 else if (!strcmp( value, "bgr" )) ret = WINE_GGO_HBGR_BITMAP;
815 else if (!strcmp( value, "vrgb" )) ret = WINE_GGO_VRGB_BITMAP;
816 else if (!strcmp( value, "vbgr" )) ret = WINE_GGO_VBGR_BITMAP;
817 else if (!strcmp( value, "none" )) ret = GGO_GRAY4_BITMAP;
818 break;
820 return ret;
823 /**********************************************************************
824 * xrenderdrv_SelectFont
826 static HFONT CDECL xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
828 LFANDSIZE lfsz;
829 struct xrender_physdev *physdev = get_xrender_dev( dev );
830 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
831 HFONT ret;
833 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
834 if (!*aa_flags) *aa_flags = get_xft_aa_flags( &lfsz.lf );
836 ret = next->funcs->pSelectFont( next, hfont, aa_flags );
837 if (!ret) return 0;
839 switch (*aa_flags)
841 case GGO_GRAY2_BITMAP:
842 case GGO_GRAY4_BITMAP:
843 case GGO_GRAY8_BITMAP:
844 physdev->aa_flags = WINE_GGO_GRAY16_BITMAP;
845 break;
846 case 0:
847 physdev->aa_flags = GGO_BITMAP;
848 break;
849 default:
850 physdev->aa_flags = *aa_flags;
851 break;
854 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
855 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
856 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
857 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
858 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
859 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
861 GetTransform( dev->hdc, 0x204, &lfsz.xform );
862 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
863 lfsz.xform.eM21, lfsz.xform.eM22);
865 if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE)
867 lfsz.lf.lfOrientation = lfsz.lf.lfEscapement;
868 if (lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
869 lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
872 /* Not used fields, would break hashing */
873 lfsz.xform.eDx = lfsz.xform.eDy = 0;
875 lfsz_calc_hash(&lfsz);
877 EnterCriticalSection(&xrender_cs);
878 if (physdev->cache_index != -1)
879 dec_ref_cache( physdev->cache_index );
880 physdev->cache_index = GetCacheEntry( &lfsz );
881 LeaveCriticalSection(&xrender_cs);
882 return ret;
885 static void set_physdev_format( struct xrender_physdev *physdev, enum wxr_format format )
887 if (physdev->x11dev->drawable == DefaultRootWindow( gdi_display ))
888 physdev->format = WXR_FORMAT_ROOT;
889 else
890 physdev->format = format;
892 physdev->pict_format = pict_formats[physdev->format];
895 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
897 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
898 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
900 if (!physdev) return FALSE;
901 physdev->x11dev = x11dev;
902 physdev->cache_index = -1;
903 set_physdev_format( physdev, format );
904 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
905 return TRUE;
908 /* store the color mask data in the bitmap info structure */
909 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
911 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
913 info->bmiHeader.biPlanes = 1;
914 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
915 info->bmiHeader.biCompression = BI_RGB;
916 info->bmiHeader.biClrUsed = 0;
918 switch (info->bmiHeader.biBitCount)
920 case 16:
921 colors[0] = format->direct.redMask << format->direct.red;
922 colors[1] = format->direct.greenMask << format->direct.green;
923 colors[2] = format->direct.blueMask << format->direct.blue;
924 info->bmiHeader.biCompression = BI_BITFIELDS;
925 break;
926 case 32:
927 colors[0] = format->direct.redMask << format->direct.red;
928 colors[1] = format->direct.greenMask << format->direct.green;
929 colors[2] = format->direct.blueMask << format->direct.blue;
930 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
931 info->bmiHeader.biCompression = BI_BITFIELDS;
932 break;
937 /**********************************************************************
938 * xrenderdrv_CreateDC
940 static BOOL CDECL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
941 LPCWSTR output, const DEVMODEW* initData )
943 return create_xrender_dc( pdev, default_format );
946 /**********************************************************************
947 * xrenderdrv_CreateCompatibleDC
949 static BOOL CDECL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
951 if (orig) /* chain to x11drv first */
953 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
954 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
956 /* otherwise we have been called by x11drv */
958 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
961 /**********************************************************************
962 * xrenderdrv_DeleteDC
964 static BOOL CDECL xrenderdrv_DeleteDC( PHYSDEV dev )
966 struct xrender_physdev *physdev = get_xrender_dev( dev );
968 free_xrender_picture( physdev );
970 EnterCriticalSection( &xrender_cs );
971 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
972 LeaveCriticalSection( &xrender_cs );
974 HeapFree( GetProcessHeap(), 0, physdev );
975 return TRUE;
978 /**********************************************************************
979 * xrenderdrv_ExtEscape
981 static INT CDECL xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
982 INT out_count, LPVOID out_data )
984 struct xrender_physdev *physdev = get_xrender_dev( dev );
986 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
988 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
990 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
992 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
993 if (ret)
995 free_xrender_picture( physdev );
996 set_physdev_format( physdev, default_format );
998 return ret;
1001 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1004 /***********************************************************************
1005 * xrenderdrv_SetDeviceClipping
1007 static void CDECL xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1009 struct xrender_physdev *physdev = get_xrender_dev( dev );
1011 physdev->region = rgn;
1012 physdev->update_clip = TRUE;
1014 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1015 dev->funcs->pSetDeviceClipping( dev, rgn );
1019 /************************************************************************
1020 * UploadGlyph
1022 * Helper to ExtTextOut. Must be called inside xrender_cs
1024 static void UploadGlyph(struct xrender_physdev *physDev, UINT glyph, enum glyph_type type)
1026 unsigned int buflen;
1027 char *buf;
1028 Glyph gid;
1029 GLYPHMETRICS gm;
1030 XGlyphInfo gi;
1031 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1032 gsCacheEntryFormat *formatEntry;
1033 UINT ggo_format = physDev->aa_flags;
1034 AA_Type format = aa_type_from_flags( physDev->aa_flags );
1035 enum wxr_format wxr_format;
1036 static const char zero[4];
1037 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1039 if (type == GLYPH_INDEX) ggo_format |= GGO_GLYPH_INDEX;
1040 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1041 if(buflen == GDI_ERROR) {
1042 if(format != AA_None) {
1043 format = AA_None;
1044 physDev->aa_flags = GGO_BITMAP;
1045 ggo_format = (ggo_format & GGO_GLYPH_INDEX) | GGO_BITMAP;
1046 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1048 if(buflen == GDI_ERROR) {
1049 WARN("GetGlyphOutlineW failed using default glyph\n");
1050 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1051 if(buflen == GDI_ERROR) {
1052 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1053 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1054 if(buflen == GDI_ERROR) {
1055 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1056 return;
1060 TRACE("Turning off antialiasing for this monochrome font\n");
1063 /* If there is nothing for the current type, we create the entry. */
1064 if( !entry->format[type][format] ) {
1065 entry->format[type][format] = HeapAlloc(GetProcessHeap(),
1066 HEAP_ZERO_MEMORY,
1067 sizeof(gsCacheEntryFormat));
1069 formatEntry = entry->format[type][format];
1071 if(formatEntry->nrealized <= glyph) {
1072 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1074 if (formatEntry->realized)
1075 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1076 HEAP_ZERO_MEMORY,
1077 formatEntry->realized,
1078 formatEntry->nrealized * sizeof(BOOL));
1079 else
1080 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1081 HEAP_ZERO_MEMORY,
1082 formatEntry->nrealized * sizeof(BOOL));
1084 if (formatEntry->gis)
1085 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1086 HEAP_ZERO_MEMORY,
1087 formatEntry->gis,
1088 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1089 else
1090 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1091 HEAP_ZERO_MEMORY,
1092 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1096 if(formatEntry->glyphset == 0) {
1097 switch(format) {
1098 case AA_Grey:
1099 wxr_format = WXR_FORMAT_GRAY;
1100 break;
1102 case AA_RGB:
1103 case AA_BGR:
1104 case AA_VRGB:
1105 case AA_VBGR:
1106 wxr_format = WXR_FORMAT_A8R8G8B8;
1107 break;
1109 default:
1110 ERR("aa = %d - not implemented\n", format);
1111 /* fall through */
1112 case AA_None:
1113 wxr_format = WXR_FORMAT_MONO;
1114 break;
1117 formatEntry->font_format = pict_formats[wxr_format];
1118 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1122 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1123 if (buflen)
1124 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1125 else
1126 gm.gmBlackBoxX = gm.gmBlackBoxY = 0; /* empty glyph */
1127 formatEntry->realized[glyph] = TRUE;
1129 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1130 buflen,
1131 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1132 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1134 gi.width = gm.gmBlackBoxX;
1135 gi.height = gm.gmBlackBoxY;
1136 gi.x = -gm.gmptGlyphOrigin.x;
1137 gi.y = gm.gmptGlyphOrigin.y;
1138 gi.xOff = gm.gmCellIncX;
1139 gi.yOff = gm.gmCellIncY;
1141 if(TRACE_ON(xrender)) {
1142 int pitch, i, j;
1143 char output[300];
1144 unsigned char *line;
1146 if(format == AA_None) {
1147 pitch = ((gi.width + 31) / 32) * 4;
1148 for(i = 0; i < gi.height; i++) {
1149 line = (unsigned char*) buf + i * pitch;
1150 output[0] = '\0';
1151 for(j = 0; j < pitch * 8; j++) {
1152 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1154 TRACE("%s\n", output);
1156 } else {
1157 static const char blks[] = " .:;!o*#";
1158 char str[2];
1160 str[1] = '\0';
1161 pitch = ((gi.width + 3) / 4) * 4;
1162 for(i = 0; i < gi.height; i++) {
1163 line = (unsigned char*) buf + i * pitch;
1164 output[0] = '\0';
1165 for(j = 0; j < pitch; j++) {
1166 str[0] = blks[line[j] >> 5];
1167 strcat(output, str);
1169 TRACE("%s\n", output);
1175 if(formatEntry->glyphset) {
1176 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1177 unsigned char *byte = (unsigned char*) buf, c;
1178 int i = buflen;
1180 while(i--) {
1181 c = *byte;
1183 /* magic to flip bit order */
1184 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1185 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1186 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1188 *byte++ = c;
1191 else if ( format != AA_Grey &&
1192 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1194 unsigned int i, *data = (unsigned int *)buf;
1195 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1197 gid = glyph;
1200 XRenderCompositeText seems to ignore 0x0 glyphs when
1201 AA_None, which means we lose the advance width of glyphs
1202 like the space. We'll pretend that such glyphs are 1x1
1203 bitmaps.
1206 if(buflen == 0)
1207 gi.width = gi.height = 1;
1209 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1210 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1213 HeapFree(GetProcessHeap(), 0, buf);
1214 formatEntry->gis[glyph] = gi;
1217 /*************************************************************
1218 * get_tile_pict
1220 * Returns an appropriate Picture for tiling the text colour.
1221 * Call and use result within the xrender_cs
1223 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1225 static struct
1227 Pixmap xpm;
1228 Picture pict;
1229 XRenderColor current_color;
1230 } tiles[WXR_NB_FORMATS], *tile;
1232 tile = &tiles[wxr_format];
1234 if(!tile->xpm)
1236 XRenderPictureAttributes pa;
1237 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1239 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1241 pa.repeat = RepeatNormal;
1242 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1244 /* init current_color to something different from text_pixel */
1245 tile->current_color = *color;
1246 tile->current_color.red ^= 0xffff;
1248 if (wxr_format == WXR_FORMAT_MONO)
1250 /* for a 1bpp bitmap we always need a 1 in the tile */
1251 XRenderColor col;
1252 col.red = col.green = col.blue = 0;
1253 col.alpha = 0xffff;
1254 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1258 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1260 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1261 tile->current_color = *color;
1263 return tile->pict;
1266 /*************************************************************
1267 * get_mask_pict
1269 * Returns an appropriate Picture for masking with the specified alpha.
1270 * Call and use result within the xrender_cs
1272 static Picture get_mask_pict( int alpha )
1274 static Pixmap pixmap;
1275 static Picture pict;
1276 static int current_alpha;
1278 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1280 if (!pixmap)
1282 XRenderPictureAttributes pa;
1284 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1285 pa.repeat = RepeatNormal;
1286 pict = pXRenderCreatePicture( gdi_display, pixmap,
1287 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1288 current_alpha = -1;
1291 if (alpha != current_alpha)
1293 XRenderColor col;
1294 col.red = col.green = col.blue = 0;
1295 col.alpha = current_alpha = alpha;
1296 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1298 return pict;
1301 /***********************************************************************
1302 * xrenderdrv_ExtTextOut
1304 static BOOL CDECL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1305 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1307 struct xrender_physdev *physdev = get_xrender_dev( dev );
1308 gsCacheEntry *entry;
1309 gsCacheEntryFormat *formatEntry;
1310 unsigned int idx;
1311 Picture pict, tile_pict = 0;
1312 XGlyphElt16 *elts;
1313 POINT offset, desired, current;
1314 int render_op = PictOpOver;
1315 XRenderColor col;
1316 RECT rect, bounds;
1317 enum glyph_type type = (flags & ETO_GLYPH_INDEX) ? GLYPH_INDEX : GLYPH_WCHAR;
1319 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1320 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1322 if(flags & ETO_OPAQUE)
1324 XRenderColor bg;
1326 if (physdev->format == WXR_FORMAT_MONO)
1327 /* use the inverse of the text color */
1328 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1329 else
1330 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1332 set_xrender_transformation( pict, 1, 1, 0, 0 );
1333 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1334 physdev->x11dev->dc_rect.left + lprect->left,
1335 physdev->x11dev->dc_rect.top + lprect->top,
1336 lprect->right - lprect->left,
1337 lprect->bottom - lprect->top );
1338 add_device_bounds( physdev->x11dev, lprect );
1341 if(count == 0) return TRUE;
1343 EnterCriticalSection(&xrender_cs);
1345 entry = glyphsetCache + physdev->cache_index;
1346 formatEntry = entry->format[type][aa_type_from_flags( physdev->aa_flags )];
1348 for(idx = 0; idx < count; idx++) {
1349 if( !formatEntry ) {
1350 UploadGlyph(physdev, wstr[idx], type);
1351 /* re-evaluate format entry since aa_flags may have changed */
1352 formatEntry = entry->format[type][aa_type_from_flags( physdev->aa_flags )];
1353 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1354 UploadGlyph(physdev, wstr[idx], type);
1357 if (!formatEntry)
1359 WARN("could not upload requested glyphs\n");
1360 LeaveCriticalSection(&xrender_cs);
1361 return FALSE;
1364 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1365 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1367 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1369 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1370 So we pass zeros to the function and move to our starting position using the first
1371 element of the elts array. */
1373 desired.x = physdev->x11dev->dc_rect.left + x;
1374 desired.y = physdev->x11dev->dc_rect.top + y;
1375 offset.x = offset.y = 0;
1376 current.x = current.y = 0;
1378 tile_pict = get_tile_pict(physdev->format, &col);
1380 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1382 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1383 render_op = PictOpOutReverse; /* This gives us 'black' text */
1385 reset_bounds( &bounds );
1386 for(idx = 0; idx < count; idx++)
1388 elts[idx].glyphset = formatEntry->glyphset;
1389 elts[idx].chars = wstr + idx;
1390 elts[idx].nchars = 1;
1391 elts[idx].xOff = desired.x - current.x;
1392 elts[idx].yOff = desired.y - current.y;
1394 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1395 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1397 rect.left = desired.x - physdev->x11dev->dc_rect.left - formatEntry->gis[wstr[idx]].x;
1398 rect.top = desired.y - physdev->x11dev->dc_rect.top - formatEntry->gis[wstr[idx]].y;
1399 rect.right = rect.left + formatEntry->gis[wstr[idx]].width;
1400 rect.bottom = rect.top + formatEntry->gis[wstr[idx]].height;
1401 add_bounds_rect( &bounds, &rect );
1403 if(!lpDx)
1405 desired.x += formatEntry->gis[wstr[idx]].xOff;
1406 desired.y += formatEntry->gis[wstr[idx]].yOff;
1408 else
1410 if(flags & ETO_PDY)
1412 offset.x += lpDx[idx * 2];
1413 offset.y += lpDx[idx * 2 + 1];
1415 else
1416 offset.x += lpDx[idx];
1417 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1418 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1422 /* Make sure we don't have any transforms set from a previous call */
1423 set_xrender_transformation(pict, 1, 1, 0, 0);
1424 pXRenderCompositeText16(gdi_display, render_op,
1425 tile_pict,
1426 pict,
1427 formatEntry->font_format,
1428 0, 0, 0, 0, elts, count);
1429 HeapFree(GetProcessHeap(), 0, elts);
1431 LeaveCriticalSection(&xrender_cs);
1432 add_device_bounds( physdev->x11dev, &bounds );
1433 return TRUE;
1436 /* multiply the alpha channel of a picture */
1437 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1438 int x, int y, int width, int height )
1440 XRenderPictureAttributes pa;
1441 Pixmap src_pixmap, mask_pixmap;
1442 Picture src_pict, mask_pict;
1443 XRenderColor color;
1445 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1446 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1447 pa.repeat = RepeatNormal;
1448 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1449 pa.component_alpha = True;
1450 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1451 color.red = color.green = color.blue = color.alpha = 0xffff;
1452 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1453 color.alpha = alpha;
1454 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1455 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1456 0, 0, 0, 0, x, y, width, height );
1457 pXRenderFreePicture( gdi_display, src_pict );
1458 pXRenderFreePicture( gdi_display, mask_pict );
1459 XFreePixmap( gdi_display, src_pixmap );
1460 XFreePixmap( gdi_display, mask_pixmap );
1463 /* Helper function for (stretched) blitting using xrender */
1464 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1465 int x_src, int y_src, int width_src, int height_src,
1466 int x_dst, int y_dst, int width_dst, int height_dst,
1467 double xscale, double yscale )
1469 int x_offset, y_offset;
1471 if (width_src < 0)
1473 x_src += width_src + 1;
1475 if (height_src < 0)
1477 y_src += height_src + 1;
1479 if (width_dst < 0)
1481 x_dst += width_dst + 1;
1482 width_dst = -width_dst;
1484 if (height_dst < 0)
1486 y_dst += height_dst + 1;
1487 height_dst = -height_dst;
1490 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1491 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1492 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1493 if(xscale != 1.0 || yscale != 1.0)
1495 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1496 * in the wrong quadrant of the x-y plane.
1498 x_offset = (xscale < 0) ? -width_dst : 0;
1499 y_offset = (yscale < 0) ? -height_dst : 0;
1500 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1502 else
1504 x_offset = x_src;
1505 y_offset = y_src;
1506 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1508 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1509 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1512 /* Helper function for (stretched) mono->color blitting using xrender */
1513 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1514 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1515 int x_src, int y_src, int width_src, int height_src,
1516 int x_dst, int y_dst, int width_dst, int height_dst,
1517 double xscale, double yscale )
1519 Picture tile_pict;
1520 int x_offset, y_offset;
1521 XRenderColor color;
1523 if (width_src < 0)
1525 x_src += width_src + 1;
1526 width_src = -width_src;
1528 if (height_src < 0)
1530 y_src += height_src + 1;
1531 height_src = -height_src;
1533 if (width_dst < 0)
1535 x_dst += width_dst + 1;
1536 width_dst = -width_dst;
1538 if (height_dst < 0)
1540 y_dst += height_dst + 1;
1541 height_dst = -height_dst;
1544 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1545 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1546 * the tile data.
1548 EnterCriticalSection( &xrender_cs );
1549 color = *bg;
1550 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1551 tile_pict = get_tile_pict( dst_format, &color );
1553 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1555 if (xscale != 1.0 || yscale != 1.0)
1557 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1558 * in the wrong quadrant of the x-y plane.
1560 x_offset = (xscale < 0) ? -width_dst : 0;
1561 y_offset = (yscale < 0) ? -height_dst : 0;
1562 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1564 else
1566 x_offset = x_src;
1567 y_offset = y_src;
1568 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1570 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1571 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1572 LeaveCriticalSection( &xrender_cs );
1574 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1575 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1576 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1577 x_dst, y_dst, width_dst, height_dst );
1580 /* create a pixmap and render picture for an image */
1581 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1582 struct bitblt_coords *src, enum wxr_format format,
1583 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1585 DWORD ret;
1586 int width = src->visrect.right - src->visrect.left;
1587 int height = src->visrect.bottom - src->visrect.top;
1588 int depth = pict_formats[format]->depth;
1589 struct gdi_image_bits dst_bits;
1590 XRenderPictureAttributes pa;
1591 GC gc;
1592 XImage *image;
1594 image = XCreateImage( gdi_display, default_visual.visual, depth, ZPixmap, 0, NULL,
1595 info->bmiHeader.biWidth, height, 32, 0 );
1596 if (!image) return ERROR_OUTOFMEMORY;
1598 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1599 if (ret) return ret;
1601 image->data = dst_bits.ptr;
1603 *use_repeat = (width == 1 && height == 1);
1604 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1606 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1607 gc = XCreateGC( gdi_display, *pixmap, 0, NULL );
1608 XPutImage( gdi_display, *pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1609 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1610 XFreeGC( gdi_display, gc );
1612 /* make coordinates relative to the pixmap */
1613 src->x -= src->visrect.left;
1614 src->y -= src->visrect.top;
1615 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1617 image->data = NULL;
1618 XDestroyImage( image );
1619 if (dst_bits.free) dst_bits.free( &dst_bits );
1620 return ret;
1623 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1624 Drawable drawable, const struct bitblt_coords *src,
1625 const struct bitblt_coords *dst )
1627 int x_dst, y_dst;
1628 Picture src_pict = 0, dst_pict, mask_pict = 0;
1629 double xscale = src->width / (double)dst->width;
1630 double yscale = src->height / (double)dst->height;
1632 if (drawable) /* using an intermediate pixmap */
1634 x_dst = dst->x;
1635 y_dst = dst->y;
1636 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, 0, NULL );
1638 else
1640 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
1641 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
1642 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1645 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1647 /* mono -> color */
1648 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1650 XRenderColor fg, bg;
1652 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
1653 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
1654 fg.alpha = bg.alpha = 0;
1656 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
1657 physdev_src->x11dev->dc_rect.left + src->x,
1658 physdev_src->x11dev->dc_rect.top + src->y,
1659 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1661 else /* color -> color (can be at different depths) or mono -> mono */
1663 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
1664 mask_pict = get_no_alpha_mask();
1666 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
1667 physdev_src->x11dev->dc_rect.left + src->x,
1668 physdev_src->x11dev->dc_rect.top + src->y,
1669 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1672 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1676 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
1677 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
1678 Drawable drawable, struct bitblt_coords *src,
1679 struct bitblt_coords *dst, BOOL use_repeat )
1681 int x_dst, y_dst;
1682 Picture dst_pict;
1683 double xscale, yscale;
1685 if (drawable) /* using an intermediate pixmap */
1687 RGNDATA *clip_data = NULL;
1689 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1690 x_dst = dst->x;
1691 y_dst = dst->y;
1692 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL );
1693 if (clip_data)
1694 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
1695 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
1696 HeapFree( GetProcessHeap(), 0, clip_data );
1698 else
1700 x_dst = physdev->x11dev->dc_rect.left + dst->x;
1701 y_dst = physdev->x11dev->dc_rect.top + dst->y;
1702 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
1705 if (!use_repeat)
1707 xscale = src->width / (double)dst->width;
1708 yscale = src->height / (double)dst->height;
1710 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1712 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
1713 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1715 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1719 /***********************************************************************
1720 * xrenderdrv_StretchBlt
1722 static BOOL CDECL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1723 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1725 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1726 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1727 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
1729 if (src_dev->funcs != dst_dev->funcs)
1731 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
1732 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
1735 /* XRender is of no use for color -> mono */
1736 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
1737 goto x11drv_fallback;
1739 /* if not stretching, we only need to handle format conversion */
1740 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
1742 if (rop != SRCCOPY)
1744 GC tmpGC;
1745 Pixmap tmp_pixmap;
1746 struct bitblt_coords tmp;
1748 /* make coordinates relative to tmp pixmap */
1749 tmp = *dst;
1750 tmp.x -= tmp.visrect.left;
1751 tmp.y -= tmp.visrect.top;
1752 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1754 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
1755 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1756 XSetGraphicsExposures( gdi_display, tmpGC, False );
1757 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
1758 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
1760 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
1761 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
1763 XFreePixmap( gdi_display, tmp_pixmap );
1764 XFreeGC( gdi_display, tmpGC );
1766 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
1768 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
1769 return TRUE;
1771 x11drv_fallback:
1772 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
1776 /***********************************************************************
1777 * xrenderdrv_PutImage
1779 static DWORD CDECL xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1780 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1781 struct bitblt_coords *dst, DWORD rop )
1783 struct xrender_physdev *physdev = get_xrender_dev( dev );
1784 DWORD ret;
1785 Pixmap tmp_pixmap;
1786 GC gc;
1787 enum wxr_format src_format, dst_format;
1788 XRenderPictFormat *pict_format;
1789 Pixmap src_pixmap;
1790 Picture src_pict, mask_pict = 0;
1791 BOOL use_repeat;
1793 dst_format = physdev->format;
1794 src_format = get_xrender_format_from_bitmapinfo( info );
1795 if (!(pict_format = pict_formats[src_format])) goto update_format;
1797 /* make sure we can create an image with the same bpp */
1798 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
1799 goto update_format;
1801 /* mono <-> color conversions not supported */
1802 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
1803 goto x11drv_fallback;
1805 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1807 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
1809 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
1810 if (!ret)
1812 struct bitblt_coords tmp;
1814 if (rop != SRCCOPY)
1816 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
1818 /* make coordinates relative to tmp pixmap */
1819 tmp = *dst;
1820 tmp.x -= tmp.visrect.left;
1821 tmp.y -= tmp.visrect.top;
1822 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1824 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
1825 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1826 XSetGraphicsExposures( gdi_display, gc, False );
1827 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
1828 tmp.visrect.right - tmp.visrect.left,
1829 tmp.visrect.bottom - tmp.visrect.top,
1830 physdev->pict_format->depth );
1832 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
1833 NULL, tmp_pixmap, src, &tmp, use_repeat );
1834 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
1836 XFreePixmap( gdi_display, tmp_pixmap );
1837 XFreeGC( gdi_display, gc );
1838 if (restore_region) restore_clipping_region( physdev->x11dev );
1840 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
1841 physdev->pict_format, physdev, 0, src, dst, use_repeat );
1843 add_device_bounds( physdev->x11dev, &dst->visrect );
1845 pXRenderFreePicture( gdi_display, src_pict );
1846 XFreePixmap( gdi_display, src_pixmap );
1848 return ret;
1850 update_format:
1851 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1852 set_color_info( pict_formats[dst_format], info );
1853 return ERROR_BAD_FORMAT;
1855 x11drv_fallback:
1856 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
1857 return dev->funcs->pPutImage( dev, clip, info, bits, src, dst, rop );
1861 /***********************************************************************
1862 * xrenderdrv_BlendImage
1864 static DWORD CDECL xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
1865 struct bitblt_coords *src, struct bitblt_coords *dst,
1866 BLENDFUNCTION func )
1868 struct xrender_physdev *physdev = get_xrender_dev( dev );
1869 DWORD ret;
1870 enum wxr_format format;
1871 XRenderPictFormat *pict_format;
1872 Picture dst_pict, src_pict, mask_pict;
1873 Pixmap src_pixmap;
1874 BOOL use_repeat;
1876 format = get_xrender_format_from_bitmapinfo( info );
1877 if (!(func.AlphaFormat & AC_SRC_ALPHA))
1878 format = get_format_without_alpha( format );
1879 else if (format != WXR_FORMAT_A8R8G8B8 || info->bmiHeader.biCompression != BI_RGB)
1880 return ERROR_INVALID_PARAMETER;
1882 if (!(pict_format = pict_formats[format])) goto update_format;
1884 /* make sure we can create an image with the same bpp */
1885 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
1886 goto update_format;
1888 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
1889 goto update_format;
1891 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1893 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
1894 if (!ret)
1896 double xscale, yscale;
1898 if (!use_repeat)
1900 xscale = src->width / (double)dst->width;
1901 yscale = src->height / (double)dst->height;
1903 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1905 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
1907 EnterCriticalSection( &xrender_cs );
1908 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
1910 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
1911 src->x, src->y, src->width, src->height,
1912 physdev->x11dev->dc_rect.left + dst->x,
1913 physdev->x11dev->dc_rect.top + dst->y,
1914 dst->width, dst->height, xscale, yscale );
1916 pXRenderFreePicture( gdi_display, src_pict );
1917 XFreePixmap( gdi_display, src_pixmap );
1919 LeaveCriticalSection( &xrender_cs );
1920 add_device_bounds( physdev->x11dev, &dst->visrect );
1922 return ret;
1924 update_format:
1925 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1926 set_color_info( physdev->pict_format, info );
1927 return ERROR_BAD_FORMAT;
1931 /***********************************************************************
1932 * xrenderdrv_AlphaBlend
1934 static BOOL CDECL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
1935 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
1937 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1938 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1939 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
1940 XRenderPictureAttributes pa;
1941 Pixmap tmp_pixmap = 0;
1942 double xscale, yscale;
1944 if (src_dev->funcs != dst_dev->funcs)
1946 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
1947 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
1950 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
1952 SetLastError( ERROR_INVALID_PARAMETER );
1953 return FALSE;
1956 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1958 xscale = src->width / (double)dst->width;
1959 yscale = src->height / (double)dst->height;
1961 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1963 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1965 /* mono -> color blending needs an intermediate color pixmap */
1966 XRenderColor fg, bg;
1967 int width = src->visrect.right - src->visrect.left;
1968 int height = src->visrect.bottom - src->visrect.top;
1970 /* blending doesn't use the destination DC colors */
1971 fg.red = fg.green = fg.blue = 0;
1972 bg.red = bg.green = bg.blue = 0xffff;
1973 fg.alpha = bg.alpha = 0xffff;
1975 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
1976 physdev_dst->pict_format->depth );
1977 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format, 0, NULL );
1979 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
1980 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
1982 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
1984 /* we need a source picture with no alpha */
1985 enum wxr_format format = get_format_without_alpha( physdev_src->format );
1986 if (format != physdev_src->format)
1988 pa.subwindow_mode = IncludeInferiors;
1989 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
1990 pict_formats[format], CPSubwindowMode, &pa );
1994 if (tmp_pict) src_pict = tmp_pict;
1996 EnterCriticalSection( &xrender_cs );
1997 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
1999 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2000 physdev_src->x11dev->dc_rect.left + src->x,
2001 physdev_src->x11dev->dc_rect.top + src->y,
2002 src->width, src->height,
2003 physdev_dst->x11dev->dc_rect.left + dst->x,
2004 physdev_dst->x11dev->dc_rect.top + dst->y,
2005 dst->width, dst->height, xscale, yscale );
2007 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2008 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2010 LeaveCriticalSection( &xrender_cs );
2011 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2012 return TRUE;
2015 /***********************************************************************
2016 * xrenderdrv_GradientFill
2018 static BOOL CDECL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2019 void * grad_array, ULONG ngrad, ULONG mode )
2021 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2022 static const XFixed stops[2] = { 0, 1 << 16 };
2023 struct xrender_physdev *physdev = get_xrender_dev( dev );
2024 XLinearGradient gradient;
2025 XRenderColor colors[2];
2026 Picture src_pict, dst_pict;
2027 unsigned int i;
2028 const GRADIENT_RECT *rect = grad_array;
2029 RECT rc;
2030 POINT pt[2];
2032 if (!pXRenderCreateLinearGradient) goto fallback;
2034 /* <= 16-bpp uses dithering */
2035 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2037 switch (mode)
2039 case GRADIENT_FILL_RECT_H:
2040 case GRADIENT_FILL_RECT_V:
2041 for (i = 0; i < ngrad; i++, rect++)
2043 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2044 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2046 colors[0].red = v1->Red * 257 / 256;
2047 colors[0].green = v1->Green * 257 / 256;
2048 colors[0].blue = v1->Blue * 257 / 256;
2049 colors[1].red = v2->Red * 257 / 256;
2050 colors[1].green = v2->Green * 257 / 256;
2051 colors[1].blue = v2->Blue * 257 / 256;
2052 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2053 colors[0].alpha = colors[1].alpha = 65535;
2055 pt[0].x = v1->x;
2056 pt[0].y = v1->y;
2057 pt[1].x = v2->x;
2058 pt[1].y = v2->y;
2059 LPtoDP( dev->hdc, pt, 2 );
2060 if (mode == GRADIENT_FILL_RECT_H)
2062 gradient.p1.y = gradient.p2.y = 0;
2063 if (pt[1].x > pt[0].x)
2065 gradient.p1.x = 0;
2066 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2068 else
2070 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2071 gradient.p2.x = 0;
2074 else
2076 gradient.p1.x = gradient.p2.x = 0;
2077 if (pt[1].y > pt[0].y)
2079 gradient.p1.y = 0;
2080 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2082 else
2084 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2085 gradient.p2.y = 0;
2089 rc.left = min( pt[0].x, pt[1].x );
2090 rc.top = min( pt[0].y, pt[1].y );
2091 rc.right = max( pt[0].x, pt[1].x );
2092 rc.bottom = max( pt[0].y, pt[1].y );
2094 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2095 mode, wine_dbgstr_rect( &rc ),
2096 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2097 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2099 dst_pict = get_xrender_picture( physdev, 0, NULL );
2101 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2102 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2103 0, 0, rc.right - rc.left, rc.bottom - rc.top,
2104 physdev->x11dev->dc_rect.left + rc.left,
2105 physdev->x11dev->dc_rect.top + rc.top,
2106 rc.right - rc.left, rc.bottom - rc.top, 1, 1 );
2107 pXRenderFreePicture( gdi_display, src_pict );
2108 add_device_bounds( physdev->x11dev, &rc );
2110 return TRUE;
2113 fallback:
2114 #endif
2115 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2116 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2119 /***********************************************************************
2120 * xrenderdrv_SelectBrush
2122 static HBRUSH CDECL xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2124 struct xrender_physdev *physdev = get_xrender_dev( dev );
2125 Pixmap pixmap;
2126 XVisualInfo vis = default_visual;
2127 XRenderPictFormat *format = physdev->pict_format;
2129 if (!pattern) goto x11drv_fallback;
2130 if (pattern->info->bmiHeader.biBitCount == 1) goto x11drv_fallback;
2131 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2133 vis.depth = format->depth;
2134 vis.red_mask = format->direct.redMask << format->direct.red;
2135 vis.green_mask = format->direct.greenMask << format->direct.green;
2136 vis.blue_mask = format->direct.blueMask << format->direct.blue;
2138 pixmap = create_pixmap_from_image( physdev->dev.hdc, &vis, pattern->info,
2139 &pattern->bits, pattern->usage );
2140 if (!pixmap) return 0;
2142 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2143 physdev->x11dev->brush.pixmap = pixmap;
2144 physdev->x11dev->brush.fillStyle = FillTiled;
2145 physdev->x11dev->brush.pixel = 0; /* ignored */
2146 physdev->x11dev->brush.style = BS_PATTERN;
2147 return hbrush;
2149 x11drv_fallback:
2150 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2151 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2155 static const struct gdi_dc_funcs xrender_funcs =
2157 NULL, /* pAbortDoc */
2158 NULL, /* pAbortPath */
2159 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2160 NULL, /* pAngleArc */
2161 NULL, /* pArc */
2162 NULL, /* pArcTo */
2163 NULL, /* pBeginPath */
2164 xrenderdrv_BlendImage, /* pBlendImage */
2165 NULL, /* pChord */
2166 NULL, /* pCloseFigure */
2167 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2168 xrenderdrv_CreateDC, /* pCreateDC */
2169 xrenderdrv_DeleteDC, /* pDeleteDC */
2170 NULL, /* pDeleteObject */
2171 NULL, /* pDeviceCapabilities */
2172 NULL, /* pEllipse */
2173 NULL, /* pEndDoc */
2174 NULL, /* pEndPage */
2175 NULL, /* pEndPath */
2176 NULL, /* pEnumFonts */
2177 NULL, /* pEnumICMProfiles */
2178 NULL, /* pExcludeClipRect */
2179 NULL, /* pExtDeviceMode */
2180 xrenderdrv_ExtEscape, /* pExtEscape */
2181 NULL, /* pExtFloodFill */
2182 NULL, /* pExtSelectClipRgn */
2183 xrenderdrv_ExtTextOut, /* pExtTextOut */
2184 NULL, /* pFillPath */
2185 NULL, /* pFillRgn */
2186 NULL, /* pFlattenPath */
2187 NULL, /* pFontIsLinked */
2188 NULL, /* pFrameRgn */
2189 NULL, /* pGdiComment */
2190 NULL, /* pGetBoundsRect */
2191 NULL, /* pGetCharABCWidths */
2192 NULL, /* pGetCharABCWidthsI */
2193 NULL, /* pGetCharWidth */
2194 NULL, /* pGetCharWidthInfo */
2195 NULL, /* pGetDeviceCaps */
2196 NULL, /* pGetDeviceGammaRamp */
2197 NULL, /* pGetFontData */
2198 NULL, /* pGetFontRealizationInfo */
2199 NULL, /* pGetFontUnicodeRanges */
2200 NULL, /* pGetGlyphIndices */
2201 NULL, /* pGetGlyphOutline */
2202 NULL, /* pGetICMProfile */
2203 NULL, /* pGetImage */
2204 NULL, /* pGetKerningPairs */
2205 NULL, /* pGetNearestColor */
2206 NULL, /* pGetOutlineTextMetrics */
2207 NULL, /* pGetPixel */
2208 NULL, /* pGetSystemPaletteEntries */
2209 NULL, /* pGetTextCharsetInfo */
2210 NULL, /* pGetTextExtentExPoint */
2211 NULL, /* pGetTextExtentExPointI */
2212 NULL, /* pGetTextFace */
2213 NULL, /* pGetTextMetrics */
2214 xrenderdrv_GradientFill, /* pGradientFill */
2215 NULL, /* pIntersectClipRect */
2216 NULL, /* pInvertRgn */
2217 NULL, /* pLineTo */
2218 NULL, /* pModifyWorldTransform */
2219 NULL, /* pMoveTo */
2220 NULL, /* pOffsetClipRgn */
2221 NULL, /* pOffsetViewportOrg */
2222 NULL, /* pOffsetWindowOrg */
2223 NULL, /* pPaintRgn */
2224 NULL, /* pPatBlt */
2225 NULL, /* pPie */
2226 NULL, /* pPolyBezier */
2227 NULL, /* pPolyBezierTo */
2228 NULL, /* pPolyDraw */
2229 NULL, /* pPolyPolygon */
2230 NULL, /* pPolyPolyline */
2231 NULL, /* pPolygon */
2232 NULL, /* pPolyline */
2233 NULL, /* pPolylineTo */
2234 xrenderdrv_PutImage, /* pPutImage */
2235 NULL, /* pRealizeDefaultPalette */
2236 NULL, /* pRealizePalette */
2237 NULL, /* pRectangle */
2238 NULL, /* pResetDC */
2239 NULL, /* pRestoreDC */
2240 NULL, /* pRoundRect */
2241 NULL, /* pSaveDC */
2242 NULL, /* pScaleViewportExt */
2243 NULL, /* pScaleWindowExt */
2244 NULL, /* pSelectBitmap */
2245 xrenderdrv_SelectBrush, /* pSelectBrush */
2246 NULL, /* pSelectClipPath */
2247 xrenderdrv_SelectFont, /* pSelectFont */
2248 NULL, /* pSelectPalette */
2249 NULL, /* pSelectPen */
2250 NULL, /* pSetArcDirection */
2251 NULL, /* pSetBkColor */
2252 NULL, /* pSetBkMode */
2253 NULL, /* pSetBoundsRect */
2254 NULL, /* pSetDCBrushColor */
2255 NULL, /* pSetDCPenColor */
2256 NULL, /* pSetDIBitsToDevice */
2257 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2258 NULL, /* pSetDeviceGammaRamp */
2259 NULL, /* pSetLayout */
2260 NULL, /* pSetMapMode */
2261 NULL, /* pSetMapperFlags */
2262 NULL, /* pSetPixel */
2263 NULL, /* pSetPolyFillMode */
2264 NULL, /* pSetROP2 */
2265 NULL, /* pSetRelAbs */
2266 NULL, /* pSetStretchBltMode */
2267 NULL, /* pSetTextAlign */
2268 NULL, /* pSetTextCharacterExtra */
2269 NULL, /* pSetTextColor */
2270 NULL, /* pSetTextJustification */
2271 NULL, /* pSetViewportExt */
2272 NULL, /* pSetViewportOrg */
2273 NULL, /* pSetWindowExt */
2274 NULL, /* pSetWindowOrg */
2275 NULL, /* pSetWorldTransform */
2276 NULL, /* pStartDoc */
2277 NULL, /* pStartPage */
2278 xrenderdrv_StretchBlt, /* pStretchBlt */
2279 NULL, /* pStretchDIBits */
2280 NULL, /* pStrokeAndFillPath */
2281 NULL, /* pStrokePath */
2282 NULL, /* pUnrealizePalette */
2283 NULL, /* pWidenPath */
2284 NULL, /* pD3DKMTCheckVidPnExclusiveOwnership */
2285 NULL, /* pD3DKMTSetVidPnSourceOwner */
2286 NULL, /* wine_get_wgl_driver */
2287 NULL, /* wine_get_vulkan_driver */
2288 GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
2291 #else /* SONAME_LIBXRENDER */
2293 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2295 TRACE("XRender support not compiled in.\n");
2296 return NULL;
2299 #endif /* SONAME_LIBXRENDER */