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
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
26 #include "wine/port.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);
48 #include <X11/extensions/Xrender.h>
50 #ifndef RepeatNone /* added in 0.10 */
52 #define RepeatNormal 1
54 #define RepeatReflect 3
72 WXR_INVALID_FORMAT = WXR_NB_FORMATS
75 typedef struct wine_xrender_format_template
79 unsigned int alphaMask;
83 unsigned int greenMask;
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 */];
129 SIZE devsize; /* size in device coords */
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;
140 XRenderPictFormat *font_format;
144 } gsCacheEntryFormat;
149 gsCacheEntryFormat * format[AA_MAXVALUE];
154 struct xrender_physdev
156 struct gdi_physdev dev;
157 X11DRV_PDEVICE *x11dev;
159 enum wxr_format format;
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;
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)
200 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
201 MAKE_FUNCPTR(XRenderSetPictureTransform)
203 MAKE_FUNCPTR(XRenderQueryExtension)
207 static CRITICAL_SECTION xrender_cs;
208 static CRITICAL_SECTION_DEBUG critsect_debug =
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 ) | \
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
231 #define get_be_word(x) RtlUshortByteSwap(x)
232 #define NATIVE_BYTE_ORDER LSBFirst
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 )
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)
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;
265 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
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;
282 static int load_xrender_formats(void)
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)
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;
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);
319 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
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)
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);
356 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
357 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
359 #undef LOAD_OPTIONAL_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");
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");
379 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
380 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
382 glyphsetCacheSize = INIT_CACHE_SIZE;
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;
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;
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)
429 return WXR_FORMAT_MONO;
434 if (info->bmiHeader.biCompression != BI_RGB) break;
435 return WXR_FORMAT_R8G8B8;
438 if (info->bmiHeader.biCompression == BI_BITFIELDS)
440 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
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))
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);
473 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
475 XRenderPictureAttributes pa;
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);
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 );
519 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
520 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
521 update_xrender_clipping( dev, 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 */
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 );
557 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
558 pXRenderFreePicture(gdi_display, dev->pict);
563 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
564 pXRenderFreePicture(gdi_display, dev->pict_src);
570 /* return a mask picture used to force alpha to 0 */
571 static Picture get_no_alpha_mask(void)
573 static Pixmap pixmap;
576 EnterCriticalSection( &xrender_cs );
579 XRenderPictureAttributes pa;
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;
589 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
591 LeaveCriticalSection( &xrender_cs );
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);
605 static void walk_cache(void)
609 EnterCriticalSection(&xrender_cs);
610 for(i=mru; i >= 0; i = glyphsetCache[i].next)
611 TRACE("item %d\n", i);
612 LeaveCriticalSection(&xrender_cs);
616 static int LookupEntry(LFANDSIZE *plfsz)
620 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
622 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
624 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
625 glyphsetCache[i].count++;
627 glyphsetCache[prev_i].next = glyphsetCache[i].next;
628 glyphsetCache[i].next = mru;
631 TRACE("found font in cache %d\n", i);
636 TRACE("font not in cache\n");
640 static void FreeEntry(int entry)
644 for(format = 0; format < AA_MAXVALUE; format++) {
645 gsCacheEntryFormat * formatEntry;
647 if( !glyphsetCache[entry].format[format] )
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;
674 assert(glyphsetCache[lastfree].count == -1);
675 glyphsetCache[lastfree].count = 1;
677 lastfree = glyphsetCache[lastfree].next;
679 glyphsetCache[best].next = mru;
682 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
686 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
687 if(glyphsetCache[i].count == 0) {
695 TRACE("freeing unused glyphset at cache %d\n", best);
697 glyphsetCache[best].count = 1;
699 glyphsetCache[prev_best].next = glyphsetCache[best].next;
700 glyphsetCache[best].next = mru;
708 TRACE("Growing cache\n");
711 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
713 (glyphsetCacheSize + INIT_CACHE_SIZE)
714 * sizeof(*glyphsetCache));
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;
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;
732 TRACE("new free cache slot at %d\n", mru);
736 static int GetCacheEntry( LFANDSIZE *plfsz )
742 if((ret = LookupEntry(plfsz)) != -1) return ret;
745 entry = glyphsetCache + ret;
746 entry->lfsz = *plfsz;
747 for( format = 0; format < AA_MAXVALUE; format++ ) {
748 assert( !entry->format[format] );
754 static void dec_ref_cache(int index)
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;
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++)
772 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
774 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
776 pwc = (WCHAR *)&two_chars;
778 *pwc = toupperW(*pwc);
780 *pwc = toupperW(*pwc);
788 static AA_Type aa_type_from_flags( UINT aa_flags )
790 switch (aa_flags & 0x7f)
794 case WINE_GGO_GRAY16_BITMAP:
796 case WINE_GGO_HRGB_BITMAP:
798 case WINE_GGO_HBGR_BITMAP:
800 case WINE_GGO_VRGB_BITMAP:
802 case WINE_GGO_VBGR_BITMAP:
805 FIXME( "unknown flags %x\n", aa_flags );
810 static UINT get_xft_aa_flags( const LOGFONTW *lf )
815 switch (lf->lfQuality)
817 case NONANTIALIASED_QUALITY:
818 case ANTIALIASED_QUALITY:
821 if (!(value = XGetDefault( gdi_display, "Xft", "antialias" ))) break;
822 TRACE( "got antialias '%s'\n", value );
823 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
824 value[0] == '0' || !strcasecmp( value, "off" ))
829 ret = GGO_GRAY4_BITMAP;
831 case CLEARTYPE_QUALITY:
832 case CLEARTYPE_NATURAL_QUALITY:
833 if (!(value = XGetDefault( gdi_display, "Xft", "rgba" ))) break;
834 TRACE( "got rgba '%s'\n", value );
835 if (!strcmp( value, "rgb" )) ret = WINE_GGO_HRGB_BITMAP;
836 else if (!strcmp( value, "bgr" )) ret = WINE_GGO_HBGR_BITMAP;
837 else if (!strcmp( value, "vrgb" )) ret = WINE_GGO_VRGB_BITMAP;
838 else if (!strcmp( value, "vbgr" )) ret = WINE_GGO_VBGR_BITMAP;
839 else if (!strcmp( value, "none" )) ret = GGO_GRAY4_BITMAP;
845 /**********************************************************************
846 * xrenderdrv_SelectFont
848 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
851 struct xrender_physdev *physdev = get_xrender_dev( dev );
852 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
855 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
856 if (!*aa_flags) *aa_flags = get_xft_aa_flags( &lfsz.lf );
858 ret = next->funcs->pSelectFont( next, hfont, aa_flags );
863 case GGO_GRAY2_BITMAP:
864 case GGO_GRAY4_BITMAP:
865 case GGO_GRAY8_BITMAP:
866 physdev->aa_flags = WINE_GGO_GRAY16_BITMAP;
869 physdev->aa_flags = GGO_BITMAP;
872 physdev->aa_flags = *aa_flags;
876 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
877 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
878 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
879 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
880 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
881 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
883 GetTransform( dev->hdc, 0x204, &lfsz.xform );
884 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
885 lfsz.xform.eM21, lfsz.xform.eM22);
887 if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE && lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
888 lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
890 /* Not used fields, would break hashing */
891 lfsz.xform.eDx = lfsz.xform.eDy = 0;
893 lfsz_calc_hash(&lfsz);
895 EnterCriticalSection(&xrender_cs);
896 if (physdev->cache_index != -1)
897 dec_ref_cache( physdev->cache_index );
898 physdev->cache_index = GetCacheEntry( &lfsz );
899 LeaveCriticalSection(&xrender_cs);
903 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
905 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
906 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
908 if (!physdev) return FALSE;
909 physdev->x11dev = x11dev;
910 physdev->cache_index = -1;
911 physdev->format = format;
912 physdev->pict_format = pict_formats[format];
913 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
917 /* store the color mask data in the bitmap info structure */
918 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
920 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
922 info->bmiHeader.biPlanes = 1;
923 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
924 info->bmiHeader.biCompression = BI_RGB;
925 info->bmiHeader.biClrUsed = 0;
927 switch (info->bmiHeader.biBitCount)
930 colors[0] = format->direct.redMask << format->direct.red;
931 colors[1] = format->direct.greenMask << format->direct.green;
932 colors[2] = format->direct.blueMask << format->direct.blue;
933 info->bmiHeader.biCompression = BI_BITFIELDS;
936 colors[0] = format->direct.redMask << format->direct.red;
937 colors[1] = format->direct.greenMask << format->direct.green;
938 colors[2] = format->direct.blueMask << format->direct.blue;
939 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
940 info->bmiHeader.biCompression = BI_BITFIELDS;
946 /**********************************************************************
947 * xrenderdrv_CreateDC
949 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
950 LPCWSTR output, const DEVMODEW* initData )
952 return create_xrender_dc( pdev, default_format );
955 /**********************************************************************
956 * xrenderdrv_CreateCompatibleDC
958 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
960 if (orig) /* chain to x11drv first */
962 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
963 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
965 /* otherwise we have been called by x11drv */
967 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
970 /**********************************************************************
971 * xrenderdrv_DeleteDC
973 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
975 struct xrender_physdev *physdev = get_xrender_dev( dev );
977 free_xrender_picture( physdev );
979 EnterCriticalSection( &xrender_cs );
980 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
981 LeaveCriticalSection( &xrender_cs );
983 HeapFree( GetProcessHeap(), 0, physdev );
987 /**********************************************************************
988 * xrenderdrv_ExtEscape
990 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
991 INT out_count, LPVOID out_data )
993 struct xrender_physdev *physdev = get_xrender_dev( dev );
995 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
997 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
999 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1001 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1002 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1006 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1009 /***********************************************************************
1010 * xrenderdrv_SetDeviceClipping
1012 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1014 struct xrender_physdev *physdev = get_xrender_dev( dev );
1016 physdev->region = rgn;
1017 physdev->update_clip = TRUE;
1019 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1020 dev->funcs->pSetDeviceClipping( dev, rgn );
1024 /************************************************************************
1027 * Helper to ExtTextOut. Must be called inside xrender_cs
1029 static void UploadGlyph(struct xrender_physdev *physDev, int glyph)
1031 unsigned int buflen;
1036 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1037 gsCacheEntryFormat *formatEntry;
1038 UINT ggo_format = GGO_GLYPH_INDEX | physDev->aa_flags;
1039 AA_Type format = aa_type_from_flags( physDev->aa_flags );
1040 enum wxr_format wxr_format;
1041 static const char zero[4];
1042 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1044 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1045 if(buflen == GDI_ERROR) {
1046 if(format != AA_None) {
1048 physDev->aa_flags = GGO_BITMAP;
1049 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1050 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1052 if(buflen == GDI_ERROR) {
1053 WARN("GetGlyphOutlineW failed using default glyph\n");
1054 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1055 if(buflen == GDI_ERROR) {
1056 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1057 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1058 if(buflen == GDI_ERROR) {
1059 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1064 TRACE("Turning off antialiasing for this monochrome font\n");
1067 /* If there is nothing for the current type, we create the entry. */
1068 if( !entry->format[format] ) {
1069 entry->format[format] = HeapAlloc(GetProcessHeap(),
1071 sizeof(gsCacheEntryFormat));
1073 formatEntry = entry->format[format];
1075 if(formatEntry->nrealized <= glyph) {
1076 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1078 if (formatEntry->realized)
1079 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1081 formatEntry->realized,
1082 formatEntry->nrealized * sizeof(BOOL));
1084 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1086 formatEntry->nrealized * sizeof(BOOL));
1088 if (formatEntry->gis)
1089 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1092 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1094 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1096 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1100 if(formatEntry->glyphset == 0) {
1103 wxr_format = WXR_FORMAT_GRAY;
1110 wxr_format = WXR_FORMAT_A8R8G8B8;
1114 ERR("aa = %d - not implemented\n", format);
1117 wxr_format = WXR_FORMAT_MONO;
1121 formatEntry->font_format = pict_formats[wxr_format];
1122 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1126 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1127 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1128 formatEntry->realized[glyph] = TRUE;
1130 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1132 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1133 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1135 gi.width = gm.gmBlackBoxX;
1136 gi.height = gm.gmBlackBoxY;
1137 gi.x = -gm.gmptGlyphOrigin.x;
1138 gi.y = gm.gmptGlyphOrigin.y;
1139 gi.xOff = gm.gmCellIncX;
1140 gi.yOff = gm.gmCellIncY;
1142 if(TRACE_ON(xrender)) {
1145 unsigned char *line;
1147 if(format == AA_None) {
1148 pitch = ((gi.width + 31) / 32) * 4;
1149 for(i = 0; i < gi.height; i++) {
1150 line = (unsigned char*) buf + i * pitch;
1152 for(j = 0; j < pitch * 8; j++) {
1153 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1155 TRACE("%s\n", output);
1158 static const char blks[] = " .:;!o*#";
1162 pitch = ((gi.width + 3) / 4) * 4;
1163 for(i = 0; i < gi.height; i++) {
1164 line = (unsigned char*) buf + i * pitch;
1166 for(j = 0; j < pitch; j++) {
1167 str[0] = blks[line[j] >> 5];
1168 strcat(output, str);
1170 TRACE("%s\n", output);
1176 if(formatEntry->glyphset) {
1177 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1178 unsigned char *byte = (unsigned char*) buf, c;
1184 /* magic to flip bit order */
1185 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1186 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1187 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1192 else if ( format != AA_Grey &&
1193 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1195 unsigned int i, *data = (unsigned int *)buf;
1196 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1201 XRenderCompositeText seems to ignore 0x0 glyphs when
1202 AA_None, which means we lose the advance width of glyphs
1203 like the space. We'll pretend that such glyphs are 1x1
1208 gi.width = gi.height = 1;
1210 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1211 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1214 HeapFree(GetProcessHeap(), 0, buf);
1215 formatEntry->gis[glyph] = gi;
1218 /*************************************************************
1221 * Returns an appropriate Picture for tiling the text colour.
1222 * Call and use result within the xrender_cs
1224 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1230 XRenderColor current_color;
1231 } tiles[WXR_NB_FORMATS], *tile;
1233 tile = &tiles[wxr_format];
1237 XRenderPictureAttributes pa;
1238 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1240 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1242 pa.repeat = RepeatNormal;
1243 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1245 /* init current_color to something different from text_pixel */
1246 tile->current_color = *color;
1247 tile->current_color.red ^= 0xffff;
1249 if (wxr_format == WXR_FORMAT_MONO)
1251 /* for a 1bpp bitmap we always need a 1 in the tile */
1253 col.red = col.green = col.blue = 0;
1255 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1259 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1261 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1262 tile->current_color = *color;
1267 /*************************************************************
1270 * Returns an appropriate Picture for masking with the specified alpha.
1271 * Call and use result within the xrender_cs
1273 static Picture get_mask_pict( int alpha )
1275 static Pixmap pixmap;
1276 static Picture pict;
1277 static int current_alpha;
1279 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1283 XRenderPictureAttributes pa;
1285 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1286 pa.repeat = RepeatNormal;
1287 pict = pXRenderCreatePicture( gdi_display, pixmap,
1288 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1292 if (alpha != current_alpha)
1295 col.red = col.green = col.blue = 0;
1296 col.alpha = current_alpha = alpha;
1297 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1302 /***********************************************************************
1303 * xrenderdrv_ExtTextOut
1305 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1306 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1308 struct xrender_physdev *physdev = get_xrender_dev( dev );
1309 gsCacheEntry *entry;
1310 gsCacheEntryFormat *formatEntry;
1312 Picture pict, tile_pict = 0;
1314 POINT offset, desired, current;
1315 int render_op = PictOpOver;
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)
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;
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[aa_type_from_flags( physdev->aa_flags )];
1348 for(idx = 0; idx < count; idx++) {
1349 if( !formatEntry ) {
1350 UploadGlyph(physdev, wstr[idx]);
1351 /* re-evaluate format entry since aa_flags may have changed */
1352 formatEntry = entry->format[aa_type_from_flags( physdev->aa_flags )];
1353 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1354 UploadGlyph(physdev, wstr[idx]);
1359 WARN("could not upload requested glyphs\n");
1360 LeaveCriticalSection(&xrender_cs);
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 );
1405 desired.x += formatEntry->gis[wstr[idx]].xOff;
1406 desired.y += formatEntry->gis[wstr[idx]].yOff;
1412 offset.x += lpDx[idx * 2];
1413 offset.y += lpDx[idx * 2 + 1];
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,
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 );
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;
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;
1473 x_src += width_src + 1;
1474 width_src = -width_src;
1478 y_src += height_src + 1;
1479 height_src = -height_src;
1483 x_dst += width_dst + 1;
1484 width_dst = -width_dst;
1488 y_dst += height_dst + 1;
1489 height_dst = -height_dst;
1492 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1493 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1494 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1495 if(xscale != 1.0 || yscale != 1.0)
1497 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1498 * in the wrong quadrant of the x-y plane.
1500 x_offset = (xscale < 0) ? -width_dst : 0;
1501 y_offset = (yscale < 0) ? -height_dst : 0;
1502 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1508 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1510 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1511 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1514 /* Helper function for (stretched) mono->color blitting using xrender */
1515 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1516 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1517 int x_src, int y_src, int width_src, int height_src,
1518 int x_dst, int y_dst, int width_dst, int height_dst,
1519 double xscale, double yscale )
1522 int x_offset, y_offset;
1527 x_src += width_src + 1;
1528 width_src = -width_src;
1532 y_src += height_src + 1;
1533 height_src = -height_src;
1537 x_dst += width_dst + 1;
1538 width_dst = -width_dst;
1542 y_dst += height_dst + 1;
1543 height_dst = -height_dst;
1546 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1547 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1550 EnterCriticalSection( &xrender_cs );
1552 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1553 tile_pict = get_tile_pict( dst_format, &color );
1555 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1557 if (xscale != 1.0 || yscale != 1.0)
1559 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1560 * in the wrong quadrant of the x-y plane.
1562 x_offset = (xscale < 0) ? -width_dst : 0;
1563 y_offset = (yscale < 0) ? -height_dst : 0;
1564 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1570 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1572 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1573 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1574 LeaveCriticalSection( &xrender_cs );
1576 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1577 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1578 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1579 x_dst, y_dst, width_dst, height_dst );
1582 /* create a pixmap and render picture for an image */
1583 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1584 struct bitblt_coords *src, enum wxr_format format,
1585 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1588 int width = src->visrect.right - src->visrect.left;
1589 int height = src->visrect.bottom - src->visrect.top;
1590 int depth = pict_formats[format]->depth;
1591 struct gdi_image_bits dst_bits;
1592 XRenderPictureAttributes pa;
1596 image = XCreateImage( gdi_display, default_visual.visual, depth, ZPixmap, 0, NULL,
1597 info->bmiHeader.biWidth, height, 32, 0 );
1598 if (!image) return ERROR_OUTOFMEMORY;
1600 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1601 if (ret) return ret;
1603 image->data = dst_bits.ptr;
1605 *use_repeat = (width == 1 && height == 1);
1606 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1608 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1609 gc = XCreateGC( gdi_display, *pixmap, 0, NULL );
1610 XPutImage( gdi_display, *pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1611 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1612 XFreeGC( gdi_display, gc );
1614 /* make coordinates relative to the pixmap */
1615 src->x -= src->visrect.left;
1616 src->y -= src->visrect.top;
1617 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1620 XDestroyImage( image );
1621 if (dst_bits.free) dst_bits.free( &dst_bits );
1625 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1626 Drawable drawable, const struct bitblt_coords *src,
1627 const struct bitblt_coords *dst )
1630 Picture src_pict = 0, dst_pict, mask_pict = 0;
1631 double xscale = src->width / (double)dst->width;
1632 double yscale = src->height / (double)dst->height;
1634 if (drawable) /* using an intermediate pixmap */
1638 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, 0, NULL );
1642 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
1643 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
1644 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1647 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1650 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1652 XRenderColor fg, bg;
1654 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
1655 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
1656 fg.alpha = bg.alpha = 0;
1658 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
1659 physdev_src->x11dev->dc_rect.left + src->x,
1660 physdev_src->x11dev->dc_rect.top + src->y,
1661 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1663 else /* color -> color (can be at different depths) or mono -> mono */
1665 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
1666 mask_pict = get_no_alpha_mask();
1668 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
1669 physdev_src->x11dev->dc_rect.left + src->x,
1670 physdev_src->x11dev->dc_rect.top + src->y,
1671 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1674 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1678 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
1679 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
1680 Drawable drawable, struct bitblt_coords *src,
1681 struct bitblt_coords *dst, BOOL use_repeat )
1685 double xscale, yscale;
1687 if (drawable) /* using an intermediate pixmap */
1689 RGNDATA *clip_data = NULL;
1691 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1694 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL );
1696 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
1697 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
1698 HeapFree( GetProcessHeap(), 0, clip_data );
1702 x_dst = physdev->x11dev->dc_rect.left + dst->x;
1703 y_dst = physdev->x11dev->dc_rect.top + dst->y;
1704 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
1709 xscale = src->width / (double)dst->width;
1710 yscale = src->height / (double)dst->height;
1712 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1714 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
1715 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1717 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1721 /***********************************************************************
1722 * xrenderdrv_StretchBlt
1724 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1725 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1727 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1728 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1729 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
1731 if (src_dev->funcs != dst_dev->funcs)
1733 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
1734 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
1737 /* XRender is of no use for color -> mono */
1738 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
1739 goto x11drv_fallback;
1741 /* if not stretching, we only need to handle format conversion */
1742 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
1748 struct bitblt_coords tmp;
1750 /* make coordinates relative to tmp pixmap */
1752 tmp.x -= tmp.visrect.left;
1753 tmp.y -= tmp.visrect.top;
1754 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1756 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
1757 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1758 XSetGraphicsExposures( gdi_display, tmpGC, False );
1759 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
1760 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
1762 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
1763 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
1765 XFreePixmap( gdi_display, tmp_pixmap );
1766 XFreeGC( gdi_display, tmpGC );
1768 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
1770 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
1774 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
1778 /***********************************************************************
1779 * xrenderdrv_PutImage
1781 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1782 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1783 struct bitblt_coords *dst, DWORD rop )
1785 struct xrender_physdev *physdev = get_xrender_dev( dev );
1789 enum wxr_format src_format, dst_format;
1790 XRenderPictFormat *pict_format;
1792 Picture src_pict, mask_pict = 0;
1795 dst_format = physdev->format;
1796 src_format = get_xrender_format_from_bitmapinfo( info );
1797 if (!(pict_format = pict_formats[src_format])) goto update_format;
1799 /* make sure we can create an image with the same bpp */
1800 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
1803 /* mono <-> color conversions not supported */
1804 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
1805 goto x11drv_fallback;
1807 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1809 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
1811 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
1814 struct bitblt_coords tmp;
1818 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
1820 /* make coordinates relative to tmp pixmap */
1822 tmp.x -= tmp.visrect.left;
1823 tmp.y -= tmp.visrect.top;
1824 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1826 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
1827 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1828 XSetGraphicsExposures( gdi_display, gc, False );
1829 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
1830 tmp.visrect.right - tmp.visrect.left,
1831 tmp.visrect.bottom - tmp.visrect.top,
1832 physdev->pict_format->depth );
1834 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
1835 NULL, tmp_pixmap, src, &tmp, use_repeat );
1836 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
1838 XFreePixmap( gdi_display, tmp_pixmap );
1839 XFreeGC( gdi_display, gc );
1840 if (restore_region) restore_clipping_region( physdev->x11dev );
1842 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
1843 physdev->pict_format, physdev, 0, src, dst, use_repeat );
1845 add_device_bounds( physdev->x11dev, &dst->visrect );
1847 pXRenderFreePicture( gdi_display, src_pict );
1848 XFreePixmap( gdi_display, src_pixmap );
1853 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1854 set_color_info( pict_formats[dst_format], info );
1855 return ERROR_BAD_FORMAT;
1858 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
1859 return dev->funcs->pPutImage( dev, clip, info, bits, src, dst, rop );
1863 /***********************************************************************
1864 * xrenderdrv_BlendImage
1866 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
1867 struct bitblt_coords *src, struct bitblt_coords *dst,
1868 BLENDFUNCTION func )
1870 struct xrender_physdev *physdev = get_xrender_dev( dev );
1872 enum wxr_format format;
1873 XRenderPictFormat *pict_format;
1874 Picture dst_pict, src_pict, mask_pict;
1878 format = get_xrender_format_from_bitmapinfo( info );
1879 if (!(func.AlphaFormat & AC_SRC_ALPHA))
1880 format = get_format_without_alpha( format );
1881 else if (format != WXR_FORMAT_A8R8G8B8 || info->bmiHeader.biCompression != BI_RGB)
1882 return ERROR_INVALID_PARAMETER;
1884 if (!(pict_format = pict_formats[format])) goto update_format;
1886 /* make sure we can create an image with the same bpp */
1887 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
1890 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
1893 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1895 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
1898 double xscale, yscale;
1902 xscale = src->width / (double)dst->width;
1903 yscale = src->height / (double)dst->height;
1905 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1907 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
1909 EnterCriticalSection( &xrender_cs );
1910 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
1912 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
1913 src->x, src->y, src->width, src->height,
1914 physdev->x11dev->dc_rect.left + dst->x,
1915 physdev->x11dev->dc_rect.top + dst->y,
1916 dst->width, dst->height, xscale, yscale );
1918 pXRenderFreePicture( gdi_display, src_pict );
1919 XFreePixmap( gdi_display, src_pixmap );
1921 LeaveCriticalSection( &xrender_cs );
1922 add_device_bounds( physdev->x11dev, &dst->visrect );
1927 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1928 set_color_info( physdev->pict_format, info );
1929 return ERROR_BAD_FORMAT;
1933 /***********************************************************************
1934 * xrenderdrv_AlphaBlend
1936 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
1937 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
1939 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1940 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1941 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
1942 XRenderPictureAttributes pa;
1943 Pixmap tmp_pixmap = 0;
1944 double xscale, yscale;
1946 if (src_dev->funcs != dst_dev->funcs)
1948 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
1949 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
1952 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
1954 SetLastError( ERROR_INVALID_PARAMETER );
1958 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1960 xscale = src->width / (double)dst->width;
1961 yscale = src->height / (double)dst->height;
1963 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1965 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1967 /* mono -> color blending needs an intermediate color pixmap */
1968 XRenderColor fg, bg;
1969 int width = src->visrect.right - src->visrect.left;
1970 int height = src->visrect.bottom - src->visrect.top;
1972 /* blending doesn't use the destination DC colors */
1973 fg.red = fg.green = fg.blue = 0;
1974 bg.red = bg.green = bg.blue = 0xffff;
1975 fg.alpha = bg.alpha = 0xffff;
1977 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
1978 physdev_dst->pict_format->depth );
1979 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format, 0, NULL );
1981 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
1982 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
1984 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
1986 /* we need a source picture with no alpha */
1987 enum wxr_format format = get_format_without_alpha( physdev_src->format );
1988 if (format != physdev_src->format)
1990 pa.subwindow_mode = IncludeInferiors;
1991 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
1992 pict_formats[format], CPSubwindowMode, &pa );
1996 if (tmp_pict) src_pict = tmp_pict;
1998 EnterCriticalSection( &xrender_cs );
1999 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2001 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2002 physdev_src->x11dev->dc_rect.left + src->x,
2003 physdev_src->x11dev->dc_rect.top + src->y,
2004 src->width, src->height,
2005 physdev_dst->x11dev->dc_rect.left + dst->x,
2006 physdev_dst->x11dev->dc_rect.top + dst->y,
2007 dst->width, dst->height, xscale, yscale );
2009 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2010 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2012 LeaveCriticalSection( &xrender_cs );
2013 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2017 /***********************************************************************
2018 * xrenderdrv_GradientFill
2020 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2021 void * grad_array, ULONG ngrad, ULONG mode )
2023 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2024 static const XFixed stops[2] = { 0, 1 << 16 };
2025 struct xrender_physdev *physdev = get_xrender_dev( dev );
2026 XLinearGradient gradient;
2027 XRenderColor colors[2];
2028 Picture src_pict, dst_pict;
2030 const GRADIENT_RECT *rect = grad_array;
2034 if (!pXRenderCreateLinearGradient) goto fallback;
2036 /* <= 16-bpp uses dithering */
2037 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2041 case GRADIENT_FILL_RECT_H:
2042 case GRADIENT_FILL_RECT_V:
2043 for (i = 0; i < ngrad; i++, rect++)
2045 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2046 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2048 colors[0].red = v1->Red * 257 / 256;
2049 colors[0].green = v1->Green * 257 / 256;
2050 colors[0].blue = v1->Blue * 257 / 256;
2051 colors[1].red = v2->Red * 257 / 256;
2052 colors[1].green = v2->Green * 257 / 256;
2053 colors[1].blue = v2->Blue * 257 / 256;
2054 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2055 colors[0].alpha = colors[1].alpha = 65535;
2061 LPtoDP( dev->hdc, pt, 2 );
2062 if (mode == GRADIENT_FILL_RECT_H)
2064 gradient.p1.y = gradient.p2.y = 0;
2065 if (pt[1].x > pt[0].x)
2068 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2072 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2078 gradient.p1.x = gradient.p2.x = 0;
2079 if (pt[1].y > pt[0].y)
2082 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2086 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2091 rc.left = min( pt[0].x, pt[1].x );
2092 rc.top = min( pt[0].y, pt[1].y );
2093 rc.right = max( pt[0].x, pt[1].x );
2094 rc.bottom = max( pt[0].y, pt[1].y );
2096 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2097 mode, wine_dbgstr_rect( &rc ),
2098 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2099 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2101 dst_pict = get_xrender_picture( physdev, 0, NULL );
2103 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2104 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2105 0, 0, rc.right - rc.left, rc.bottom - rc.top,
2106 physdev->x11dev->dc_rect.left + rc.left,
2107 physdev->x11dev->dc_rect.top + rc.top,
2108 rc.right - rc.left, rc.bottom - rc.top, 1, 1 );
2109 pXRenderFreePicture( gdi_display, src_pict );
2110 add_device_bounds( physdev->x11dev, &rc );
2117 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2118 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2121 /***********************************************************************
2122 * xrenderdrv_SelectBrush
2124 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2126 struct xrender_physdev *physdev = get_xrender_dev( dev );
2128 XVisualInfo vis = default_visual;
2129 XRenderPictFormat *format = physdev->pict_format;
2131 if (!pattern) goto x11drv_fallback;
2132 if (pattern->info->bmiHeader.biBitCount == 1) goto x11drv_fallback;
2133 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2135 vis.depth = format->depth;
2136 vis.red_mask = format->direct.redMask << format->direct.red;
2137 vis.green_mask = format->direct.greenMask << format->direct.green;
2138 vis.blue_mask = format->direct.blueMask << format->direct.blue;
2140 pixmap = create_pixmap_from_image( physdev->dev.hdc, &vis, pattern->info,
2141 &pattern->bits, pattern->usage );
2142 if (!pixmap) return 0;
2144 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2145 physdev->x11dev->brush.pixmap = pixmap;
2146 physdev->x11dev->brush.fillStyle = FillTiled;
2147 physdev->x11dev->brush.pixel = 0; /* ignored */
2148 physdev->x11dev->brush.style = BS_PATTERN;
2152 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2153 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2157 static const struct gdi_dc_funcs xrender_funcs =
2159 NULL, /* pAbortDoc */
2160 NULL, /* pAbortPath */
2161 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2162 NULL, /* pAngleArc */
2165 NULL, /* pBeginPath */
2166 xrenderdrv_BlendImage, /* pBlendImage */
2168 NULL, /* pCloseFigure */
2169 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2170 xrenderdrv_CreateDC, /* pCreateDC */
2171 xrenderdrv_DeleteDC, /* pDeleteDC */
2172 NULL, /* pDeleteObject */
2173 NULL, /* pDeviceCapabilities */
2174 NULL, /* pEllipse */
2176 NULL, /* pEndPage */
2177 NULL, /* pEndPath */
2178 NULL, /* pEnumFonts */
2179 NULL, /* pEnumICMProfiles */
2180 NULL, /* pExcludeClipRect */
2181 NULL, /* pExtDeviceMode */
2182 xrenderdrv_ExtEscape, /* pExtEscape */
2183 NULL, /* pExtFloodFill */
2184 NULL, /* pExtSelectClipRgn */
2185 xrenderdrv_ExtTextOut, /* pExtTextOut */
2186 NULL, /* pFillPath */
2187 NULL, /* pFillRgn */
2188 NULL, /* pFlattenPath */
2189 NULL, /* pFontIsLinked */
2190 NULL, /* pFrameRgn */
2191 NULL, /* pGdiComment */
2192 NULL, /* pGdiRealizationInfo */
2193 NULL, /* pGetBoundsRect */
2194 NULL, /* pGetCharABCWidths */
2195 NULL, /* pGetCharABCWidthsI */
2196 NULL, /* pGetCharWidth */
2197 NULL, /* pGetDeviceCaps */
2198 NULL, /* pGetDeviceGammaRamp */
2199 NULL, /* pGetFontData */
2200 NULL, /* pGetFontUnicodeRanges */
2201 NULL, /* pGetGlyphIndices */
2202 NULL, /* pGetGlyphOutline */
2203 NULL, /* pGetICMProfile */
2204 NULL, /* pGetImage */
2205 NULL, /* pGetKerningPairs */
2206 NULL, /* pGetNearestColor */
2207 NULL, /* pGetOutlineTextMetrics */
2208 NULL, /* pGetPixel */
2209 NULL, /* pGetSystemPaletteEntries */
2210 NULL, /* pGetTextCharsetInfo */
2211 NULL, /* pGetTextExtentExPoint */
2212 NULL, /* pGetTextExtentExPointI */
2213 NULL, /* pGetTextFace */
2214 NULL, /* pGetTextMetrics */
2215 xrenderdrv_GradientFill, /* pGradientFill */
2216 NULL, /* pIntersectClipRect */
2217 NULL, /* pInvertRgn */
2219 NULL, /* pModifyWorldTransform */
2221 NULL, /* pOffsetClipRgn */
2222 NULL, /* pOffsetViewportOrg */
2223 NULL, /* pOffsetWindowOrg */
2224 NULL, /* pPaintRgn */
2227 NULL, /* pPolyBezier */
2228 NULL, /* pPolyBezierTo */
2229 NULL, /* pPolyDraw */
2230 NULL, /* pPolyPolygon */
2231 NULL, /* pPolyPolyline */
2232 NULL, /* pPolygon */
2233 NULL, /* pPolyline */
2234 NULL, /* pPolylineTo */
2235 xrenderdrv_PutImage, /* pPutImage */
2236 NULL, /* pRealizeDefaultPalette */
2237 NULL, /* pRealizePalette */
2238 NULL, /* pRectangle */
2239 NULL, /* pResetDC */
2240 NULL, /* pRestoreDC */
2241 NULL, /* pRoundRect */
2243 NULL, /* pScaleViewportExt */
2244 NULL, /* pScaleWindowExt */
2245 NULL, /* pSelectBitmap */
2246 xrenderdrv_SelectBrush, /* pSelectBrush */
2247 NULL, /* pSelectClipPath */
2248 xrenderdrv_SelectFont, /* pSelectFont */
2249 NULL, /* pSelectPalette */
2250 NULL, /* pSelectPen */
2251 NULL, /* pSetArcDirection */
2252 NULL, /* pSetBkColor */
2253 NULL, /* pSetBkMode */
2254 NULL, /* pSetBoundsRect */
2255 NULL, /* pSetDCBrushColor */
2256 NULL, /* pSetDCPenColor */
2257 NULL, /* pSetDIBitsToDevice */
2258 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2259 NULL, /* pSetDeviceGammaRamp */
2260 NULL, /* pSetLayout */
2261 NULL, /* pSetMapMode */
2262 NULL, /* pSetMapperFlags */
2263 NULL, /* pSetPixel */
2264 NULL, /* pSetPolyFillMode */
2265 NULL, /* pSetROP2 */
2266 NULL, /* pSetRelAbs */
2267 NULL, /* pSetStretchBltMode */
2268 NULL, /* pSetTextAlign */
2269 NULL, /* pSetTextCharacterExtra */
2270 NULL, /* pSetTextColor */
2271 NULL, /* pSetTextJustification */
2272 NULL, /* pSetViewportExt */
2273 NULL, /* pSetViewportOrg */
2274 NULL, /* pSetWindowExt */
2275 NULL, /* pSetWindowOrg */
2276 NULL, /* pSetWorldTransform */
2277 NULL, /* pStartDoc */
2278 NULL, /* pStartPage */
2279 xrenderdrv_StretchBlt, /* pStretchBlt */
2280 NULL, /* pStretchDIBits */
2281 NULL, /* pStrokeAndFillPath */
2282 NULL, /* pStrokePath */
2283 NULL, /* pUnrealizePalette */
2284 NULL, /* pWidenPath */
2285 NULL, /* wine_get_wgl_driver */
2286 GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
2289 #else /* SONAME_LIBXRENDER */
2291 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2293 TRACE("XRender support not compiled in.\n");
2297 #endif /* SONAME_LIBXRENDER */