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);
1116 wxr_format = WXR_FORMAT_MONO;
1120 formatEntry->font_format = pict_formats[wxr_format];
1121 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1125 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1126 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1127 formatEntry->realized[glyph] = TRUE;
1129 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
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)) {
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;
1151 for(j = 0; j < pitch * 8; j++) {
1152 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1154 TRACE("%s\n", output);
1157 static const char blks[] = " .:;!o*#";
1161 pitch = ((gi.width + 3) / 4) * 4;
1162 for(i = 0; i < gi.height; i++) {
1163 line = (unsigned char*) buf + i * pitch;
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;
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);
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);
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
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 /*************************************************************
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)
1229 XRenderColor current_color;
1230 } tiles[WXR_NB_FORMATS], *tile;
1232 tile = &tiles[wxr_format];
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 */
1252 col.red = col.green = col.blue = 0;
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;
1266 /*************************************************************
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 */
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 );
1291 if (alpha != current_alpha)
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 );
1301 /***********************************************************************
1302 * xrenderdrv_ExtTextOut
1304 static BOOL 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;
1311 Picture pict, tile_pict = 0;
1313 POINT offset, desired, current;
1314 int render_op = PictOpOver;
1318 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1319 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1321 if(flags & ETO_OPAQUE)
1325 if (physdev->format == WXR_FORMAT_MONO)
1326 /* use the inverse of the text color */
1327 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1329 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1331 set_xrender_transformation( pict, 1, 1, 0, 0 );
1332 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1333 physdev->x11dev->dc_rect.left + lprect->left,
1334 physdev->x11dev->dc_rect.top + lprect->top,
1335 lprect->right - lprect->left,
1336 lprect->bottom - lprect->top );
1337 add_device_bounds( physdev->x11dev, lprect );
1340 if(count == 0) return TRUE;
1342 EnterCriticalSection(&xrender_cs);
1344 entry = glyphsetCache + physdev->cache_index;
1345 formatEntry = entry->format[aa_type_from_flags( physdev->aa_flags )];
1347 for(idx = 0; idx < count; idx++) {
1348 if( !formatEntry ) {
1349 UploadGlyph(physdev, wstr[idx]);
1350 /* re-evaluate format entry since aa_flags may have changed */
1351 formatEntry = entry->format[aa_type_from_flags( physdev->aa_flags )];
1352 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1353 UploadGlyph(physdev, wstr[idx]);
1358 WARN("could not upload requested glyphs\n");
1359 LeaveCriticalSection(&xrender_cs);
1363 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1364 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1366 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1368 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1369 So we pass zeros to the function and move to our starting position using the first
1370 element of the elts array. */
1372 desired.x = physdev->x11dev->dc_rect.left + x;
1373 desired.y = physdev->x11dev->dc_rect.top + y;
1374 offset.x = offset.y = 0;
1375 current.x = current.y = 0;
1377 tile_pict = get_tile_pict(physdev->format, &col);
1379 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1381 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1382 render_op = PictOpOutReverse; /* This gives us 'black' text */
1384 reset_bounds( &bounds );
1385 for(idx = 0; idx < count; idx++)
1387 elts[idx].glyphset = formatEntry->glyphset;
1388 elts[idx].chars = wstr + idx;
1389 elts[idx].nchars = 1;
1390 elts[idx].xOff = desired.x - current.x;
1391 elts[idx].yOff = desired.y - current.y;
1393 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1394 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1396 rect.left = desired.x - physdev->x11dev->dc_rect.left - formatEntry->gis[wstr[idx]].x;
1397 rect.top = desired.y - physdev->x11dev->dc_rect.top - formatEntry->gis[wstr[idx]].y;
1398 rect.right = rect.left + formatEntry->gis[wstr[idx]].width;
1399 rect.bottom = rect.top + formatEntry->gis[wstr[idx]].height;
1400 add_bounds_rect( &bounds, &rect );
1404 desired.x += formatEntry->gis[wstr[idx]].xOff;
1405 desired.y += formatEntry->gis[wstr[idx]].yOff;
1411 offset.x += lpDx[idx * 2];
1412 offset.y += lpDx[idx * 2 + 1];
1415 offset.x += lpDx[idx];
1416 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1417 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1421 /* Make sure we don't have any transforms set from a previous call */
1422 set_xrender_transformation(pict, 1, 1, 0, 0);
1423 pXRenderCompositeText16(gdi_display, render_op,
1426 formatEntry->font_format,
1427 0, 0, 0, 0, elts, count);
1428 HeapFree(GetProcessHeap(), 0, elts);
1430 LeaveCriticalSection(&xrender_cs);
1431 add_device_bounds( physdev->x11dev, &bounds );
1435 /* multiply the alpha channel of a picture */
1436 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1437 int x, int y, int width, int height )
1439 XRenderPictureAttributes pa;
1440 Pixmap src_pixmap, mask_pixmap;
1441 Picture src_pict, mask_pict;
1444 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1445 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1446 pa.repeat = RepeatNormal;
1447 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1448 pa.component_alpha = True;
1449 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1450 color.red = color.green = color.blue = color.alpha = 0xffff;
1451 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1452 color.alpha = alpha;
1453 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1454 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1455 0, 0, 0, 0, x, y, width, height );
1456 pXRenderFreePicture( gdi_display, src_pict );
1457 pXRenderFreePicture( gdi_display, mask_pict );
1458 XFreePixmap( gdi_display, src_pixmap );
1459 XFreePixmap( gdi_display, mask_pixmap );
1462 /* Helper function for (stretched) blitting using xrender */
1463 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1464 int x_src, int y_src, int width_src, int height_src,
1465 int x_dst, int y_dst, int width_dst, int height_dst,
1466 double xscale, double yscale )
1468 int x_offset, y_offset;
1472 x_src += width_src + 1;
1473 width_src = -width_src;
1477 y_src += height_src + 1;
1478 height_src = -height_src;
1482 x_dst += width_dst + 1;
1483 width_dst = -width_dst;
1487 y_dst += height_dst + 1;
1488 height_dst = -height_dst;
1491 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1492 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1493 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1494 if(xscale != 1.0 || yscale != 1.0)
1496 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1497 * in the wrong quadrant of the x-y plane.
1499 x_offset = (xscale < 0) ? -width_dst : 0;
1500 y_offset = (yscale < 0) ? -height_dst : 0;
1501 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1507 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1509 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1510 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1513 /* Helper function for (stretched) mono->color blitting using xrender */
1514 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1515 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1516 int x_src, int y_src, int width_src, int height_src,
1517 int x_dst, int y_dst, int width_dst, int height_dst,
1518 double xscale, double yscale )
1521 int x_offset, y_offset;
1526 x_src += width_src + 1;
1527 width_src = -width_src;
1531 y_src += height_src + 1;
1532 height_src = -height_src;
1536 x_dst += width_dst + 1;
1537 width_dst = -width_dst;
1541 y_dst += height_dst + 1;
1542 height_dst = -height_dst;
1545 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1546 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1549 EnterCriticalSection( &xrender_cs );
1551 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1552 tile_pict = get_tile_pict( dst_format, &color );
1554 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1556 if (xscale != 1.0 || yscale != 1.0)
1558 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1559 * in the wrong quadrant of the x-y plane.
1561 x_offset = (xscale < 0) ? -width_dst : 0;
1562 y_offset = (yscale < 0) ? -height_dst : 0;
1563 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1569 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1571 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1572 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1573 LeaveCriticalSection( &xrender_cs );
1575 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1576 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1577 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1578 x_dst, y_dst, width_dst, height_dst );
1581 /* create a pixmap and render picture for an image */
1582 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1583 struct bitblt_coords *src, enum wxr_format format,
1584 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1587 int width = src->visrect.right - src->visrect.left;
1588 int height = src->visrect.bottom - src->visrect.top;
1589 int depth = pict_formats[format]->depth;
1590 struct gdi_image_bits dst_bits;
1591 XRenderPictureAttributes pa;
1595 image = XCreateImage( gdi_display, default_visual.visual, depth, ZPixmap, 0, NULL,
1596 info->bmiHeader.biWidth, height, 32, 0 );
1597 if (!image) return ERROR_OUTOFMEMORY;
1599 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1600 if (ret) return ret;
1602 image->data = dst_bits.ptr;
1604 *use_repeat = (width == 1 && height == 1);
1605 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1607 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1608 gc = XCreateGC( gdi_display, *pixmap, 0, NULL );
1609 XPutImage( gdi_display, *pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1610 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1611 XFreeGC( gdi_display, gc );
1613 /* make coordinates relative to the pixmap */
1614 src->x -= src->visrect.left;
1615 src->y -= src->visrect.top;
1616 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1619 XDestroyImage( image );
1620 if (dst_bits.free) dst_bits.free( &dst_bits );
1624 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1625 Drawable drawable, const struct bitblt_coords *src,
1626 const struct bitblt_coords *dst )
1629 Picture src_pict = 0, dst_pict, mask_pict = 0;
1630 double xscale = src->width / (double)dst->width;
1631 double yscale = src->height / (double)dst->height;
1633 if (drawable) /* using an intermediate pixmap */
1637 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, 0, NULL );
1641 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
1642 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
1643 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1646 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1649 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1651 XRenderColor fg, bg;
1653 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
1654 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
1655 fg.alpha = bg.alpha = 0;
1657 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
1658 physdev_src->x11dev->dc_rect.left + src->x,
1659 physdev_src->x11dev->dc_rect.top + src->y,
1660 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1662 else /* color -> color (can be at different depths) or mono -> mono */
1664 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
1665 mask_pict = get_no_alpha_mask();
1667 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
1668 physdev_src->x11dev->dc_rect.left + src->x,
1669 physdev_src->x11dev->dc_rect.top + src->y,
1670 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1673 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1677 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
1678 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
1679 Drawable drawable, struct bitblt_coords *src,
1680 struct bitblt_coords *dst, BOOL use_repeat )
1684 double xscale, yscale;
1686 if (drawable) /* using an intermediate pixmap */
1688 RGNDATA *clip_data = NULL;
1690 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1693 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL );
1695 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
1696 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
1697 HeapFree( GetProcessHeap(), 0, clip_data );
1701 x_dst = physdev->x11dev->dc_rect.left + dst->x;
1702 y_dst = physdev->x11dev->dc_rect.top + dst->y;
1703 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
1708 xscale = src->width / (double)dst->width;
1709 yscale = src->height / (double)dst->height;
1711 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1713 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
1714 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1716 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1720 /***********************************************************************
1721 * xrenderdrv_StretchBlt
1723 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1724 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1726 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1727 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1728 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
1730 if (src_dev->funcs != dst_dev->funcs)
1732 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
1733 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
1736 /* XRender is of no use for color -> mono */
1737 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
1738 goto x11drv_fallback;
1740 /* if not stretching, we only need to handle format conversion */
1741 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
1747 struct bitblt_coords tmp;
1749 /* make coordinates relative to tmp pixmap */
1751 tmp.x -= tmp.visrect.left;
1752 tmp.y -= tmp.visrect.top;
1753 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1755 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
1756 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1757 XSetGraphicsExposures( gdi_display, tmpGC, False );
1758 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
1759 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
1761 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
1762 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
1764 XFreePixmap( gdi_display, tmp_pixmap );
1765 XFreeGC( gdi_display, tmpGC );
1767 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
1769 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
1773 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
1777 /***********************************************************************
1778 * xrenderdrv_PutImage
1780 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1781 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1782 struct bitblt_coords *dst, DWORD rop )
1784 struct xrender_physdev *physdev = get_xrender_dev( dev );
1788 enum wxr_format src_format, dst_format;
1789 XRenderPictFormat *pict_format;
1791 Picture src_pict, mask_pict = 0;
1794 dst_format = physdev->format;
1795 src_format = get_xrender_format_from_bitmapinfo( info );
1796 if (!(pict_format = pict_formats[src_format])) goto update_format;
1798 /* make sure we can create an image with the same bpp */
1799 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
1802 /* mono <-> color conversions not supported */
1803 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
1804 goto x11drv_fallback;
1806 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1808 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
1810 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
1813 struct bitblt_coords tmp;
1817 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
1819 /* make coordinates relative to tmp pixmap */
1821 tmp.x -= tmp.visrect.left;
1822 tmp.y -= tmp.visrect.top;
1823 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1825 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
1826 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1827 XSetGraphicsExposures( gdi_display, gc, False );
1828 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
1829 tmp.visrect.right - tmp.visrect.left,
1830 tmp.visrect.bottom - tmp.visrect.top,
1831 physdev->pict_format->depth );
1833 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
1834 NULL, tmp_pixmap, src, &tmp, use_repeat );
1835 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
1837 XFreePixmap( gdi_display, tmp_pixmap );
1838 XFreeGC( gdi_display, gc );
1839 if (restore_region) restore_clipping_region( physdev->x11dev );
1841 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
1842 physdev->pict_format, physdev, 0, src, dst, use_repeat );
1844 add_device_bounds( physdev->x11dev, &dst->visrect );
1846 pXRenderFreePicture( gdi_display, src_pict );
1847 XFreePixmap( gdi_display, src_pixmap );
1852 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1853 set_color_info( pict_formats[dst_format], info );
1854 return ERROR_BAD_FORMAT;
1857 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
1858 return dev->funcs->pPutImage( dev, clip, info, bits, src, dst, rop );
1862 /***********************************************************************
1863 * xrenderdrv_BlendImage
1865 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
1866 struct bitblt_coords *src, struct bitblt_coords *dst,
1867 BLENDFUNCTION func )
1869 struct xrender_physdev *physdev = get_xrender_dev( dev );
1871 enum wxr_format format;
1872 XRenderPictFormat *pict_format;
1873 Picture dst_pict, src_pict, mask_pict;
1877 format = get_xrender_format_from_bitmapinfo( info );
1878 if (!(func.AlphaFormat & AC_SRC_ALPHA))
1879 format = get_format_without_alpha( format );
1880 else if (format != WXR_FORMAT_A8R8G8B8 || info->bmiHeader.biCompression != BI_RGB)
1881 return ERROR_INVALID_PARAMETER;
1883 if (!(pict_format = pict_formats[format])) goto update_format;
1885 /* make sure we can create an image with the same bpp */
1886 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
1889 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
1892 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1894 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
1897 double xscale, yscale;
1901 xscale = src->width / (double)dst->width;
1902 yscale = src->height / (double)dst->height;
1904 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1906 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
1908 EnterCriticalSection( &xrender_cs );
1909 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
1911 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
1912 src->x, src->y, src->width, src->height,
1913 physdev->x11dev->dc_rect.left + dst->x,
1914 physdev->x11dev->dc_rect.top + dst->y,
1915 dst->width, dst->height, xscale, yscale );
1917 pXRenderFreePicture( gdi_display, src_pict );
1918 XFreePixmap( gdi_display, src_pixmap );
1920 LeaveCriticalSection( &xrender_cs );
1921 add_device_bounds( physdev->x11dev, &dst->visrect );
1926 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1927 set_color_info( physdev->pict_format, info );
1928 return ERROR_BAD_FORMAT;
1932 /***********************************************************************
1933 * xrenderdrv_AlphaBlend
1935 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
1936 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
1938 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1939 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1940 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
1941 XRenderPictureAttributes pa;
1942 Pixmap tmp_pixmap = 0;
1943 double xscale, yscale;
1945 if (src_dev->funcs != dst_dev->funcs)
1947 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
1948 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
1951 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
1953 SetLastError( ERROR_INVALID_PARAMETER );
1957 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1959 xscale = src->width / (double)dst->width;
1960 yscale = src->height / (double)dst->height;
1962 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1964 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1966 /* mono -> color blending needs an intermediate color pixmap */
1967 XRenderColor fg, bg;
1968 int width = src->visrect.right - src->visrect.left;
1969 int height = src->visrect.bottom - src->visrect.top;
1971 /* blending doesn't use the destination DC colors */
1972 fg.red = fg.green = fg.blue = 0;
1973 bg.red = bg.green = bg.blue = 0xffff;
1974 fg.alpha = bg.alpha = 0xffff;
1976 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
1977 physdev_dst->pict_format->depth );
1978 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format, 0, NULL );
1980 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
1981 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
1983 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
1985 /* we need a source picture with no alpha */
1986 enum wxr_format format = get_format_without_alpha( physdev_src->format );
1987 if (format != physdev_src->format)
1989 pa.subwindow_mode = IncludeInferiors;
1990 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
1991 pict_formats[format], CPSubwindowMode, &pa );
1995 if (tmp_pict) src_pict = tmp_pict;
1997 EnterCriticalSection( &xrender_cs );
1998 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2000 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2001 physdev_src->x11dev->dc_rect.left + src->x,
2002 physdev_src->x11dev->dc_rect.top + src->y,
2003 src->width, src->height,
2004 physdev_dst->x11dev->dc_rect.left + dst->x,
2005 physdev_dst->x11dev->dc_rect.top + dst->y,
2006 dst->width, dst->height, xscale, yscale );
2008 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2009 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2011 LeaveCriticalSection( &xrender_cs );
2012 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2016 /***********************************************************************
2017 * xrenderdrv_GradientFill
2019 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2020 void * grad_array, ULONG ngrad, ULONG mode )
2022 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2023 static const XFixed stops[2] = { 0, 1 << 16 };
2024 struct xrender_physdev *physdev = get_xrender_dev( dev );
2025 XLinearGradient gradient;
2026 XRenderColor colors[2];
2027 Picture src_pict, dst_pict;
2029 const GRADIENT_RECT *rect = grad_array;
2033 if (!pXRenderCreateLinearGradient) goto fallback;
2035 /* <= 16-bpp uses dithering */
2036 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2040 case GRADIENT_FILL_RECT_H:
2041 case GRADIENT_FILL_RECT_V:
2042 for (i = 0; i < ngrad; i++, rect++)
2044 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2045 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2047 colors[0].red = v1->Red * 257 / 256;
2048 colors[0].green = v1->Green * 257 / 256;
2049 colors[0].blue = v1->Blue * 257 / 256;
2050 colors[1].red = v2->Red * 257 / 256;
2051 colors[1].green = v2->Green * 257 / 256;
2052 colors[1].blue = v2->Blue * 257 / 256;
2053 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2054 colors[0].alpha = colors[1].alpha = 65535;
2060 LPtoDP( dev->hdc, pt, 2 );
2061 if (mode == GRADIENT_FILL_RECT_H)
2063 gradient.p1.y = gradient.p2.y = 0;
2064 if (pt[1].x > pt[0].x)
2067 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2071 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2077 gradient.p1.x = gradient.p2.x = 0;
2078 if (pt[1].y > pt[0].y)
2081 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2085 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2090 rc.left = min( pt[0].x, pt[1].x );
2091 rc.top = min( pt[0].y, pt[1].y );
2092 rc.right = max( pt[0].x, pt[1].x );
2093 rc.bottom = max( pt[0].y, pt[1].y );
2095 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2096 mode, wine_dbgstr_rect( &rc ),
2097 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2098 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2100 dst_pict = get_xrender_picture( physdev, 0, NULL );
2102 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2103 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2104 0, 0, rc.right - rc.left, rc.bottom - rc.top,
2105 physdev->x11dev->dc_rect.left + rc.left,
2106 physdev->x11dev->dc_rect.top + rc.top,
2107 rc.right - rc.left, rc.bottom - rc.top, 1, 1 );
2108 pXRenderFreePicture( gdi_display, src_pict );
2109 add_device_bounds( physdev->x11dev, &rc );
2116 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2117 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2120 /***********************************************************************
2121 * xrenderdrv_SelectBrush
2123 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2125 struct xrender_physdev *physdev = get_xrender_dev( dev );
2127 XVisualInfo vis = default_visual;
2128 XRenderPictFormat *format = physdev->pict_format;
2130 if (!pattern) goto x11drv_fallback;
2131 if (pattern->info->bmiHeader.biBitCount == 1) goto x11drv_fallback;
2132 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2134 vis.depth = format->depth;
2135 vis.red_mask = format->direct.redMask << format->direct.red;
2136 vis.green_mask = format->direct.greenMask << format->direct.green;
2137 vis.blue_mask = format->direct.blueMask << format->direct.blue;
2139 pixmap = create_pixmap_from_image( physdev->dev.hdc, &vis, pattern->info,
2140 &pattern->bits, pattern->usage );
2141 if (!pixmap) return 0;
2143 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2144 physdev->x11dev->brush.pixmap = pixmap;
2145 physdev->x11dev->brush.fillStyle = FillTiled;
2146 physdev->x11dev->brush.pixel = 0; /* ignored */
2147 physdev->x11dev->brush.style = BS_PATTERN;
2151 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2152 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2156 static const struct gdi_dc_funcs xrender_funcs =
2158 NULL, /* pAbortDoc */
2159 NULL, /* pAbortPath */
2160 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2161 NULL, /* pAngleArc */
2164 NULL, /* pBeginPath */
2165 xrenderdrv_BlendImage, /* pBlendImage */
2167 NULL, /* pCloseFigure */
2168 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2169 xrenderdrv_CreateDC, /* pCreateDC */
2170 xrenderdrv_DeleteDC, /* pDeleteDC */
2171 NULL, /* pDeleteObject */
2172 NULL, /* pDeviceCapabilities */
2173 NULL, /* pEllipse */
2175 NULL, /* pEndPage */
2176 NULL, /* pEndPath */
2177 NULL, /* pEnumFonts */
2178 NULL, /* pEnumICMProfiles */
2179 NULL, /* pExcludeClipRect */
2180 NULL, /* pExtDeviceMode */
2181 xrenderdrv_ExtEscape, /* pExtEscape */
2182 NULL, /* pExtFloodFill */
2183 NULL, /* pExtSelectClipRgn */
2184 xrenderdrv_ExtTextOut, /* pExtTextOut */
2185 NULL, /* pFillPath */
2186 NULL, /* pFillRgn */
2187 NULL, /* pFlattenPath */
2188 NULL, /* pFontIsLinked */
2189 NULL, /* pFrameRgn */
2190 NULL, /* pGdiComment */
2191 NULL, /* pGdiRealizationInfo */
2192 NULL, /* pGetBoundsRect */
2193 NULL, /* pGetCharABCWidths */
2194 NULL, /* pGetCharABCWidthsI */
2195 NULL, /* pGetCharWidth */
2196 NULL, /* pGetDeviceCaps */
2197 NULL, /* pGetDeviceGammaRamp */
2198 NULL, /* pGetFontData */
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 */
2218 NULL, /* pModifyWorldTransform */
2220 NULL, /* pOffsetClipRgn */
2221 NULL, /* pOffsetViewportOrg */
2222 NULL, /* pOffsetWindowOrg */
2223 NULL, /* pPaintRgn */
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 */
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, /* wine_get_wgl_driver */
2285 GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
2288 #else /* SONAME_LIBXRENDER */
2290 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2292 TRACE("XRender support not compiled in.\n");
2296 #endif /* SONAME_LIBXRENDER */