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;
150 gsCacheEntryFormat * format[AA_MAXVALUE];
155 struct xrender_physdev
157 struct gdi_physdev dev;
158 X11DRV_PDEVICE *x11dev;
160 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 int antialias = 1;
184 static void *xrender_handle;
186 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
187 MAKE_FUNCPTR(XRenderAddGlyphs)
188 MAKE_FUNCPTR(XRenderChangePicture)
189 MAKE_FUNCPTR(XRenderComposite)
190 MAKE_FUNCPTR(XRenderCompositeText16)
191 MAKE_FUNCPTR(XRenderCreateGlyphSet)
192 MAKE_FUNCPTR(XRenderCreatePicture)
193 MAKE_FUNCPTR(XRenderFillRectangle)
194 MAKE_FUNCPTR(XRenderFindFormat)
195 MAKE_FUNCPTR(XRenderFindVisualFormat)
196 MAKE_FUNCPTR(XRenderFreeGlyphSet)
197 MAKE_FUNCPTR(XRenderFreePicture)
198 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
199 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
200 MAKE_FUNCPTR(XRenderCreateLinearGradient)
202 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
203 MAKE_FUNCPTR(XRenderSetPictureTransform)
205 MAKE_FUNCPTR(XRenderQueryExtension)
207 #ifdef SONAME_LIBFONTCONFIG
208 #include <fontconfig/fontconfig.h>
209 MAKE_FUNCPTR(FcConfigSubstitute)
210 MAKE_FUNCPTR(FcDefaultSubstitute)
211 MAKE_FUNCPTR(FcFontMatch)
213 MAKE_FUNCPTR(FcPatternCreate)
214 MAKE_FUNCPTR(FcPatternDestroy)
215 MAKE_FUNCPTR(FcPatternAddInteger)
216 MAKE_FUNCPTR(FcPatternAddString)
217 MAKE_FUNCPTR(FcPatternGetBool)
218 MAKE_FUNCPTR(FcPatternGetInteger)
219 MAKE_FUNCPTR(FcPatternGetString)
220 static void *fontconfig_handle;
221 static BOOL fontconfig_installed;
226 static CRITICAL_SECTION xrender_cs;
227 static CRITICAL_SECTION_DEBUG critsect_debug =
230 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
231 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
233 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
235 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
236 ( ( (ULONG)_x4 << 24 ) | \
237 ( (ULONG)_x3 << 16 ) | \
238 ( (ULONG)_x2 << 8 ) | \
241 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
243 #define GASP_GRIDFIT 0x01
244 #define GASP_DOGRAY 0x02
246 #ifdef WORDS_BIGENDIAN
247 #define get_be_word(x) (x)
248 #define NATIVE_BYTE_ORDER MSBFirst
250 #define get_be_word(x) RtlUshortByteSwap(x)
251 #define NATIVE_BYTE_ORDER LSBFirst
254 static BOOL has_alpha( enum wxr_format format )
256 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
259 static enum wxr_format get_format_without_alpha( enum wxr_format format )
263 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
264 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
265 default: return format;
269 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
272 templ->type = PictTypeDirect;
273 templ->depth = fmt->depth;
274 templ->direct.alpha = fmt->alpha;
275 templ->direct.alphaMask = fmt->alphaMask;
276 templ->direct.red = fmt->red;
277 templ->direct.redMask = fmt->redMask;
278 templ->direct.green = fmt->green;
279 templ->direct.greenMask = fmt->greenMask;
280 templ->direct.blue = fmt->blue;
281 templ->direct.blueMask = fmt->blueMask;
284 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
289 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
291 if(fmt->depth != default_visual.depth) return FALSE;
292 if( (fmt->redMask << fmt->red) != default_visual.red_mask) return FALSE;
293 if( (fmt->greenMask << fmt->green) != default_visual.green_mask) return FALSE;
294 if( (fmt->blueMask << fmt->blue) != default_visual.blue_mask) return FALSE;
296 /* We never select a default ARGB visual */
297 if(fmt->alphaMask) return FALSE;
301 static int load_xrender_formats(void)
306 for (i = 0; i < WXR_NB_FORMATS; i++)
308 XRenderPictFormat templ;
310 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
312 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, default_visual.visual);
313 if (!pict_formats[i])
315 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
316 if (default_visual.class == DirectColor)
319 if (XMatchVisualInfo( gdi_display, default_visual.screen,
320 default_visual.depth, TrueColor, &info ))
322 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
323 if (pict_formats[i]) default_visual = info;
327 if (pict_formats[i]) default_format = i;
331 unsigned long mask = 0;
332 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
333 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
338 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
344 /***********************************************************************
345 * X11DRV_XRender_Init
347 * Let's see if our XServer has the extension available
350 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
354 if (!client_side_with_render) return NULL;
355 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
357 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
358 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
359 LOAD_FUNCPTR(XRenderAddGlyphs);
360 LOAD_FUNCPTR(XRenderChangePicture);
361 LOAD_FUNCPTR(XRenderComposite);
362 LOAD_FUNCPTR(XRenderCompositeText16);
363 LOAD_FUNCPTR(XRenderCreateGlyphSet);
364 LOAD_FUNCPTR(XRenderCreatePicture);
365 LOAD_FUNCPTR(XRenderFillRectangle);
366 LOAD_FUNCPTR(XRenderFindFormat);
367 LOAD_FUNCPTR(XRenderFindVisualFormat);
368 LOAD_FUNCPTR(XRenderFreeGlyphSet);
369 LOAD_FUNCPTR(XRenderFreePicture);
370 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
371 LOAD_FUNCPTR(XRenderQueryExtension);
372 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
373 LOAD_OPTIONAL_FUNCPTR(XRenderCreateLinearGradient);
375 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
376 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
378 #undef LOAD_OPTIONAL_FUNCPTR
381 if (!pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base)) return NULL;
383 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
384 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
386 ERR_(winediag)("Wine has detected that you probably have a buggy version "
387 "of libXrender. Because of this client side font rendering "
388 "will be disabled. Please upgrade this library.\n");
392 if (!default_visual.red_mask || !default_visual.green_mask || !default_visual.blue_mask)
394 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
398 #ifdef SONAME_LIBFONTCONFIG
399 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
401 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fontconfig_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
402 LOAD_FUNCPTR(FcConfigSubstitute);
403 LOAD_FUNCPTR(FcDefaultSubstitute);
404 LOAD_FUNCPTR(FcFontMatch);
405 LOAD_FUNCPTR(FcInit);
406 LOAD_FUNCPTR(FcPatternCreate);
407 LOAD_FUNCPTR(FcPatternDestroy);
408 LOAD_FUNCPTR(FcPatternAddInteger);
409 LOAD_FUNCPTR(FcPatternAddString);
410 LOAD_FUNCPTR(FcPatternGetBool);
411 LOAD_FUNCPTR(FcPatternGetInteger);
412 LOAD_FUNCPTR(FcPatternGetString);
414 fontconfig_installed = pFcInit();
416 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
421 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
422 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
424 glyphsetCacheSize = INIT_CACHE_SIZE;
426 for(i = 0; i < INIT_CACHE_SIZE; i++) {
427 glyphsetCache[i].next = i + 1;
428 glyphsetCache[i].count = -1;
430 glyphsetCache[i-1].next = -1;
432 if(default_visual.depth <= 8 || !client_side_antialias_with_render) antialias = 0;
434 return &xrender_funcs;
437 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
438 static void get_xrender_color( struct xrender_physdev *physdev, COLORREF src_color, XRenderColor *dst_color )
440 if (src_color & (1 << 24)) /* PALETTEINDEX */
442 HPALETTE pal = GetCurrentObject( physdev->dev.hdc, OBJ_PAL );
443 PALETTEENTRY pal_ent;
445 if (!GetPaletteEntries( pal, LOWORD(src_color), 1, &pal_ent ))
446 GetPaletteEntries( pal, 0, 1, &pal_ent );
447 dst_color->red = pal_ent.peRed * 257;
448 dst_color->green = pal_ent.peGreen * 257;
449 dst_color->blue = pal_ent.peBlue * 257;
453 if (src_color >> 16 == 0x10ff) src_color = 0; /* DIBINDEX */
455 dst_color->red = GetRValue( src_color ) * 257;
456 dst_color->green = GetGValue( src_color ) * 257;
457 dst_color->blue = GetBValue( src_color ) * 257;
460 if (physdev->format == WXR_FORMAT_MONO && !dst_color->red && !dst_color->green && !dst_color->blue)
461 dst_color->alpha = 0;
463 dst_color->alpha = 0xffff;
466 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
468 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
470 switch (info->bmiHeader.biBitCount)
473 return WXR_FORMAT_MONO;
478 if (info->bmiHeader.biCompression != BI_RGB) break;
479 return WXR_FORMAT_R8G8B8;
482 if (info->bmiHeader.biCompression == BI_BITFIELDS)
484 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
487 for (i = 0; i < WXR_NB_FORMATS; i++)
489 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
490 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
491 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
492 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
497 if (info->bmiHeader.biCompression != BI_RGB) break;
498 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
500 return WXR_INVALID_FORMAT;
503 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
504 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
506 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
507 XTransform xform = {{
508 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
509 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
510 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
513 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
517 static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn )
519 XRenderPictureAttributes pa;
525 pXRenderChangePicture( gdi_display, dev->pict, CPClipMask, &pa );
527 else if ((data = X11DRV_GetRegionData( rgn, 0 )))
529 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
530 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
531 (XRectangle *)data->Buffer, data->rdh.nCount );
532 HeapFree( GetProcessHeap(), 0, data );
537 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
539 if (!dev->pict && dev->pict_format)
541 XRenderPictureAttributes pa;
543 pa.subwindow_mode = IncludeInferiors;
544 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
545 dev->pict_format, CPSubwindowMode, &pa );
546 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
547 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
548 dev->update_clip = (dev->region != 0);
553 HRGN rgn = CreateRectRgnIndirect( clip_rect );
554 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
555 if (dev->region) CombineRgn( rgn, rgn, dev->region, RGN_AND );
556 update_xrender_clipping( dev, rgn );
563 HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
564 CombineRgn( rgn, clip_rgn, dev->region, RGN_AND );
565 update_xrender_clipping( dev, rgn );
568 else update_xrender_clipping( dev, clip_rgn );
570 else if (dev->update_clip) update_xrender_clipping( dev, dev->region );
572 dev->update_clip = (clip_rect || clip_rgn); /* have to update again if we are using a custom region */
576 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
578 if (!dev->pict_src && dev->pict_format)
580 XRenderPictureAttributes pa;
582 pa.subwindow_mode = IncludeInferiors;
583 pa.repeat = repeat ? RepeatNormal : RepeatNone;
584 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
585 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
587 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
588 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
591 return dev->pict_src;
594 static void free_xrender_picture( struct xrender_physdev *dev )
596 if (dev->pict || dev->pict_src)
598 XFlush( gdi_display );
601 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
602 pXRenderFreePicture(gdi_display, dev->pict);
607 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
608 pXRenderFreePicture(gdi_display, dev->pict_src);
614 /* return a mask picture used to force alpha to 0 */
615 static Picture get_no_alpha_mask(void)
617 static Pixmap pixmap;
620 EnterCriticalSection( &xrender_cs );
623 XRenderPictureAttributes pa;
626 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
627 pa.repeat = RepeatNormal;
628 pa.component_alpha = True;
629 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
630 CPRepeat|CPComponentAlpha, &pa );
631 col.red = col.green = col.blue = 0xffff;
633 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
635 LeaveCriticalSection( &xrender_cs );
639 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
641 if(p1->hash != p2->hash) return TRUE;
642 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
643 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
644 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
645 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
649 static void walk_cache(void)
653 EnterCriticalSection(&xrender_cs);
654 for(i=mru; i >= 0; i = glyphsetCache[i].next)
655 TRACE("item %d\n", i);
656 LeaveCriticalSection(&xrender_cs);
660 static int LookupEntry(LFANDSIZE *plfsz)
664 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
666 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
668 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
669 glyphsetCache[i].count++;
671 glyphsetCache[prev_i].next = glyphsetCache[i].next;
672 glyphsetCache[i].next = mru;
675 TRACE("found font in cache %d\n", i);
680 TRACE("font not in cache\n");
684 static void FreeEntry(int entry)
688 for(format = 0; format < AA_MAXVALUE; format++) {
689 gsCacheEntryFormat * formatEntry;
691 if( !glyphsetCache[entry].format[format] )
694 formatEntry = glyphsetCache[entry].format[format];
696 if(formatEntry->glyphset) {
697 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
698 formatEntry->glyphset = 0;
700 if(formatEntry->nrealized) {
701 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
702 formatEntry->realized = NULL;
703 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
704 formatEntry->gis = NULL;
705 formatEntry->nrealized = 0;
708 HeapFree(GetProcessHeap(), 0, formatEntry);
709 glyphsetCache[entry].format[format] = NULL;
713 static int AllocEntry(void)
715 int best = -1, prev_best = -1, i, prev_i = -1;
718 assert(glyphsetCache[lastfree].count == -1);
719 glyphsetCache[lastfree].count = 1;
721 lastfree = glyphsetCache[lastfree].next;
723 glyphsetCache[best].next = mru;
726 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
730 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
731 if(glyphsetCache[i].count == 0) {
739 TRACE("freeing unused glyphset at cache %d\n", best);
741 glyphsetCache[best].count = 1;
743 glyphsetCache[prev_best].next = glyphsetCache[best].next;
744 glyphsetCache[best].next = mru;
752 TRACE("Growing cache\n");
755 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
757 (glyphsetCacheSize + INIT_CACHE_SIZE)
758 * sizeof(*glyphsetCache));
760 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
761 (glyphsetCacheSize + INIT_CACHE_SIZE)
762 * sizeof(*glyphsetCache));
764 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
766 glyphsetCache[i].next = i + 1;
767 glyphsetCache[i].count = -1;
769 glyphsetCache[i-1].next = -1;
770 glyphsetCacheSize += INIT_CACHE_SIZE;
772 lastfree = glyphsetCache[best].next;
773 glyphsetCache[best].count = 1;
774 glyphsetCache[best].next = mru;
776 TRACE("new free cache slot at %d\n", mru);
780 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
790 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
791 if(size == GDI_ERROR)
794 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
795 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
797 GetTextMetricsW(hdc, &tm);
798 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
801 num_recs = get_be_word(*gasp);
805 *flags = get_be_word(*(gasp + 1));
806 if(ppem <= get_be_word(*gasp))
810 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
812 HeapFree(GetProcessHeap(), 0, buffer);
816 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
820 UINT font_smoothing_type, font_smoothing_orientation;
823 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
824 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
826 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
827 &font_smoothing_orientation, 0) &&
828 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
835 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
836 But, Wine's subpixel rendering can support the portrait mode.
839 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
847 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
852 static int hinter = -1;
853 static int subpixel = -1;
856 if((ret = LookupEntry(plfsz)) != -1) return ret;
859 entry = glyphsetCache + ret;
860 entry->lfsz = *plfsz;
861 for( format = 0; format < AA_MAXVALUE; format++ ) {
862 assert( !entry->format[format] );
865 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
867 if(hinter == -1 || subpixel == -1)
869 RASTERIZER_STATUS status;
870 GetRasterizerCaps(&status, sizeof(status));
871 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
872 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
875 switch (plfsz->lf.lfQuality)
877 case ANTIALIASED_QUALITY:
878 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
879 return ret; /* ignore further configuration */
880 case CLEARTYPE_QUALITY:
881 case CLEARTYPE_NATURAL_QUALITY:
882 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
884 case DEFAULT_QUALITY:
888 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
891 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
894 entry->aa_default = AA_None;
898 font_smoothing = TRUE; /* default to enabled */
899 #ifdef SONAME_LIBFONTCONFIG
900 if (fontconfig_installed)
902 FcPattern *match, *pattern;
904 char family[LF_FACESIZE * 4];
906 #if defined(__i386__) && defined(__GNUC__)
907 /* fontconfig generates floating point exceptions, mask them */
908 WORD cw, default_cw = 0x37f;
909 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
912 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
913 pattern = pFcPatternCreate();
914 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
915 if (plfsz->lf.lfWeight != FW_DONTCARE)
918 switch (plfsz->lf.lfWeight)
920 case FW_THIN: weight = FC_WEIGHT_THIN; break;
921 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
922 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
923 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
924 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
925 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
926 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
927 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
928 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
929 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
931 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
933 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
934 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
935 pFcDefaultSubstitute( pattern );
936 if ((match = pFcFontMatch( NULL, pattern, &result )))
941 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
943 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
946 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
948 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
949 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
953 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
954 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
955 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
956 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
957 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
960 if (!antialias) font_smoothing = FALSE;
961 pFcPatternDestroy( match );
963 pFcPatternDestroy( pattern );
965 #if defined(__i386__) && defined(__GNUC__)
966 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
969 #endif /* SONAME_LIBFONTCONFIG */
971 /* now check Xft resources */
974 BOOL antialias = TRUE;
976 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
978 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
979 value[0] == '0' || !strcasecmp( value, "off" ))
982 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
984 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
985 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
986 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
987 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
988 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
989 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
991 if (!antialias) font_smoothing = FALSE;
994 if (!font_smoothing) entry->aa_default = AA_None;
997 entry->aa_default = AA_None;
1002 static void dec_ref_cache(int index)
1005 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1006 assert(glyphsetCache[index].count > 0);
1007 glyphsetCache[index].count--;
1010 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1012 DWORD hash = 0, *ptr, two_chars;
1016 hash ^= plfsz->devsize.cx;
1017 hash ^= plfsz->devsize.cy;
1018 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1020 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1022 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1024 pwc = (WCHAR *)&two_chars;
1026 *pwc = toupperW(*pwc);
1028 *pwc = toupperW(*pwc);
1036 /**********************************************************************
1037 * xrenderdrv_SelectFont
1039 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1042 struct xrender_physdev *physdev = get_xrender_dev( dev );
1043 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1044 HFONT ret = next->funcs->pSelectFont( next, hfont );
1048 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1050 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1051 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1052 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1053 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1054 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1055 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1057 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1058 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1059 lfsz.xform.eM21, lfsz.xform.eM22);
1061 if (GetGraphicsMode( dev->hdc ) == GM_COMPATIBLE && lfsz.xform.eM11 * lfsz.xform.eM22 < 0)
1062 lfsz.lf.lfOrientation = -lfsz.lf.lfOrientation;
1064 /* Not used fields, would break hashing */
1065 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1067 lfsz_calc_hash(&lfsz);
1069 EnterCriticalSection(&xrender_cs);
1070 if (physdev->cache_index != -1)
1071 dec_ref_cache( physdev->cache_index );
1072 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1073 LeaveCriticalSection(&xrender_cs);
1077 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1079 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1080 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1082 if (!physdev) return FALSE;
1083 physdev->x11dev = x11dev;
1084 physdev->cache_index = -1;
1085 physdev->format = format;
1086 physdev->pict_format = pict_formats[format];
1087 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1091 /* store the color mask data in the bitmap info structure */
1092 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1094 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1096 info->bmiHeader.biPlanes = 1;
1097 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1098 info->bmiHeader.biCompression = BI_RGB;
1099 info->bmiHeader.biClrUsed = 0;
1101 switch (info->bmiHeader.biBitCount)
1104 colors[0] = format->direct.redMask << format->direct.red;
1105 colors[1] = format->direct.greenMask << format->direct.green;
1106 colors[2] = format->direct.blueMask << format->direct.blue;
1107 info->bmiHeader.biCompression = BI_BITFIELDS;
1110 colors[0] = format->direct.redMask << format->direct.red;
1111 colors[1] = format->direct.greenMask << format->direct.green;
1112 colors[2] = format->direct.blueMask << format->direct.blue;
1113 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1114 info->bmiHeader.biCompression = BI_BITFIELDS;
1120 /**********************************************************************
1121 * xrenderdrv_CreateDC
1123 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1124 LPCWSTR output, const DEVMODEW* initData )
1126 return create_xrender_dc( pdev, default_format );
1129 /**********************************************************************
1130 * xrenderdrv_CreateCompatibleDC
1132 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1134 if (orig) /* chain to x11drv first */
1136 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1137 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1139 /* otherwise we have been called by x11drv */
1141 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1144 /**********************************************************************
1145 * xrenderdrv_DeleteDC
1147 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1149 struct xrender_physdev *physdev = get_xrender_dev( dev );
1151 free_xrender_picture( physdev );
1153 EnterCriticalSection( &xrender_cs );
1154 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1155 LeaveCriticalSection( &xrender_cs );
1157 HeapFree( GetProcessHeap(), 0, physdev );
1161 /**********************************************************************
1162 * xrenderdrv_ExtEscape
1164 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1165 INT out_count, LPVOID out_data )
1167 struct xrender_physdev *physdev = get_xrender_dev( dev );
1169 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1171 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1173 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1175 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1176 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1180 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1183 /***********************************************************************
1184 * xrenderdrv_SetDeviceClipping
1186 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
1188 struct xrender_physdev *physdev = get_xrender_dev( dev );
1190 physdev->region = rgn;
1191 physdev->update_clip = TRUE;
1193 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1194 dev->funcs->pSetDeviceClipping( dev, rgn );
1198 /************************************************************************
1201 * Helper to ExtTextOut. Must be called inside xrender_cs
1203 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1205 unsigned int buflen;
1210 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1211 gsCacheEntryFormat *formatEntry;
1212 UINT ggo_format = GGO_GLYPH_INDEX;
1213 enum wxr_format wxr_format;
1214 static const char zero[4];
1215 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1219 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1222 ggo_format |= WINE_GGO_HRGB_BITMAP;
1225 ggo_format |= WINE_GGO_HBGR_BITMAP;
1228 ggo_format |= WINE_GGO_VRGB_BITMAP;
1231 ggo_format |= WINE_GGO_VBGR_BITMAP;
1235 ERR("aa = %d - not implemented\n", format);
1237 ggo_format |= GGO_BITMAP;
1241 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1242 if(buflen == GDI_ERROR) {
1243 if(format != AA_None) {
1245 entry->aa_default = AA_None;
1246 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1247 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1249 if(buflen == GDI_ERROR) {
1250 WARN("GetGlyphOutlineW failed using default glyph\n");
1251 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1252 if(buflen == GDI_ERROR) {
1253 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1254 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1255 if(buflen == GDI_ERROR) {
1256 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1261 TRACE("Turning off antialiasing for this monochrome font\n");
1264 /* If there is nothing for the current type, we create the entry. */
1265 if( !entry->format[format] ) {
1266 entry->format[format] = HeapAlloc(GetProcessHeap(),
1268 sizeof(gsCacheEntryFormat));
1270 formatEntry = entry->format[format];
1272 if(formatEntry->nrealized <= glyph) {
1273 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1275 if (formatEntry->realized)
1276 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1278 formatEntry->realized,
1279 formatEntry->nrealized * sizeof(BOOL));
1281 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1283 formatEntry->nrealized * sizeof(BOOL));
1285 if (formatEntry->gis)
1286 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1289 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1291 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1293 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1297 if(formatEntry->glyphset == 0) {
1300 wxr_format = WXR_FORMAT_GRAY;
1307 wxr_format = WXR_FORMAT_A8R8G8B8;
1311 ERR("aa = %d - not implemented\n", format);
1313 wxr_format = WXR_FORMAT_MONO;
1317 formatEntry->font_format = pict_formats[wxr_format];
1318 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1322 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1323 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1324 formatEntry->realized[glyph] = TRUE;
1326 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1328 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1329 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1331 gi.width = gm.gmBlackBoxX;
1332 gi.height = gm.gmBlackBoxY;
1333 gi.x = -gm.gmptGlyphOrigin.x;
1334 gi.y = gm.gmptGlyphOrigin.y;
1335 gi.xOff = gm.gmCellIncX;
1336 gi.yOff = gm.gmCellIncY;
1338 if(TRACE_ON(xrender)) {
1341 unsigned char *line;
1343 if(format == AA_None) {
1344 pitch = ((gi.width + 31) / 32) * 4;
1345 for(i = 0; i < gi.height; i++) {
1346 line = (unsigned char*) buf + i * pitch;
1348 for(j = 0; j < pitch * 8; j++) {
1349 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1351 TRACE("%s\n", output);
1354 static const char blks[] = " .:;!o*#";
1358 pitch = ((gi.width + 3) / 4) * 4;
1359 for(i = 0; i < gi.height; i++) {
1360 line = (unsigned char*) buf + i * pitch;
1362 for(j = 0; j < pitch; j++) {
1363 str[0] = blks[line[j] >> 5];
1364 strcat(output, str);
1366 TRACE("%s\n", output);
1372 if(formatEntry->glyphset) {
1373 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1374 unsigned char *byte = (unsigned char*) buf, c;
1380 /* magic to flip bit order */
1381 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1382 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1383 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1388 else if ( format != AA_Grey &&
1389 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1391 unsigned int i, *data = (unsigned int *)buf;
1392 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1397 XRenderCompositeText seems to ignore 0x0 glyphs when
1398 AA_None, which means we lose the advance width of glyphs
1399 like the space. We'll pretend that such glyphs are 1x1
1404 gi.width = gi.height = 1;
1406 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1407 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1408 HeapFree(GetProcessHeap(), 0, buf);
1411 formatEntry->gis[glyph] = gi;
1414 /*************************************************************
1417 * Returns an appropriate Picture for tiling the text colour.
1418 * Call and use result within the xrender_cs
1420 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1426 XRenderColor current_color;
1427 } tiles[WXR_NB_FORMATS], *tile;
1429 tile = &tiles[wxr_format];
1433 XRenderPictureAttributes pa;
1434 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1436 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1438 pa.repeat = RepeatNormal;
1439 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1441 /* init current_color to something different from text_pixel */
1442 tile->current_color = *color;
1443 tile->current_color.red ^= 0xffff;
1445 if (wxr_format == WXR_FORMAT_MONO)
1447 /* for a 1bpp bitmap we always need a 1 in the tile */
1449 col.red = col.green = col.blue = 0;
1451 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1455 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1457 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1458 tile->current_color = *color;
1463 /*************************************************************
1466 * Returns an appropriate Picture for masking with the specified alpha.
1467 * Call and use result within the xrender_cs
1469 static Picture get_mask_pict( int alpha )
1471 static Pixmap pixmap;
1472 static Picture pict;
1473 static int current_alpha;
1475 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1479 XRenderPictureAttributes pa;
1481 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1482 pa.repeat = RepeatNormal;
1483 pict = pXRenderCreatePicture( gdi_display, pixmap,
1484 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1488 if (alpha != current_alpha)
1491 col.red = col.green = col.blue = 0;
1492 col.alpha = current_alpha = alpha;
1493 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1498 /***********************************************************************
1499 * xrenderdrv_ExtTextOut
1501 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1502 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1504 struct xrender_physdev *physdev = get_xrender_dev( dev );
1505 gsCacheEntry *entry;
1506 gsCacheEntryFormat *formatEntry;
1507 AA_Type aa_type = AA_None;
1509 Picture pict, tile_pict = 0;
1511 POINT offset, desired, current;
1512 int render_op = PictOpOver;
1516 get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col );
1517 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1519 if(flags & ETO_OPAQUE)
1523 if (physdev->format == WXR_FORMAT_MONO)
1524 /* use the inverse of the text color */
1525 bg.red = bg.green = bg.blue = bg.alpha = ~col.alpha;
1527 get_xrender_color( physdev, GetBkColor( physdev->dev.hdc ), &bg );
1529 set_xrender_transformation( pict, 1, 1, 0, 0 );
1530 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &bg,
1531 physdev->x11dev->dc_rect.left + lprect->left,
1532 physdev->x11dev->dc_rect.top + lprect->top,
1533 lprect->right - lprect->left,
1534 lprect->bottom - lprect->top );
1535 add_device_bounds( physdev->x11dev, lprect );
1538 if(count == 0) return TRUE;
1540 EnterCriticalSection(&xrender_cs);
1542 entry = glyphsetCache + physdev->cache_index;
1543 aa_type = entry->aa_default;
1544 formatEntry = entry->format[aa_type];
1546 for(idx = 0; idx < count; idx++) {
1547 if( !formatEntry ) {
1548 UploadGlyph(physdev, wstr[idx], aa_type);
1549 /* re-evaluate antialias since aa_default may have changed */
1550 aa_type = entry->aa_default;
1551 formatEntry = entry->format[aa_type];
1552 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1553 UploadGlyph(physdev, wstr[idx], aa_type);
1558 WARN("could not upload requested glyphs\n");
1559 LeaveCriticalSection(&xrender_cs);
1563 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1564 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1566 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1568 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1569 So we pass zeros to the function and move to our starting position using the first
1570 element of the elts array. */
1572 desired.x = physdev->x11dev->dc_rect.left + x;
1573 desired.y = physdev->x11dev->dc_rect.top + y;
1574 offset.x = offset.y = 0;
1575 current.x = current.y = 0;
1577 tile_pict = get_tile_pict(physdev->format, &col);
1579 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1581 if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0)
1582 render_op = PictOpOutReverse; /* This gives us 'black' text */
1584 reset_bounds( &bounds );
1585 for(idx = 0; idx < count; idx++)
1587 elts[idx].glyphset = formatEntry->glyphset;
1588 elts[idx].chars = wstr + idx;
1589 elts[idx].nchars = 1;
1590 elts[idx].xOff = desired.x - current.x;
1591 elts[idx].yOff = desired.y - current.y;
1593 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1594 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1596 rect.left = desired.x - physdev->x11dev->dc_rect.left - formatEntry->gis[wstr[idx]].x;
1597 rect.top = desired.y - physdev->x11dev->dc_rect.top - formatEntry->gis[wstr[idx]].y;
1598 rect.right = rect.left + formatEntry->gis[wstr[idx]].width;
1599 rect.bottom = rect.top + formatEntry->gis[wstr[idx]].height;
1600 add_bounds_rect( &bounds, &rect );
1604 desired.x += formatEntry->gis[wstr[idx]].xOff;
1605 desired.y += formatEntry->gis[wstr[idx]].yOff;
1611 offset.x += lpDx[idx * 2];
1612 offset.y += lpDx[idx * 2 + 1];
1615 offset.x += lpDx[idx];
1616 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1617 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1621 /* Make sure we don't have any transforms set from a previous call */
1622 set_xrender_transformation(pict, 1, 1, 0, 0);
1623 pXRenderCompositeText16(gdi_display, render_op,
1626 formatEntry->font_format,
1627 0, 0, 0, 0, elts, count);
1628 HeapFree(GetProcessHeap(), 0, elts);
1630 LeaveCriticalSection(&xrender_cs);
1631 add_device_bounds( physdev->x11dev, &bounds );
1635 /* multiply the alpha channel of a picture */
1636 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1637 int x, int y, int width, int height )
1639 XRenderPictureAttributes pa;
1640 Pixmap src_pixmap, mask_pixmap;
1641 Picture src_pict, mask_pict;
1644 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1645 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1646 pa.repeat = RepeatNormal;
1647 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1648 pa.component_alpha = True;
1649 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1650 color.red = color.green = color.blue = color.alpha = 0xffff;
1651 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1652 color.alpha = alpha;
1653 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1654 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1655 0, 0, 0, 0, x, y, width, height );
1656 pXRenderFreePicture( gdi_display, src_pict );
1657 pXRenderFreePicture( gdi_display, mask_pict );
1658 XFreePixmap( gdi_display, src_pixmap );
1659 XFreePixmap( gdi_display, mask_pixmap );
1662 /* Helper function for (stretched) blitting using xrender */
1663 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1664 int x_src, int y_src, int width_src, int height_src,
1665 int x_dst, int y_dst, int width_dst, int height_dst,
1666 double xscale, double yscale )
1668 int x_offset, y_offset;
1672 x_src += width_src + 1;
1673 width_src = -width_src;
1677 y_src += height_src + 1;
1678 height_src = -height_src;
1682 x_dst += width_dst + 1;
1683 width_dst = -width_dst;
1687 y_dst += height_dst + 1;
1688 height_dst = -height_dst;
1691 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1692 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1693 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1694 if(xscale != 1.0 || yscale != 1.0)
1696 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1697 * in the wrong quadrant of the x-y plane.
1699 x_offset = (xscale < 0) ? -width_dst : 0;
1700 y_offset = (yscale < 0) ? -height_dst : 0;
1701 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1707 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1709 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1710 x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst );
1713 /* Helper function for (stretched) mono->color blitting using xrender */
1714 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1715 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1716 int x_src, int y_src, int width_src, int height_src,
1717 int x_dst, int y_dst, int width_dst, int height_dst,
1718 double xscale, double yscale )
1721 int x_offset, y_offset;
1726 x_src += width_src + 1;
1727 width_src = -width_src;
1731 y_src += height_src + 1;
1732 height_src = -height_src;
1736 x_dst += width_dst + 1;
1737 width_dst = -width_dst;
1741 y_dst += height_dst + 1;
1742 height_dst = -height_dst;
1745 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1746 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1749 EnterCriticalSection( &xrender_cs );
1751 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1752 tile_pict = get_tile_pict( dst_format, &color );
1754 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width_dst, height_dst );
1756 if (xscale != 1.0 || yscale != 1.0)
1758 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1759 * in the wrong quadrant of the x-y plane.
1761 x_offset = (xscale < 0) ? -width_dst : 0;
1762 y_offset = (yscale < 0) ? -height_dst : 0;
1763 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1769 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1771 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1772 0, 0, x_offset, y_offset, x_dst, y_dst, width_dst, height_dst );
1773 LeaveCriticalSection( &xrender_cs );
1775 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1776 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1777 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha,
1778 x_dst, y_dst, width_dst, height_dst );
1781 /* create a pixmap and render picture for an image */
1782 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1783 struct bitblt_coords *src, enum wxr_format format,
1784 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1787 int width = src->visrect.right - src->visrect.left;
1788 int height = src->visrect.bottom - src->visrect.top;
1789 int depth = pict_formats[format]->depth;
1790 struct gdi_image_bits dst_bits;
1791 XRenderPictureAttributes pa;
1795 image = XCreateImage( gdi_display, default_visual.visual, depth, ZPixmap, 0, NULL,
1796 info->bmiHeader.biWidth, height, 32, 0 );
1797 if (!image) return ERROR_OUTOFMEMORY;
1799 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1800 if (ret) return ret;
1802 image->data = dst_bits.ptr;
1804 *use_repeat = (width == 1 && height == 1);
1805 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1807 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1808 gc = XCreateGC( gdi_display, *pixmap, 0, NULL );
1809 XPutImage( gdi_display, *pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1810 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1811 XFreeGC( gdi_display, gc );
1813 /* make coordinates relative to the pixmap */
1814 src->x -= src->visrect.left;
1815 src->y -= src->visrect.top;
1816 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
1819 XDestroyImage( image );
1820 if (dst_bits.free) dst_bits.free( &dst_bits );
1824 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
1825 Drawable drawable, const struct bitblt_coords *src,
1826 const struct bitblt_coords *dst )
1829 Picture src_pict = 0, dst_pict, mask_pict = 0;
1830 double xscale = src->width / (double)dst->width;
1831 double yscale = src->height / (double)dst->height;
1833 if (drawable) /* using an intermediate pixmap */
1837 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, 0, NULL );
1841 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
1842 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
1843 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
1846 src_pict = get_xrender_picture_source( physdev_src, FALSE );
1849 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
1851 XRenderColor fg, bg;
1853 get_xrender_color( physdev_dst, GetTextColor( physdev_dst->dev.hdc ), &fg );
1854 get_xrender_color( physdev_dst, GetBkColor( physdev_dst->dev.hdc ), &bg );
1855 fg.alpha = bg.alpha = 0;
1857 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
1858 physdev_src->x11dev->dc_rect.left + src->x,
1859 physdev_src->x11dev->dc_rect.top + src->y,
1860 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1862 else /* color -> color (can be at different depths) or mono -> mono */
1864 if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32)
1865 mask_pict = get_no_alpha_mask();
1867 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
1868 physdev_src->x11dev->dc_rect.left + src->x,
1869 physdev_src->x11dev->dc_rect.top + src->y,
1870 src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1873 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1877 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
1878 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
1879 Drawable drawable, struct bitblt_coords *src,
1880 struct bitblt_coords *dst, BOOL use_repeat )
1884 double xscale, yscale;
1886 if (drawable) /* using an intermediate pixmap */
1888 RGNDATA *clip_data = NULL;
1890 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1893 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL );
1895 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
1896 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
1897 HeapFree( GetProcessHeap(), 0, clip_data );
1901 x_dst = physdev->x11dev->dc_rect.left + dst->x;
1902 y_dst = physdev->x11dev->dc_rect.top + dst->y;
1903 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
1908 xscale = src->width / (double)dst->width;
1909 yscale = src->height / (double)dst->height;
1911 else xscale = yscale = 1; /* no scaling needed with a repeating source */
1913 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height,
1914 x_dst, y_dst, dst->width, dst->height, xscale, yscale );
1916 if (drawable) pXRenderFreePicture( gdi_display, dst_pict );
1920 /***********************************************************************
1921 * xrenderdrv_StretchBlt
1923 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1924 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1926 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
1927 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
1928 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
1930 if (src_dev->funcs != dst_dev->funcs)
1932 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
1933 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
1936 /* XRender is of no use for color -> mono */
1937 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
1938 goto x11drv_fallback;
1940 /* if not stretching, we only need to handle format conversion */
1941 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
1947 struct bitblt_coords tmp;
1949 /* make coordinates relative to tmp pixmap */
1951 tmp.x -= tmp.visrect.left;
1952 tmp.y -= tmp.visrect.top;
1953 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
1955 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
1956 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1957 XSetGraphicsExposures( gdi_display, tmpGC, False );
1958 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
1959 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth );
1961 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
1962 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
1964 XFreePixmap( gdi_display, tmp_pixmap );
1965 XFreeGC( gdi_display, tmpGC );
1967 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
1969 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
1973 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
1977 /***********************************************************************
1978 * xrenderdrv_PutImage
1980 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1981 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1982 struct bitblt_coords *dst, DWORD rop )
1984 struct xrender_physdev *physdev = get_xrender_dev( dev );
1988 enum wxr_format src_format, dst_format;
1989 XRenderPictFormat *pict_format;
1991 Picture src_pict, mask_pict = 0;
1994 dst_format = physdev->format;
1995 src_format = get_xrender_format_from_bitmapinfo( info );
1996 if (!(pict_format = pict_formats[src_format])) goto update_format;
1998 /* make sure we can create an image with the same bpp */
1999 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2002 /* mono <-> color conversions not supported */
2003 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2004 goto x11drv_fallback;
2006 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2008 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2010 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2013 struct bitblt_coords tmp;
2017 BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip );
2019 /* make coordinates relative to tmp pixmap */
2021 tmp.x -= tmp.visrect.left;
2022 tmp.y -= tmp.visrect.top;
2023 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2025 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2026 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2027 XSetGraphicsExposures( gdi_display, gc, False );
2028 tmp_pixmap = XCreatePixmap( gdi_display, root_window,
2029 tmp.visrect.right - tmp.visrect.left,
2030 tmp.visrect.bottom - tmp.visrect.top,
2031 physdev->pict_format->depth );
2033 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2034 NULL, tmp_pixmap, src, &tmp, use_repeat );
2035 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2037 XFreePixmap( gdi_display, tmp_pixmap );
2038 XFreeGC( gdi_display, gc );
2039 if (restore_region) restore_clipping_region( physdev->x11dev );
2041 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2042 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2044 add_device_bounds( physdev->x11dev, &dst->visrect );
2046 pXRenderFreePicture( gdi_display, src_pict );
2047 XFreePixmap( gdi_display, src_pixmap );
2052 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2053 set_color_info( pict_formats[dst_format], info );
2054 return ERROR_BAD_FORMAT;
2057 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2058 return dev->funcs->pPutImage( dev, clip, info, bits, src, dst, rop );
2062 /***********************************************************************
2063 * xrenderdrv_BlendImage
2065 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2066 struct bitblt_coords *src, struct bitblt_coords *dst,
2067 BLENDFUNCTION func )
2069 struct xrender_physdev *physdev = get_xrender_dev( dev );
2071 enum wxr_format format;
2072 XRenderPictFormat *pict_format;
2073 Picture dst_pict, src_pict, mask_pict;
2077 format = get_xrender_format_from_bitmapinfo( info );
2078 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2079 format = get_format_without_alpha( format );
2080 else if (format != WXR_FORMAT_A8R8G8B8)
2081 return ERROR_INVALID_PARAMETER;
2083 if (!(pict_format = pict_formats[format])) goto update_format;
2085 /* make sure we can create an image with the same bpp */
2086 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2089 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2092 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2094 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2097 double xscale, yscale;
2101 xscale = src->width / (double)dst->width;
2102 yscale = src->height / (double)dst->height;
2104 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2106 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2108 EnterCriticalSection( &xrender_cs );
2109 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2111 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2112 src->x, src->y, src->width, src->height,
2113 physdev->x11dev->dc_rect.left + dst->x,
2114 physdev->x11dev->dc_rect.top + dst->y,
2115 dst->width, dst->height, xscale, yscale );
2117 pXRenderFreePicture( gdi_display, src_pict );
2118 XFreePixmap( gdi_display, src_pixmap );
2120 LeaveCriticalSection( &xrender_cs );
2121 add_device_bounds( physdev->x11dev, &dst->visrect );
2126 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2127 set_color_info( physdev->pict_format, info );
2128 return ERROR_BAD_FORMAT;
2132 /***********************************************************************
2133 * xrenderdrv_AlphaBlend
2135 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2136 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2138 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2139 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2140 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2141 XRenderPictureAttributes pa;
2142 Pixmap tmp_pixmap = 0;
2143 double xscale, yscale;
2145 if (src_dev->funcs != dst_dev->funcs)
2147 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2148 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2151 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2153 SetLastError( ERROR_INVALID_PARAMETER );
2157 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2159 xscale = src->width / (double)dst->width;
2160 yscale = src->height / (double)dst->height;
2162 src_pict = get_xrender_picture_source( physdev_src, FALSE );
2164 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2166 /* mono -> color blending needs an intermediate color pixmap */
2167 XRenderColor fg, bg;
2168 int width = src->visrect.right - src->visrect.left;
2169 int height = src->visrect.bottom - src->visrect.top;
2171 /* blending doesn't use the destination DC colors */
2172 fg.red = fg.green = fg.blue = 0;
2173 bg.red = bg.green = bg.blue = 0xffff;
2174 fg.alpha = bg.alpha = 0xffff;
2176 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2177 physdev_dst->pict_format->depth );
2178 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format, 0, NULL );
2180 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2181 src->visrect.left, src->visrect.top, width, height, 0, 0, width, height, 1, 1 );
2183 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2185 /* we need a source picture with no alpha */
2186 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2187 if (format != physdev_src->format)
2189 pa.subwindow_mode = IncludeInferiors;
2190 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2191 pict_formats[format], CPSubwindowMode, &pa );
2195 if (tmp_pict) src_pict = tmp_pict;
2197 EnterCriticalSection( &xrender_cs );
2198 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2200 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2201 physdev_src->x11dev->dc_rect.left + src->x,
2202 physdev_src->x11dev->dc_rect.top + src->y,
2203 src->width, src->height,
2204 physdev_dst->x11dev->dc_rect.left + dst->x,
2205 physdev_dst->x11dev->dc_rect.top + dst->y,
2206 dst->width, dst->height, xscale, yscale );
2208 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2209 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2211 LeaveCriticalSection( &xrender_cs );
2212 add_device_bounds( physdev_dst->x11dev, &dst->visrect );
2216 /***********************************************************************
2217 * xrenderdrv_GradientFill
2219 static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
2220 void * grad_array, ULONG ngrad, ULONG mode )
2222 #ifdef HAVE_XRENDERCREATELINEARGRADIENT
2223 static const XFixed stops[2] = { 0, 1 << 16 };
2224 struct xrender_physdev *physdev = get_xrender_dev( dev );
2225 XLinearGradient gradient;
2226 XRenderColor colors[2];
2227 Picture src_pict, dst_pict;
2229 const GRADIENT_RECT *rect = grad_array;
2233 if (!pXRenderCreateLinearGradient) goto fallback;
2235 /* <= 16-bpp uses dithering */
2236 if (!physdev->pict_format || physdev->pict_format->depth <= 16) goto fallback;
2240 case GRADIENT_FILL_RECT_H:
2241 case GRADIENT_FILL_RECT_V:
2242 for (i = 0; i < ngrad; i++, rect++)
2244 const TRIVERTEX *v1 = vert_array + rect->UpperLeft;
2245 const TRIVERTEX *v2 = vert_array + rect->LowerRight;
2247 colors[0].red = v1->Red * 257 / 256;
2248 colors[0].green = v1->Green * 257 / 256;
2249 colors[0].blue = v1->Blue * 257 / 256;
2250 colors[1].red = v2->Red * 257 / 256;
2251 colors[1].green = v2->Green * 257 / 256;
2252 colors[1].blue = v2->Blue * 257 / 256;
2253 /* always ignore alpha since otherwise xrender will want to pre-multiply the colors */
2254 colors[0].alpha = colors[1].alpha = 65535;
2260 LPtoDP( dev->hdc, pt, 2 );
2261 if (mode == GRADIENT_FILL_RECT_H)
2263 gradient.p1.y = gradient.p2.y = 0;
2264 if (pt[1].x > pt[0].x)
2267 gradient.p2.x = (pt[1].x - pt[0].x) << 16;
2271 gradient.p1.x = (pt[0].x - pt[1].x) << 16;
2277 gradient.p1.x = gradient.p2.x = 0;
2278 if (pt[1].y > pt[0].y)
2281 gradient.p2.y = (pt[1].y - pt[0].y) << 16;
2285 gradient.p1.y = (pt[0].y - pt[1].y) << 16;
2290 rc.left = min( pt[0].x, pt[1].x );
2291 rc.top = min( pt[0].y, pt[1].y );
2292 rc.right = max( pt[0].x, pt[1].x );
2293 rc.bottom = max( pt[0].y, pt[1].y );
2295 TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n",
2296 mode, wine_dbgstr_rect( &rc ),
2297 colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha,
2298 colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha );
2300 dst_pict = get_xrender_picture( physdev, 0, NULL );
2302 src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 );
2303 xrender_blit( PictOpSrc, src_pict, 0, dst_pict,
2304 0, 0, rc.right - rc.left, rc.bottom - rc.top,
2305 physdev->x11dev->dc_rect.left + rc.left,
2306 physdev->x11dev->dc_rect.top + rc.top,
2307 rc.right - rc.left, rc.bottom - rc.top, 1, 1 );
2308 pXRenderFreePicture( gdi_display, src_pict );
2309 add_device_bounds( physdev->x11dev, &rc );
2316 dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
2317 return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
2320 /***********************************************************************
2321 * xrenderdrv_SelectBrush
2323 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_pattern *pattern )
2325 struct xrender_physdev *physdev = get_xrender_dev( dev );
2327 XVisualInfo vis = default_visual;
2328 XRenderPictFormat *format = physdev->pict_format;
2330 if (!pattern) goto x11drv_fallback;
2331 if (pattern->info->bmiHeader.biBitCount == 1) goto x11drv_fallback;
2332 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2334 vis.depth = format->depth;
2335 vis.red_mask = format->direct.redMask << format->direct.red;
2336 vis.green_mask = format->direct.greenMask << format->direct.green;
2337 vis.blue_mask = format->direct.blueMask << format->direct.blue;
2339 pixmap = create_pixmap_from_image( physdev->dev.hdc, &vis, pattern->info,
2340 &pattern->bits, pattern->usage );
2341 if (!pixmap) return 0;
2343 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2344 physdev->x11dev->brush.pixmap = pixmap;
2345 physdev->x11dev->brush.fillStyle = FillTiled;
2346 physdev->x11dev->brush.pixel = 0; /* ignored */
2347 physdev->x11dev->brush.style = BS_PATTERN;
2351 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2352 return dev->funcs->pSelectBrush( dev, hbrush, pattern );
2356 static const struct gdi_dc_funcs xrender_funcs =
2358 NULL, /* pAbortDoc */
2359 NULL, /* pAbortPath */
2360 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2361 NULL, /* pAngleArc */
2364 NULL, /* pBeginPath */
2365 xrenderdrv_BlendImage, /* pBlendImage */
2367 NULL, /* pCloseFigure */
2368 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2369 xrenderdrv_CreateDC, /* pCreateDC */
2370 xrenderdrv_DeleteDC, /* pDeleteDC */
2371 NULL, /* pDeleteObject */
2372 NULL, /* pDeviceCapabilities */
2373 NULL, /* pEllipse */
2375 NULL, /* pEndPage */
2376 NULL, /* pEndPath */
2377 NULL, /* pEnumFonts */
2378 NULL, /* pEnumICMProfiles */
2379 NULL, /* pExcludeClipRect */
2380 NULL, /* pExtDeviceMode */
2381 xrenderdrv_ExtEscape, /* pExtEscape */
2382 NULL, /* pExtFloodFill */
2383 NULL, /* pExtSelectClipRgn */
2384 xrenderdrv_ExtTextOut, /* pExtTextOut */
2385 NULL, /* pFillPath */
2386 NULL, /* pFillRgn */
2387 NULL, /* pFlattenPath */
2388 NULL, /* pFontIsLinked */
2389 NULL, /* pFrameRgn */
2390 NULL, /* pGdiComment */
2391 NULL, /* pGdiRealizationInfo */
2392 NULL, /* pGetBoundsRect */
2393 NULL, /* pGetCharABCWidths */
2394 NULL, /* pGetCharABCWidthsI */
2395 NULL, /* pGetCharWidth */
2396 NULL, /* pGetDeviceCaps */
2397 NULL, /* pGetDeviceGammaRamp */
2398 NULL, /* pGetFontData */
2399 NULL, /* pGetFontUnicodeRanges */
2400 NULL, /* pGetGlyphIndices */
2401 NULL, /* pGetGlyphOutline */
2402 NULL, /* pGetICMProfile */
2403 NULL, /* pGetImage */
2404 NULL, /* pGetKerningPairs */
2405 NULL, /* pGetNearestColor */
2406 NULL, /* pGetOutlineTextMetrics */
2407 NULL, /* pGetPixel */
2408 NULL, /* pGetSystemPaletteEntries */
2409 NULL, /* pGetTextCharsetInfo */
2410 NULL, /* pGetTextExtentExPoint */
2411 NULL, /* pGetTextExtentExPointI */
2412 NULL, /* pGetTextFace */
2413 NULL, /* pGetTextMetrics */
2414 xrenderdrv_GradientFill, /* pGradientFill */
2415 NULL, /* pIntersectClipRect */
2416 NULL, /* pInvertRgn */
2418 NULL, /* pModifyWorldTransform */
2420 NULL, /* pOffsetClipRgn */
2421 NULL, /* pOffsetViewportOrg */
2422 NULL, /* pOffsetWindowOrg */
2423 NULL, /* pPaintRgn */
2426 NULL, /* pPolyBezier */
2427 NULL, /* pPolyBezierTo */
2428 NULL, /* pPolyDraw */
2429 NULL, /* pPolyPolygon */
2430 NULL, /* pPolyPolyline */
2431 NULL, /* pPolygon */
2432 NULL, /* pPolyline */
2433 NULL, /* pPolylineTo */
2434 xrenderdrv_PutImage, /* pPutImage */
2435 NULL, /* pRealizeDefaultPalette */
2436 NULL, /* pRealizePalette */
2437 NULL, /* pRectangle */
2438 NULL, /* pResetDC */
2439 NULL, /* pRestoreDC */
2440 NULL, /* pRoundRect */
2442 NULL, /* pScaleViewportExt */
2443 NULL, /* pScaleWindowExt */
2444 NULL, /* pSelectBitmap */
2445 xrenderdrv_SelectBrush, /* pSelectBrush */
2446 NULL, /* pSelectClipPath */
2447 xrenderdrv_SelectFont, /* pSelectFont */
2448 NULL, /* pSelectPalette */
2449 NULL, /* pSelectPen */
2450 NULL, /* pSetArcDirection */
2451 NULL, /* pSetBkColor */
2452 NULL, /* pSetBkMode */
2453 NULL, /* pSetBoundsRect */
2454 NULL, /* pSetDCBrushColor */
2455 NULL, /* pSetDCPenColor */
2456 NULL, /* pSetDIBitsToDevice */
2457 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2458 NULL, /* pSetDeviceGammaRamp */
2459 NULL, /* pSetLayout */
2460 NULL, /* pSetMapMode */
2461 NULL, /* pSetMapperFlags */
2462 NULL, /* pSetPixel */
2463 NULL, /* pSetPolyFillMode */
2464 NULL, /* pSetROP2 */
2465 NULL, /* pSetRelAbs */
2466 NULL, /* pSetStretchBltMode */
2467 NULL, /* pSetTextAlign */
2468 NULL, /* pSetTextCharacterExtra */
2469 NULL, /* pSetTextColor */
2470 NULL, /* pSetTextJustification */
2471 NULL, /* pSetViewportExt */
2472 NULL, /* pSetViewportOrg */
2473 NULL, /* pSetWindowExt */
2474 NULL, /* pSetWindowOrg */
2475 NULL, /* pSetWorldTransform */
2476 NULL, /* pStartDoc */
2477 NULL, /* pStartPage */
2478 xrenderdrv_StretchBlt, /* pStretchBlt */
2479 NULL, /* pStretchDIBits */
2480 NULL, /* pStrokeAndFillPath */
2481 NULL, /* pStrokePath */
2482 NULL, /* pUnrealizePalette */
2483 NULL, /* pWidenPath */
2484 NULL, /* wine_get_wgl_driver */
2485 GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
2488 #else /* SONAME_LIBXRENDER */
2490 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2492 TRACE("XRender support not compiled in.\n");
2496 #endif /* SONAME_LIBXRENDER */