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 int using_client_side_fonts = FALSE;
43 WINE_DEFAULT_DEBUG_CHANNEL(xrender);
45 #ifdef SONAME_LIBXRENDER
47 static BOOL X11DRV_XRender_Installed = FALSE;
50 #include <X11/extensions/Xrender.h>
52 #ifndef RepeatNone /* added in 0.10 */
54 #define RepeatNormal 1
56 #define RepeatReflect 3
74 WXR_INVALID_FORMAT = WXR_NB_FORMATS
77 typedef struct wine_xrender_format_template
81 unsigned int alphaMask;
85 unsigned int greenMask;
87 unsigned int blueMask;
88 } WineXRenderFormatTemplate;
90 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
92 /* Format depth alpha mask red mask green mask blue mask*/
93 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
94 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
95 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
96 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
97 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
98 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
99 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
100 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
101 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
103 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
107 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
109 /* format phys red phys green phys blue log red log green log blue */
110 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
111 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
112 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
113 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
114 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
115 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
116 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
117 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
118 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
120 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
124 static enum wxr_format default_format = WXR_INVALID_FORMAT;
125 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
131 SIZE devsize; /* size in device coords */
135 #define INITIAL_REALIZED_BUF_SIZE 128
137 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
142 XRenderPictFormat *font_format;
147 } gsCacheEntryFormat;
153 gsCacheEntryFormat * format[AA_MAXVALUE];
158 struct xrender_physdev
160 struct gdi_physdev dev;
161 X11DRV_PDEVICE *x11dev;
162 enum wxr_format format;
167 XRenderPictFormat *pict_format;
170 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
172 return (struct xrender_physdev *)dev;
175 static const struct gdi_dc_funcs xrender_funcs;
177 static gsCacheEntry *glyphsetCache = NULL;
178 static DWORD glyphsetCacheSize = 0;
179 static INT lastfree = -1;
182 #define INIT_CACHE_SIZE 10
184 static int antialias = 1;
186 static void *xrender_handle;
188 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
189 MAKE_FUNCPTR(XRenderAddGlyphs)
190 MAKE_FUNCPTR(XRenderComposite)
191 MAKE_FUNCPTR(XRenderCompositeText16)
192 MAKE_FUNCPTR(XRenderCreateGlyphSet)
193 MAKE_FUNCPTR(XRenderCreatePicture)
194 MAKE_FUNCPTR(XRenderFillRectangle)
195 MAKE_FUNCPTR(XRenderFindFormat)
196 MAKE_FUNCPTR(XRenderFindVisualFormat)
197 MAKE_FUNCPTR(XRenderFreeGlyphSet)
198 MAKE_FUNCPTR(XRenderFreePicture)
199 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
200 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
201 MAKE_FUNCPTR(XRenderSetPictureTransform)
203 MAKE_FUNCPTR(XRenderQueryExtension)
205 #ifdef SONAME_LIBFONTCONFIG
206 #include <fontconfig/fontconfig.h>
207 MAKE_FUNCPTR(FcConfigSubstitute)
208 MAKE_FUNCPTR(FcDefaultSubstitute)
209 MAKE_FUNCPTR(FcFontMatch)
211 MAKE_FUNCPTR(FcPatternCreate)
212 MAKE_FUNCPTR(FcPatternDestroy)
213 MAKE_FUNCPTR(FcPatternAddInteger)
214 MAKE_FUNCPTR(FcPatternAddString)
215 MAKE_FUNCPTR(FcPatternGetBool)
216 MAKE_FUNCPTR(FcPatternGetInteger)
217 MAKE_FUNCPTR(FcPatternGetString)
218 static void *fontconfig_handle;
219 static BOOL fontconfig_installed;
224 static CRITICAL_SECTION xrender_cs;
225 static CRITICAL_SECTION_DEBUG critsect_debug =
228 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
229 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
231 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
233 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
234 ( ( (ULONG)_x4 << 24 ) | \
235 ( (ULONG)_x3 << 16 ) | \
236 ( (ULONG)_x2 << 8 ) | \
239 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
241 #define GASP_GRIDFIT 0x01
242 #define GASP_DOGRAY 0x02
244 #ifdef WORDS_BIGENDIAN
245 #define get_be_word(x) (x)
246 #define NATIVE_BYTE_ORDER MSBFirst
248 #define get_be_word(x) RtlUshortByteSwap(x)
249 #define NATIVE_BYTE_ORDER LSBFirst
252 static BOOL has_alpha( enum wxr_format format )
254 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
257 static enum wxr_format get_format_without_alpha( enum wxr_format format )
261 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
262 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
263 default: return format;
267 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
270 templ->type = PictTypeDirect;
271 templ->depth = fmt->depth;
272 templ->direct.alpha = fmt->alpha;
273 templ->direct.alphaMask = fmt->alphaMask;
274 templ->direct.red = fmt->red;
275 templ->direct.redMask = fmt->redMask;
276 templ->direct.green = fmt->green;
277 templ->direct.greenMask = fmt->greenMask;
278 templ->direct.blue = fmt->blue;
279 templ->direct.blueMask = fmt->blueMask;
282 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
287 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
289 if(fmt->depth != screen_depth)
291 if( (fmt->redMask << fmt->red) != visual->red_mask)
293 if( (fmt->greenMask << fmt->green) != visual->green_mask)
295 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
298 /* We never select a default ARGB visual */
305 static int load_xrender_formats(void)
310 for (i = 0; i < WXR_NB_FORMATS; i++)
312 XRenderPictFormat templ;
314 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
317 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
318 if (!pict_formats[i])
320 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
321 if (visual->class == DirectColor)
324 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
325 screen_depth, TrueColor, &info ))
327 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
328 if (pict_formats[i]) visual = info.visual;
333 if (pict_formats[i]) default_format = i;
337 unsigned long mask = 0;
338 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
341 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
347 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
353 /***********************************************************************
354 * X11DRV_XRender_Init
356 * Let's see if our XServer has the extension available
359 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
363 if (client_side_with_render &&
364 (xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0)))
367 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
368 LOAD_FUNCPTR(XRenderAddGlyphs)
369 LOAD_FUNCPTR(XRenderComposite)
370 LOAD_FUNCPTR(XRenderCompositeText16)
371 LOAD_FUNCPTR(XRenderCreateGlyphSet)
372 LOAD_FUNCPTR(XRenderCreatePicture)
373 LOAD_FUNCPTR(XRenderFillRectangle)
374 LOAD_FUNCPTR(XRenderFindFormat)
375 LOAD_FUNCPTR(XRenderFindVisualFormat)
376 LOAD_FUNCPTR(XRenderFreeGlyphSet)
377 LOAD_FUNCPTR(XRenderFreePicture)
378 LOAD_FUNCPTR(XRenderSetPictureClipRectangles)
379 LOAD_FUNCPTR(XRenderQueryExtension)
381 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
382 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0);
383 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform)
384 #undef LOAD_OPTIONAL_FUNCPTR
388 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
390 if(X11DRV_XRender_Installed) {
391 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
392 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
396 "Wine has detected that you probably have a buggy version\n"
397 "of libXrender.so . Because of this client side font rendering\n"
398 "will be disabled. Please upgrade this library.\n");
399 X11DRV_XRender_Installed = FALSE;
403 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask) {
404 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
405 X11DRV_XRender_Installed = FALSE;
410 #ifdef SONAME_LIBFONTCONFIG
411 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
413 #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;}
414 LOAD_FUNCPTR(FcConfigSubstitute);
415 LOAD_FUNCPTR(FcDefaultSubstitute);
416 LOAD_FUNCPTR(FcFontMatch);
417 LOAD_FUNCPTR(FcInit);
418 LOAD_FUNCPTR(FcPatternCreate);
419 LOAD_FUNCPTR(FcPatternDestroy);
420 LOAD_FUNCPTR(FcPatternAddInteger);
421 LOAD_FUNCPTR(FcPatternAddString);
422 LOAD_FUNCPTR(FcPatternGetBool);
423 LOAD_FUNCPTR(FcPatternGetInteger);
424 LOAD_FUNCPTR(FcPatternGetString);
426 fontconfig_installed = pFcInit();
428 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
432 if(X11DRV_XRender_Installed || client_side_with_core)
434 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
435 sizeof(*glyphsetCache) * INIT_CACHE_SIZE);
437 glyphsetCacheSize = INIT_CACHE_SIZE;
439 for(i = 0; i < INIT_CACHE_SIZE; i++) {
440 glyphsetCache[i].next = i + 1;
441 glyphsetCache[i].count = -1;
443 glyphsetCache[i-1].next = -1;
444 using_client_side_fonts = 1;
446 if(!X11DRV_XRender_Installed) {
447 TRACE("Xrender is not available on your XServer, client side rendering with the core protocol instead.\n");
448 if(screen_depth <= 8 || !client_side_antialias_with_core)
451 if(screen_depth <= 8 || !client_side_antialias_with_render)
454 return &xrender_funcs;
456 TRACE("Using X11 core fonts\n");
460 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
461 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
463 if(pf->direct.redMask)
464 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
468 if(pf->direct.greenMask)
469 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
471 dst_color->green = 0;
473 if(pf->direct.blueMask)
474 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
478 dst_color->alpha = 0xffff;
481 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
483 int redMask, greenMask, blueMask;
486 if (depth == 1) return WXR_FORMAT_MONO;
488 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
489 if (!shifts) return default_format;
491 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
492 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
493 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
495 /* Try to locate a format which matches the specification of the dibsection. */
496 for(i = 0; i < WXR_NB_FORMATS; i++)
498 if( depth == wxr_formats_template[i].depth &&
499 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
500 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
501 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
505 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
506 ERR("No XRender format found for %u %08x/%08x/%08x\n", depth, redMask, greenMask, blueMask);
507 return WXR_INVALID_FORMAT;
510 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
512 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
514 switch (info->bmiHeader.biBitCount)
517 return WXR_FORMAT_MONO;
522 if (info->bmiHeader.biCompression != BI_RGB) break;
523 return WXR_FORMAT_R8G8B8;
526 if (info->bmiHeader.biCompression == BI_BITFIELDS)
528 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
531 for (i = 0; i < WXR_NB_FORMATS; i++)
533 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
534 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
535 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
536 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
541 if (info->bmiHeader.biCompression != BI_RGB) break;
542 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
544 return WXR_INVALID_FORMAT;
547 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
548 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
550 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
551 XTransform xform = {{
552 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
553 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
554 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
557 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
561 /* check if we can use repeating instead of scaling for the specified source DC */
562 static BOOL use_source_repeat( struct xrender_physdev *dev )
564 return (dev->x11dev->bitmap &&
565 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
566 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
569 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
571 if (!dev->pict && dev->pict_format)
573 XRenderPictureAttributes pa;
576 pa.subwindow_mode = IncludeInferiors;
577 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
578 dev->pict_format, CPSubwindowMode, &pa );
580 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
581 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
582 dev->update_clip = TRUE;
585 if (dev->update_clip)
592 rgn = CreateRectRgnIndirect( clip_rect );
593 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
594 CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
598 rgn = CreateRectRgn( 0, 0, 0, 0 );
599 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
602 if ((clip_data = X11DRV_GetRegionData( rgn ? rgn : dev->x11dev->region, 0 )))
605 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
606 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
607 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
609 HeapFree( GetProcessHeap(), 0, clip_data );
611 dev->update_clip = (rgn != 0); /* have to update again if we are using a custom region */
612 if (rgn) DeleteObject( rgn );
617 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
619 if (!dev->pict_src && dev->pict_format)
621 XRenderPictureAttributes pa;
624 pa.subwindow_mode = IncludeInferiors;
625 pa.repeat = repeat ? RepeatNormal : RepeatNone;
626 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
627 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
630 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
631 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
634 return dev->pict_src;
637 static void free_xrender_picture( struct xrender_physdev *dev )
639 if (dev->pict || dev->pict_src)
642 XFlush( gdi_display );
645 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
646 pXRenderFreePicture(gdi_display, dev->pict);
651 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
652 pXRenderFreePicture(gdi_display, dev->pict_src);
659 /* return a mask picture used to force alpha to 0 */
660 static Picture get_no_alpha_mask(void)
662 static Pixmap pixmap;
668 XRenderPictureAttributes pa;
671 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
672 pa.repeat = RepeatNormal;
673 pa.component_alpha = True;
674 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
675 CPRepeat|CPComponentAlpha, &pa );
676 col.red = col.green = col.blue = 0xffff;
678 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
684 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
686 if(p1->hash != p2->hash) return TRUE;
687 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
688 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
689 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
690 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
694 static void walk_cache(void)
698 EnterCriticalSection(&xrender_cs);
699 for(i=mru; i >= 0; i = glyphsetCache[i].next)
700 TRACE("item %d\n", i);
701 LeaveCriticalSection(&xrender_cs);
705 static int LookupEntry(LFANDSIZE *plfsz)
709 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
711 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
713 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
714 glyphsetCache[i].count++;
716 glyphsetCache[prev_i].next = glyphsetCache[i].next;
717 glyphsetCache[i].next = mru;
720 TRACE("found font in cache %d\n", i);
725 TRACE("font not in cache\n");
729 static void FreeEntry(int entry)
733 for(format = 0; format < AA_MAXVALUE; format++) {
734 gsCacheEntryFormat * formatEntry;
736 if( !glyphsetCache[entry].format[format] )
739 formatEntry = glyphsetCache[entry].format[format];
741 if(formatEntry->glyphset) {
743 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
745 formatEntry->glyphset = 0;
747 if(formatEntry->nrealized) {
748 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
749 formatEntry->realized = NULL;
750 if(formatEntry->bitmaps) {
751 for(i = 0; i < formatEntry->nrealized; i++)
752 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps[i]);
753 HeapFree(GetProcessHeap(), 0, formatEntry->bitmaps);
754 formatEntry->bitmaps = NULL;
756 HeapFree(GetProcessHeap(), 0, formatEntry->gis);
757 formatEntry->gis = NULL;
758 formatEntry->nrealized = 0;
761 HeapFree(GetProcessHeap(), 0, formatEntry);
762 glyphsetCache[entry].format[format] = NULL;
766 static int AllocEntry(void)
768 int best = -1, prev_best = -1, i, prev_i = -1;
771 assert(glyphsetCache[lastfree].count == -1);
772 glyphsetCache[lastfree].count = 1;
774 lastfree = glyphsetCache[lastfree].next;
776 glyphsetCache[best].next = mru;
779 TRACE("empty space at %d, next lastfree = %d\n", mru, lastfree);
783 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
784 if(glyphsetCache[i].count == 0) {
792 TRACE("freeing unused glyphset at cache %d\n", best);
794 glyphsetCache[best].count = 1;
796 glyphsetCache[prev_best].next = glyphsetCache[best].next;
797 glyphsetCache[best].next = mru;
805 TRACE("Growing cache\n");
808 glyphsetCache = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
810 (glyphsetCacheSize + INIT_CACHE_SIZE)
811 * sizeof(*glyphsetCache));
813 glyphsetCache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
814 (glyphsetCacheSize + INIT_CACHE_SIZE)
815 * sizeof(*glyphsetCache));
817 for(best = i = glyphsetCacheSize; i < glyphsetCacheSize + INIT_CACHE_SIZE;
819 glyphsetCache[i].next = i + 1;
820 glyphsetCache[i].count = -1;
822 glyphsetCache[i-1].next = -1;
823 glyphsetCacheSize += INIT_CACHE_SIZE;
825 lastfree = glyphsetCache[best].next;
826 glyphsetCache[best].count = 1;
827 glyphsetCache[best].next = mru;
829 TRACE("new free cache slot at %d\n", mru);
833 static BOOL get_gasp_flags(HDC hdc, WORD *flags)
843 size = GetFontData(hdc, MS_GASP_TAG, 0, NULL, 0);
844 if(size == GDI_ERROR)
847 gasp = buffer = HeapAlloc(GetProcessHeap(), 0, size);
848 GetFontData(hdc, MS_GASP_TAG, 0, gasp, size);
850 GetTextMetricsW(hdc, &tm);
851 ppem = abs(X11DRV_YWStoDS(hdc, tm.tmAscent + tm.tmDescent - tm.tmInternalLeading));
854 num_recs = get_be_word(*gasp);
858 *flags = get_be_word(*(gasp + 1));
859 if(ppem <= get_be_word(*gasp))
863 TRACE("got flags %04x for ppem %d\n", *flags, ppem);
865 HeapFree(GetProcessHeap(), 0, buffer);
869 static AA_Type get_antialias_type( HDC hdc, BOOL subpixel, BOOL hinter )
873 UINT font_smoothing_type, font_smoothing_orientation;
875 if (X11DRV_XRender_Installed && subpixel &&
876 SystemParametersInfoW( SPI_GETFONTSMOOTHINGTYPE, 0, &font_smoothing_type, 0) &&
877 font_smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
879 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHINGORIENTATION, 0,
880 &font_smoothing_orientation, 0) &&
881 font_smoothing_orientation == FE_FONTSMOOTHINGORIENTATIONBGR)
888 If the monitor is in portrait mode, ClearType is disabled in the MS Windows (MSDN).
889 But, Wine's subpixel rendering can support the portrait mode.
892 else if (!hinter || !get_gasp_flags(hdc, &flags) || flags & GASP_DOGRAY)
900 static int GetCacheEntry( HDC hdc, LFANDSIZE *plfsz )
905 static int hinter = -1;
906 static int subpixel = -1;
909 if((ret = LookupEntry(plfsz)) != -1) return ret;
912 entry = glyphsetCache + ret;
913 entry->lfsz = *plfsz;
914 for( format = 0; format < AA_MAXVALUE; format++ ) {
915 assert( !entry->format[format] );
918 if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY)
920 if(hinter == -1 || subpixel == -1)
922 RASTERIZER_STATUS status;
923 GetRasterizerCaps(&status, sizeof(status));
924 hinter = status.wFlags & WINE_TT_HINTER_ENABLED;
925 subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED;
928 switch (plfsz->lf.lfQuality)
930 case ANTIALIASED_QUALITY:
931 entry->aa_default = get_antialias_type( hdc, FALSE, hinter );
932 return ret; /* ignore further configuration */
933 case CLEARTYPE_QUALITY:
934 case CLEARTYPE_NATURAL_QUALITY:
935 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
937 case DEFAULT_QUALITY:
941 if ( SystemParametersInfoW( SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0) &&
944 entry->aa_default = get_antialias_type( hdc, subpixel, hinter );
947 entry->aa_default = AA_None;
951 font_smoothing = TRUE; /* default to enabled */
952 #ifdef SONAME_LIBFONTCONFIG
953 if (fontconfig_installed)
955 FcPattern *match, *pattern = pFcPatternCreate();
957 char family[LF_FACESIZE * 4];
959 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
960 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
961 if (plfsz->lf.lfWeight != FW_DONTCARE)
964 switch (plfsz->lf.lfWeight)
966 case FW_THIN: weight = FC_WEIGHT_THIN; break;
967 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
968 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
969 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
970 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
971 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
972 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
973 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
974 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
975 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
977 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
979 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
980 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
981 pFcDefaultSubstitute( pattern );
982 if ((match = pFcFontMatch( NULL, pattern, &result )))
987 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
989 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
992 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
994 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
995 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
999 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1000 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1001 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1002 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1003 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1006 if (!antialias) font_smoothing = FALSE;
1007 pFcPatternDestroy( match );
1009 pFcPatternDestroy( pattern );
1011 #endif /* SONAME_LIBFONTCONFIG */
1013 /* now check Xft resources */
1016 BOOL antialias = TRUE;
1019 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1021 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1022 value[0] == '0' || !strcasecmp( value, "off" ))
1025 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1027 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1028 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1029 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1030 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1031 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1032 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1034 wine_tsx11_unlock();
1035 if (!antialias) font_smoothing = FALSE;
1038 if (!font_smoothing) entry->aa_default = AA_None;
1040 /* we can't support subpixel without xrender */
1041 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1044 entry->aa_default = AA_None;
1049 static void dec_ref_cache(int index)
1052 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1053 assert(glyphsetCache[index].count > 0);
1054 glyphsetCache[index].count--;
1057 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1059 DWORD hash = 0, *ptr, two_chars;
1063 hash ^= plfsz->devsize.cx;
1064 hash ^= plfsz->devsize.cy;
1065 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1067 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1069 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1071 pwc = (WCHAR *)&two_chars;
1073 *pwc = toupperW(*pwc);
1075 *pwc = toupperW(*pwc);
1083 /***********************************************************************
1084 * X11DRV_XRender_Finalize
1086 void X11DRV_XRender_Finalize(void)
1090 EnterCriticalSection(&xrender_cs);
1091 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1093 LeaveCriticalSection(&xrender_cs);
1096 /**********************************************************************
1097 * xrenderdrv_SelectFont
1099 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1101 struct xrender_physdev *physdev = get_xrender_dev( dev );
1102 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1103 HFONT ret = next->funcs->pSelectFont( next, hfont );
1107 if (physdev->x11dev->has_gdi_font)
1111 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1113 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1114 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1115 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1116 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1117 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1118 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1120 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1121 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1122 lfsz.xform.eM21, lfsz.xform.eM22);
1124 /* Not used fields, would break hashing */
1125 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1127 lfsz_calc_hash(&lfsz);
1129 EnterCriticalSection(&xrender_cs);
1130 if (physdev->cache_index != -1)
1131 dec_ref_cache( physdev->cache_index );
1132 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1133 LeaveCriticalSection(&xrender_cs);
1137 EnterCriticalSection( &xrender_cs );
1138 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1139 physdev->cache_index = -1;
1140 LeaveCriticalSection( &xrender_cs );
1145 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1147 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1148 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1150 if (!physdev) return FALSE;
1151 physdev->x11dev = x11dev;
1152 physdev->cache_index = -1;
1153 physdev->format = format;
1154 physdev->pict_format = pict_formats[format];
1155 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1159 /* store the color mask data in the bitmap info structure */
1160 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1162 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1164 info->bmiHeader.biPlanes = 1;
1165 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1166 info->bmiHeader.biCompression = BI_RGB;
1167 info->bmiHeader.biClrUsed = 0;
1169 switch (info->bmiHeader.biBitCount)
1172 colors[0] = format->direct.redMask << format->direct.red;
1173 colors[1] = format->direct.greenMask << format->direct.green;
1174 colors[2] = format->direct.blueMask << format->direct.blue;
1175 info->bmiHeader.biCompression = BI_BITFIELDS;
1178 colors[0] = format->direct.redMask << format->direct.red;
1179 colors[1] = format->direct.greenMask << format->direct.green;
1180 colors[2] = format->direct.blueMask << format->direct.blue;
1181 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1182 info->bmiHeader.biCompression = BI_BITFIELDS;
1188 /**********************************************************************
1189 * xrenderdrv_CreateDC
1191 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1192 LPCWSTR output, const DEVMODEW* initData )
1194 return create_xrender_dc( pdev, default_format );
1197 /**********************************************************************
1198 * xrenderdrv_CreateCompatibleDC
1200 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1202 if (orig) /* chain to x11drv first */
1204 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1205 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1207 /* otherwise we have been called by x11drv */
1209 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1212 /**********************************************************************
1213 * xrenderdrv_DeleteDC
1215 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1217 struct xrender_physdev *physdev = get_xrender_dev( dev );
1219 free_xrender_picture( physdev );
1221 EnterCriticalSection( &xrender_cs );
1222 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1223 LeaveCriticalSection( &xrender_cs );
1225 HeapFree( GetProcessHeap(), 0, physdev );
1229 /**********************************************************************
1230 * xrenderdrv_ExtEscape
1232 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1233 INT out_count, LPVOID out_data )
1235 struct xrender_physdev *physdev = get_xrender_dev( dev );
1237 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1239 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1241 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1243 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1244 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1248 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1251 /****************************************************************************
1252 * xrenderdrv_CreateBitmap
1254 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1256 enum wxr_format format = WXR_INVALID_FORMAT;
1259 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1261 if (bitmap.bmPlanes == 1 && bitmap.bmBitsPixel == screen_bpp)
1263 switch (bitmap.bmBitsPixel)
1265 case 16: format = WXR_FORMAT_R5G6B5; break;
1266 case 24: format = WXR_FORMAT_R8G8B8; break;
1267 case 32: format = WXR_FORMAT_A8R8G8B8; break;
1271 if (pict_formats[format])
1272 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1273 TRUE, &wxr_color_shifts[format] );
1275 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1276 return dev->funcs->pCreateBitmap( dev, hbitmap );
1279 /****************************************************************************
1280 * xrenderdrv_DeleteBitmap
1282 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1284 return X11DRV_DeleteBitmap( hbitmap );
1287 /***********************************************************************
1288 * xrenderdrv_SelectBitmap
1290 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1293 struct xrender_physdev *physdev = get_xrender_dev( dev );
1295 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1296 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1299 free_xrender_picture( physdev );
1300 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1301 physdev->x11dev->color_shifts );
1302 physdev->pict_format = pict_formats[physdev->format];
1307 /***********************************************************************
1308 * xrenderdrv_GetImage
1310 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1311 struct gdi_image_bits *bits, struct bitblt_coords *src )
1313 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1314 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1315 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1318 /***********************************************************************
1319 * xrenderdrv_SetDeviceClipping
1321 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1323 struct xrender_physdev *physdev = get_xrender_dev( dev );
1325 physdev->update_clip = TRUE;
1327 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1328 dev->funcs->pSetDeviceClipping( dev, vis_rgn, clip_rgn );
1332 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1334 XRenderPictFormat *pict_format;
1336 const DWORD *bitfields;
1337 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1338 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1341 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1342 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1343 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1344 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1347 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1348 bitfields = dib->dsBitfields;
1349 else if(bits_pixel == 24 || bits_pixel == 32)
1350 bitfields = bitfields_32;
1352 bitfields = bitfields_16;
1354 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1355 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1357 /* Common formats should be in our picture format table. */
1360 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1361 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1365 physBitmap->depth = pict_format->depth;
1366 physBitmap->trueColor = TRUE;
1367 physBitmap->color_shifts = shifts;
1371 /************************************************************************
1374 * Helper to ExtTextOut. Must be called inside xrender_cs
1376 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1378 unsigned int buflen;
1383 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1384 gsCacheEntryFormat *formatEntry;
1385 UINT ggo_format = GGO_GLYPH_INDEX;
1386 enum wxr_format wxr_format;
1387 static const char zero[4];
1388 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1392 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1395 ggo_format |= WINE_GGO_HRGB_BITMAP;
1398 ggo_format |= WINE_GGO_HBGR_BITMAP;
1401 ggo_format |= WINE_GGO_VRGB_BITMAP;
1404 ggo_format |= WINE_GGO_VBGR_BITMAP;
1408 ERR("aa = %d - not implemented\n", format);
1410 ggo_format |= GGO_BITMAP;
1414 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1415 if(buflen == GDI_ERROR) {
1416 if(format != AA_None) {
1418 entry->aa_default = AA_None;
1419 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1420 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1422 if(buflen == GDI_ERROR) {
1423 WARN("GetGlyphOutlineW failed using default glyph\n");
1424 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1425 if(buflen == GDI_ERROR) {
1426 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1427 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1428 if(buflen == GDI_ERROR) {
1429 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1434 TRACE("Turning off antialiasing for this monochrome font\n");
1437 /* If there is nothing for the current type, we create the entry. */
1438 if( !entry->format[format] ) {
1439 entry->format[format] = HeapAlloc(GetProcessHeap(),
1441 sizeof(gsCacheEntryFormat));
1443 formatEntry = entry->format[format];
1445 if(formatEntry->nrealized <= glyph) {
1446 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1448 if (formatEntry->realized)
1449 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1451 formatEntry->realized,
1452 formatEntry->nrealized * sizeof(BOOL));
1454 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1456 formatEntry->nrealized * sizeof(BOOL));
1458 if(!X11DRV_XRender_Installed) {
1459 if (formatEntry->bitmaps)
1460 formatEntry->bitmaps = HeapReAlloc(GetProcessHeap(),
1462 formatEntry->bitmaps,
1463 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1465 formatEntry->bitmaps = HeapAlloc(GetProcessHeap(),
1467 formatEntry->nrealized * sizeof(formatEntry->bitmaps[0]));
1469 if (formatEntry->gis)
1470 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1473 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1475 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1477 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1481 if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) {
1484 wxr_format = WXR_FORMAT_GRAY;
1491 wxr_format = WXR_FORMAT_A8R8G8B8;
1495 ERR("aa = %d - not implemented\n", format);
1497 wxr_format = WXR_FORMAT_MONO;
1502 formatEntry->font_format = pict_formats[wxr_format];
1503 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1504 wine_tsx11_unlock();
1508 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1509 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1510 formatEntry->realized[glyph] = TRUE;
1512 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1514 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1515 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1517 gi.width = gm.gmBlackBoxX;
1518 gi.height = gm.gmBlackBoxY;
1519 gi.x = -gm.gmptGlyphOrigin.x;
1520 gi.y = gm.gmptGlyphOrigin.y;
1521 gi.xOff = gm.gmCellIncX;
1522 gi.yOff = gm.gmCellIncY;
1524 if(TRACE_ON(xrender)) {
1527 unsigned char *line;
1529 if(format == AA_None) {
1530 pitch = ((gi.width + 31) / 32) * 4;
1531 for(i = 0; i < gi.height; i++) {
1532 line = (unsigned char*) buf + i * pitch;
1534 for(j = 0; j < pitch * 8; j++) {
1535 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1537 TRACE("%s\n", output);
1540 static const char blks[] = " .:;!o*#";
1544 pitch = ((gi.width + 3) / 4) * 4;
1545 for(i = 0; i < gi.height; i++) {
1546 line = (unsigned char*) buf + i * pitch;
1548 for(j = 0; j < pitch; j++) {
1549 str[0] = blks[line[j] >> 5];
1550 strcat(output, str);
1552 TRACE("%s\n", output);
1558 if(formatEntry->glyphset) {
1559 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1560 unsigned char *byte = (unsigned char*) buf, c;
1566 /* magic to flip bit order */
1567 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1568 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1569 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1574 else if ( format != AA_Grey &&
1575 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1577 unsigned int i, *data = (unsigned int *)buf;
1578 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1583 XRenderCompositeText seems to ignore 0x0 glyphs when
1584 AA_None, which means we lose the advance width of glyphs
1585 like the space. We'll pretend that such glyphs are 1x1
1590 gi.width = gi.height = 1;
1593 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1594 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1595 wine_tsx11_unlock();
1596 HeapFree(GetProcessHeap(), 0, buf);
1598 formatEntry->bitmaps[glyph] = buf;
1601 formatEntry->gis[glyph] = gi;
1604 static void SharpGlyphMono(struct xrender_physdev *physDev, INT x, INT y,
1605 void *bitmap, XGlyphInfo *gi)
1607 unsigned char *srcLine = bitmap, *src;
1608 unsigned char bits, bitsMask;
1609 int width = gi->width;
1610 int stride = ((width + 31) & ~31) >> 3;
1611 int height = gi->height;
1615 TRACE("%d, %d\n", x, y);
1624 bitsMask = 0x80; /* FreeType is always MSB first */
1630 if (bits & bitsMask)
1638 bitsMask = bitsMask >> 1;
1644 } while (bits & bitsMask);
1645 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1646 physDev->x11dev->gc, xspan, y, lenspan, 1);
1658 bitsMask = bitsMask >> 1;
1664 } while (!(bits & bitsMask));
1671 static void SharpGlyphGray(struct xrender_physdev *physDev, INT x, INT y,
1672 void *bitmap, XGlyphInfo *gi)
1674 unsigned char *srcLine = bitmap, *src, bits;
1675 int width = gi->width;
1676 int stride = ((width + 3) & ~3);
1677 int height = gi->height;
1702 } while (bits >= 0x80);
1703 XFillRectangle (gdi_display, physDev->x11dev->drawable,
1704 physDev->x11dev->gc, xspan, y, lenspan, 1);
1717 } while (bits < 0x80);
1725 static void ExamineBitfield (DWORD mask, int *shift, int *len)
1730 while ((mask & 1) == 0)
1736 while ((mask & 1) == 1)
1745 static DWORD GetField (DWORD pixel, int shift, int len)
1747 pixel = pixel & (((1 << (len)) - 1) << shift);
1748 pixel = pixel << (32 - (shift + len)) >> 24;
1751 pixel |= (pixel >> len);
1758 static DWORD PutField (DWORD pixel, int shift, int len)
1760 shift = shift - (8 - len);
1762 pixel &= (((1 << len) - 1) << (8 - len));
1770 static void SmoothGlyphGray(XImage *image, int x, int y, void *bitmap, XGlyphInfo *gi,
1776 BYTE *maskLine, *mask, m;
1781 BYTE src_r, src_g, src_b;
1786 height = gi->height;
1789 maskStride = (width + 3) & ~3;
1791 ExamineBitfield (image->red_mask, &r_shift, &r_len);
1792 ExamineBitfield (image->green_mask, &g_shift, &g_len);
1793 ExamineBitfield (image->blue_mask, &b_shift, &b_len);
1795 src_r = GetField(color, r_shift, r_len);
1796 src_g = GetField(color, g_shift, g_len);
1797 src_b = GetField(color, b_shift, b_len);
1799 for(; height--; y++)
1802 maskLine += maskStride;
1807 if(y >= image->height) break;
1811 if(tx >= image->width) break;
1814 if(tx < 0) continue;
1817 XPutPixel (image, tx, y, color);
1822 pixel = XGetPixel (image, tx, y);
1824 r = GetField(pixel, r_shift, r_len);
1825 r = ((BYTE)~m * (WORD)r + (BYTE)m * (WORD)src_r) >> 8;
1826 g = GetField(pixel, g_shift, g_len);
1827 g = ((BYTE)~m * (WORD)g + (BYTE)m * (WORD)src_g) >> 8;
1828 b = GetField(pixel, b_shift, b_len);
1829 b = ((BYTE)~m * (WORD)b + (BYTE)m * (WORD)src_b) >> 8;
1831 pixel = (PutField (r, r_shift, r_len) |
1832 PutField (g, g_shift, g_len) |
1833 PutField (b, b_shift, b_len));
1834 XPutPixel (image, tx, y, pixel);
1840 /*************************************************************
1843 * Returns an appropriate Picture for tiling the text colour.
1844 * Call and use result within the xrender_cs
1846 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1852 XRenderColor current_color;
1853 } tiles[WXR_NB_FORMATS], *tile;
1855 tile = &tiles[wxr_format];
1859 XRenderPictureAttributes pa;
1860 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1863 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1865 pa.repeat = RepeatNormal;
1866 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1867 wine_tsx11_unlock();
1869 /* init current_color to something different from text_pixel */
1870 tile->current_color = *color;
1871 tile->current_color.red ^= 0xffff;
1873 if (wxr_format == WXR_FORMAT_MONO)
1875 /* for a 1bpp bitmap we always need a 1 in the tile */
1877 col.red = col.green = col.blue = 0;
1880 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1881 wine_tsx11_unlock();
1885 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1888 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1889 wine_tsx11_unlock();
1890 tile->current_color = *color;
1895 /*************************************************************
1898 * Returns an appropriate Picture for masking with the specified alpha.
1899 * Call and use result within the xrender_cs
1901 static Picture get_mask_pict( int alpha )
1903 static Pixmap pixmap;
1904 static Picture pict;
1905 static int current_alpha;
1907 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1911 XRenderPictureAttributes pa;
1914 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1915 pa.repeat = RepeatNormal;
1916 pict = pXRenderCreatePicture( gdi_display, pixmap,
1917 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1918 wine_tsx11_unlock();
1922 if (alpha != current_alpha)
1925 col.red = col.green = col.blue = 0;
1926 col.alpha = current_alpha = alpha;
1928 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1929 wine_tsx11_unlock();
1934 static int XRenderErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
1939 /********************************************************************
1940 * is_dib_with_colortable
1942 * Return TRUE if physdev is backed by a dibsection with <= 8 bits per pixel
1944 static inline BOOL is_dib_with_colortable( X11DRV_PDEVICE *physDev )
1948 if( physDev->bitmap && GetObjectW( physDev->bitmap->hbitmap, sizeof(dib), &dib ) == sizeof(dib) &&
1949 dib.dsBmih.biBitCount <= 8 )
1955 /***********************************************************************
1956 * xrenderdrv_ExtTextOut
1958 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1959 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1961 struct xrender_physdev *physdev = get_xrender_dev( dev );
1963 gsCacheEntry *entry;
1964 gsCacheEntryFormat *formatEntry;
1966 int textPixel, backgroundPixel;
1967 RGNDATA *saved_region = NULL;
1968 BOOL disable_antialias = FALSE;
1969 AA_Type aa_type = AA_None;
1971 Picture tile_pict = 0;
1973 if (!physdev->x11dev->has_gdi_font)
1975 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1976 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1979 if(is_dib_with_colortable( physdev->x11dev ))
1981 TRACE("Disabling antialiasing\n");
1982 disable_antialias = TRUE;
1985 xgcval.function = GXcopy;
1986 xgcval.background = physdev->x11dev->backgroundPixel;
1987 xgcval.fill_style = FillSolid;
1989 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1990 wine_tsx11_unlock();
1992 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1994 if(physdev->x11dev->depth == 1) {
1995 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1997 backgroundPixel = 1;
2000 backgroundPixel = 0;
2003 textPixel = physdev->x11dev->textPixel;
2004 backgroundPixel = physdev->x11dev->backgroundPixel;
2007 if(flags & ETO_OPAQUE)
2010 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
2011 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
2012 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
2013 lprect->right - lprect->left, lprect->bottom - lprect->top );
2014 wine_tsx11_unlock();
2023 EnterCriticalSection(&xrender_cs);
2025 entry = glyphsetCache + physdev->cache_index;
2026 if( disable_antialias == FALSE )
2027 aa_type = entry->aa_default;
2028 formatEntry = entry->format[aa_type];
2030 for(idx = 0; idx < count; idx++) {
2031 if( !formatEntry ) {
2032 UploadGlyph(physdev, wstr[idx], aa_type);
2033 /* re-evaluate antialias since aa_default may have changed */
2034 if( disable_antialias == FALSE )
2035 aa_type = entry->aa_default;
2036 formatEntry = entry->format[aa_type];
2037 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
2038 UploadGlyph(physdev, wstr[idx], aa_type);
2043 WARN("could not upload requested glyphs\n");
2044 LeaveCriticalSection(&xrender_cs);
2048 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
2049 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2051 if(X11DRV_XRender_Installed)
2053 XGlyphElt16 *elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
2054 POINT offset = {0, 0};
2055 POINT desired, current;
2056 int render_op = PictOpOver;
2057 Picture pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
2060 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
2061 So we pass zeros to the function and move to our starting position using the first
2062 element of the elts array. */
2064 desired.x = physdev->x11dev->dc_rect.left + x;
2065 desired.y = physdev->x11dev->dc_rect.top + y;
2066 current.x = current.y = 0;
2068 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
2069 tile_pict = get_tile_pict(physdev->format, &col);
2071 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
2073 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
2074 render_op = PictOpOutReverse; /* This gives us 'black' text */
2076 for(idx = 0; idx < count; idx++)
2078 elts[idx].glyphset = formatEntry->glyphset;
2079 elts[idx].chars = wstr + idx;
2080 elts[idx].nchars = 1;
2081 elts[idx].xOff = desired.x - current.x;
2082 elts[idx].yOff = desired.y - current.y;
2084 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
2085 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
2089 desired.x += formatEntry->gis[wstr[idx]].xOff;
2090 desired.y += formatEntry->gis[wstr[idx]].yOff;
2096 offset.x += lpDx[idx * 2];
2097 offset.y += lpDx[idx * 2 + 1];
2100 offset.x += lpDx[idx];
2101 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
2102 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
2107 /* Make sure we don't have any transforms set from a previous call */
2108 set_xrender_transformation(pict, 1, 1, 0, 0);
2109 pXRenderCompositeText16(gdi_display, render_op,
2112 formatEntry->font_format,
2113 0, 0, 0, 0, elts, count);
2114 wine_tsx11_unlock();
2115 HeapFree(GetProcessHeap(), 0, elts);
2117 POINT offset = {0, 0};
2119 if (flags & ETO_CLIPPED)
2121 HRGN clip_region = CreateRectRgnIndirect( lprect );
2122 saved_region = add_extra_clipping_region( physdev->x11dev, clip_region );
2123 DeleteObject( clip_region );
2127 XSetForeground( gdi_display, physdev->x11dev->gc, textPixel );
2129 if(aa_type == AA_None || physdev->x11dev->depth == 1)
2131 void (* sharp_glyph_fn)(struct xrender_physdev *, INT, INT, void *, XGlyphInfo *);
2133 if(aa_type == AA_None)
2134 sharp_glyph_fn = SharpGlyphMono;
2136 sharp_glyph_fn = SharpGlyphGray;
2138 for(idx = 0; idx < count; idx++) {
2139 sharp_glyph_fn(physdev,
2140 physdev->x11dev->dc_rect.left + x + offset.x,
2141 physdev->x11dev->dc_rect.top + y + offset.y,
2142 formatEntry->bitmaps[wstr[idx]],
2143 &formatEntry->gis[wstr[idx]]);
2148 offset.x += lpDx[idx * 2];
2149 offset.y += lpDx[idx * 2 + 1];
2152 offset.x += lpDx[idx];
2156 offset.x += formatEntry->gis[wstr[idx]].xOff;
2157 offset.y += formatEntry->gis[wstr[idx]].yOff;
2162 int image_x, image_y, image_off_x, image_off_y, image_w, image_h;
2163 RECT extents = {0, 0, 0, 0};
2165 int w = physdev->x11dev->drawable_rect.right - physdev->x11dev->drawable_rect.left;
2166 int h = physdev->x11dev->drawable_rect.bottom - physdev->x11dev->drawable_rect.top;
2168 TRACE("drawable %dx%d\n", w, h);
2170 for(idx = 0; idx < count; idx++) {
2171 if(extents.left > cur.x - formatEntry->gis[wstr[idx]].x)
2172 extents.left = cur.x - formatEntry->gis[wstr[idx]].x;
2173 if(extents.top > cur.y - formatEntry->gis[wstr[idx]].y)
2174 extents.top = cur.y - formatEntry->gis[wstr[idx]].y;
2175 if(extents.right < cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width)
2176 extents.right = cur.x - formatEntry->gis[wstr[idx]].x + formatEntry->gis[wstr[idx]].width;
2177 if(extents.bottom < cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height)
2178 extents.bottom = cur.y - formatEntry->gis[wstr[idx]].y + formatEntry->gis[wstr[idx]].height;
2184 cur.x += lpDx[idx * 2];
2185 cur.y += lpDx[idx * 2 + 1];
2192 cur.x += formatEntry->gis[wstr[idx]].xOff;
2193 cur.y += formatEntry->gis[wstr[idx]].yOff;
2196 TRACE("glyph extents %d,%d - %d,%d drawable x,y %d,%d\n", extents.left, extents.top,
2197 extents.right, extents.bottom, physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
2199 if(physdev->x11dev->dc_rect.left + x + extents.left >= 0) {
2200 image_x = physdev->x11dev->dc_rect.left + x + extents.left;
2204 image_off_x = physdev->x11dev->dc_rect.left + x + extents.left;
2206 if(physdev->x11dev->dc_rect.top + y + extents.top >= 0) {
2207 image_y = physdev->x11dev->dc_rect.top + y + extents.top;
2211 image_off_y = physdev->x11dev->dc_rect.top + y + extents.top;
2213 if(physdev->x11dev->dc_rect.left + x + extents.right < w)
2214 image_w = physdev->x11dev->dc_rect.left + x + extents.right - image_x;
2216 image_w = w - image_x;
2217 if(physdev->x11dev->dc_rect.top + y + extents.bottom < h)
2218 image_h = physdev->x11dev->dc_rect.top + y + extents.bottom - image_y;
2220 image_h = h - image_y;
2222 if(image_w <= 0 || image_h <= 0) goto no_image;
2224 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2225 image = XGetImage(gdi_display, physdev->x11dev->drawable,
2226 image_x, image_y, image_w, image_h,
2227 AllPlanes, ZPixmap);
2228 X11DRV_check_error();
2230 TRACE("XGetImage(%p, %x, %d, %d, %d, %d, %lx, %x) depth = %d rets %p\n",
2231 gdi_display, (int)physdev->x11dev->drawable, image_x, image_y,
2232 image_w, image_h, AllPlanes, ZPixmap,
2233 physdev->x11dev->depth, image);
2235 Pixmap xpm = XCreatePixmap(gdi_display, root_window, image_w, image_h,
2236 physdev->x11dev->depth);
2240 gcv.graphics_exposures = False;
2241 gc = XCreateGC(gdi_display, xpm, GCGraphicsExposures, &gcv);
2242 XCopyArea(gdi_display, physdev->x11dev->drawable, xpm, gc, image_x, image_y,
2243 image_w, image_h, 0, 0);
2244 XFreeGC(gdi_display, gc);
2245 X11DRV_expect_error(gdi_display, XRenderErrorHandler, NULL);
2246 image = XGetImage(gdi_display, xpm, 0, 0, image_w, image_h, AllPlanes,
2248 X11DRV_check_error();
2249 XFreePixmap(gdi_display, xpm);
2251 if(!image) goto no_image;
2253 image->red_mask = visual->red_mask;
2254 image->green_mask = visual->green_mask;
2255 image->blue_mask = visual->blue_mask;
2257 for(idx = 0; idx < count; idx++) {
2258 SmoothGlyphGray(image,
2259 offset.x + image_off_x - extents.left,
2260 offset.y + image_off_y - extents.top,
2261 formatEntry->bitmaps[wstr[idx]],
2262 &formatEntry->gis[wstr[idx]],
2263 physdev->x11dev->textPixel);
2268 offset.x += lpDx[idx * 2];
2269 offset.y += lpDx[idx * 2 + 1];
2272 offset.x += lpDx[idx];
2276 offset.x += formatEntry->gis[wstr[idx]].xOff;
2277 offset.y += formatEntry->gis[wstr[idx]].yOff;
2280 XPutImage(gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc, image, 0, 0,
2281 image_x, image_y, image_w, image_h);
2282 XDestroyImage(image);
2285 wine_tsx11_unlock();
2286 restore_clipping_region( physdev->x11dev, saved_region );
2288 LeaveCriticalSection(&xrender_cs);
2292 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2296 /* multiply the alpha channel of a picture */
2297 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
2298 int x, int y, int width, int height )
2300 XRenderPictureAttributes pa;
2301 Pixmap src_pixmap, mask_pixmap;
2302 Picture src_pict, mask_pict;
2306 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2307 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
2308 pa.repeat = RepeatNormal;
2309 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
2310 pa.component_alpha = True;
2311 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
2312 color.red = color.green = color.blue = color.alpha = 0xffff;
2313 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
2314 color.alpha = alpha;
2315 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
2316 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
2317 0, 0, 0, 0, x, y, width, height );
2318 pXRenderFreePicture( gdi_display, src_pict );
2319 pXRenderFreePicture( gdi_display, mask_pict );
2320 XFreePixmap( gdi_display, src_pixmap );
2321 XFreePixmap( gdi_display, mask_pixmap );
2322 wine_tsx11_unlock();
2325 /* Helper function for (stretched) blitting using xrender */
2326 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
2327 int x_src, int y_src, int x_dst, int y_dst,
2328 double xscale, double yscale, int width, int height )
2330 int x_offset, y_offset;
2332 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
2333 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
2334 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
2336 if(xscale != 1.0 || yscale != 1.0)
2338 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2339 * in the wrong quadrant of the x-y plane.
2341 x_offset = (xscale < 0) ? -width : 0;
2342 y_offset = (yscale < 0) ? -height : 0;
2343 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2349 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2351 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
2352 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
2353 wine_tsx11_unlock();
2356 /* Helper function for (stretched) mono->color blitting using xrender */
2357 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
2358 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
2359 int x_src, int y_src, int x_dst, int y_dst,
2360 double xscale, double yscale, int width, int height )
2363 int x_offset, y_offset;
2366 /* When doing a mono->color blit, the source data is used as mask, and the source picture
2367 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
2370 EnterCriticalSection( &xrender_cs );
2372 color.alpha = 0xffff; /* tile pict needs 100% alpha */
2373 tile_pict = get_tile_pict( dst_format, &color );
2376 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
2378 if (xscale != 1.0 || yscale != 1.0)
2380 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
2381 * in the wrong quadrant of the x-y plane.
2383 x_offset = (xscale < 0) ? -width : 0;
2384 y_offset = (yscale < 0) ? -height : 0;
2385 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
2391 set_xrender_transformation(src_pict, 1, 1, 0, 0);
2393 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
2394 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
2395 wine_tsx11_unlock();
2396 LeaveCriticalSection( &xrender_cs );
2398 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
2399 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
2400 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
2403 /* create a pixmap and render picture for an image */
2404 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
2405 struct bitblt_coords *src, enum wxr_format format,
2406 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
2409 int width = src->visrect.right - src->visrect.left;
2410 int height = src->visrect.bottom - src->visrect.top;
2411 int depth = pict_formats[format]->depth;
2412 struct gdi_image_bits dst_bits;
2413 XRenderPictureAttributes pa;
2417 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
2418 info->bmiHeader.biWidth, height, 32, 0 );
2419 wine_tsx11_unlock();
2420 if (!image) return ERROR_OUTOFMEMORY;
2422 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
2423 if (ret) return ret;
2425 image->data = dst_bits.ptr;
2426 /* hack: make sure the bits are readable if we are reading from a DIB section */
2427 /* to be removed once we get rid of DIB access protections */
2428 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
2430 *use_repeat = (width == 1 && height == 1);
2431 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
2434 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2435 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
2436 src->visrect.left, 0, 0, 0, width, height );
2437 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
2438 wine_tsx11_unlock();
2440 /* make coordinates relative to the pixmap */
2441 src->x -= src->visrect.left;
2442 src->y -= src->visrect.top;
2443 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2447 XDestroyImage( image );
2448 wine_tsx11_unlock();
2449 if (dst_bits.free) dst_bits.free( &dst_bits );
2453 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2454 Drawable drawable, const struct bitblt_coords *src,
2455 const struct bitblt_coords *dst )
2457 int width = abs( dst->width );
2458 int height = abs( dst->height );
2459 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2460 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2462 Picture src_pict = 0, dst_pict, mask_pict = 0;
2464 double xscale, yscale;
2466 use_repeat = use_source_repeat( physdev_src );
2469 xscale = src->width / (double)dst->width;
2470 yscale = src->height / (double)dst->height;
2472 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2474 if (drawable) /* using an intermediate pixmap */
2476 XRenderPictureAttributes pa;
2480 pa.repeat = RepeatNone;
2482 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2483 wine_tsx11_unlock();
2487 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2488 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2489 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2492 if (src->width < 0) x_src += src->width + 1;
2493 if (src->height < 0) y_src += src->height + 1;
2494 if (dst->width < 0) x_dst += dst->width + 1;
2495 if (dst->height < 0) y_dst += dst->height + 1;
2497 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2500 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2502 XRenderColor fg, bg;
2504 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, &fg );
2505 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, &bg );
2506 fg.alpha = bg.alpha = 0;
2508 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2509 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2511 else /* color -> color (can be at different depths) or mono -> mono */
2513 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2514 mask_pict = get_no_alpha_mask();
2516 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2517 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2523 pXRenderFreePicture( gdi_display, dst_pict );
2524 wine_tsx11_unlock();
2529 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2530 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2531 Drawable drawable, struct bitblt_coords *src,
2532 struct bitblt_coords *dst, BOOL use_repeat )
2534 int x_src, y_src, x_dst, y_dst;
2536 XRenderPictureAttributes pa;
2537 double xscale, yscale;
2539 if (drawable) /* using an intermediate pixmap */
2541 RGNDATA *clip_data = NULL;
2543 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2546 pa.repeat = RepeatNone;
2548 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2550 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2551 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2552 wine_tsx11_unlock();
2553 HeapFree( GetProcessHeap(), 0, clip_data );
2557 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2558 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2559 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2564 xscale = src->width / (double)dst->width;
2565 yscale = src->height / (double)dst->height;
2567 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2571 if (src->width < 0) x_src += src->width + 1;
2572 if (src->height < 0) y_src += src->height + 1;
2573 if (dst->width < 0) x_dst += dst->width + 1;
2574 if (dst->height < 0) y_dst += dst->height + 1;
2576 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2577 xscale, yscale, abs( dst->width ), abs( dst->height ));
2582 pXRenderFreePicture( gdi_display, dst_pict );
2583 wine_tsx11_unlock();
2588 /***********************************************************************
2589 * xrenderdrv_StretchBlt
2591 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2592 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2594 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2595 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2596 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2598 if (src_dev->funcs != dst_dev->funcs)
2600 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2601 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2604 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2606 /* XRender is of no use for color -> mono */
2607 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2608 goto x11drv_fallback;
2610 /* if not stretching, we only need to handle format conversion */
2611 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2613 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2614 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2620 struct bitblt_coords tmp;
2622 /* make coordinates relative to tmp pixmap */
2624 tmp.x -= tmp.visrect.left;
2625 tmp.y -= tmp.visrect.top;
2626 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2629 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2630 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2631 XSetGraphicsExposures( gdi_display, tmpGC, False );
2632 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2633 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2634 wine_tsx11_unlock();
2636 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2637 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2640 XFreePixmap( gdi_display, tmp_pixmap );
2641 XFreeGC( gdi_display, tmpGC );
2642 wine_tsx11_unlock();
2644 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2646 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2647 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2651 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2655 /***********************************************************************
2656 * xrenderdrv_PutImage
2658 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2659 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2660 struct bitblt_coords *dst, DWORD rop )
2662 struct xrender_physdev *physdev;
2663 X_PHYSBITMAP *bitmap;
2667 enum wxr_format src_format, dst_format;
2668 XRenderPictFormat *pict_format;
2670 Picture src_pict, mask_pict = 0;
2673 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2677 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2679 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2683 physdev = get_xrender_dev( dev );
2685 dst_format = physdev->format;
2688 src_format = get_xrender_format_from_bitmapinfo( info );
2689 if (!(pict_format = pict_formats[src_format])) goto update_format;
2691 /* make sure we can create an image with the same bpp */
2692 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2695 /* mono <-> color conversions not supported */
2696 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2697 goto x11drv_fallback;
2699 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2701 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2703 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2706 struct bitblt_coords tmp;
2710 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2711 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2713 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2715 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2716 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2718 X11DRV_DIB_Unlock( bitmap, TRUE );
2719 DeleteObject( rgn );
2723 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2727 RGNDATA *clip_data = NULL;
2729 /* make coordinates relative to tmp pixmap */
2731 tmp.x -= tmp.visrect.left;
2732 tmp.y -= tmp.visrect.top;
2733 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2735 if (clip) clip_data = add_extra_clipping_region( physdev->x11dev, clip );
2738 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2739 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2740 XSetGraphicsExposures( gdi_display, gc, False );
2741 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2742 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2743 wine_tsx11_unlock();
2745 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2746 NULL, tmp_pixmap, src, &tmp, use_repeat );
2747 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2750 XFreePixmap( gdi_display, tmp_pixmap );
2751 XFreeGC( gdi_display, gc );
2752 wine_tsx11_unlock();
2754 restore_clipping_region( physdev->x11dev, clip_data );
2756 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2757 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2759 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2763 pXRenderFreePicture( gdi_display, src_pict );
2764 XFreePixmap( gdi_display, src_pixmap );
2765 wine_tsx11_unlock();
2770 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2771 set_color_info( pict_formats[dst_format], info );
2772 return ERROR_BAD_FORMAT;
2775 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2776 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2777 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2781 /***********************************************************************
2782 * xrenderdrv_BlendImage
2784 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2785 struct bitblt_coords *src, struct bitblt_coords *dst,
2786 BLENDFUNCTION func )
2788 struct xrender_physdev *physdev = get_xrender_dev( dev );
2790 enum wxr_format format;
2791 XRenderPictFormat *pict_format;
2792 Picture dst_pict, src_pict, mask_pict;
2796 if (!X11DRV_XRender_Installed)
2798 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2799 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2802 format = get_xrender_format_from_bitmapinfo( info );
2803 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2804 format = get_format_without_alpha( format );
2805 else if (format != WXR_FORMAT_A8R8G8B8)
2806 return ERROR_INVALID_PARAMETER;
2808 if (!(pict_format = pict_formats[format])) goto update_format;
2810 /* make sure we can create an image with the same bpp */
2811 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2814 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2817 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2819 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2822 double xscale, yscale;
2824 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2828 xscale = src->width / (double)dst->width;
2829 yscale = src->height / (double)dst->height;
2831 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2833 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2835 EnterCriticalSection( &xrender_cs );
2836 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2838 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2839 physdev->x11dev->dc_rect.left + dst->x,
2840 physdev->x11dev->dc_rect.top + dst->y,
2841 xscale, yscale, dst->width, dst->height );
2844 pXRenderFreePicture( gdi_display, src_pict );
2845 XFreePixmap( gdi_display, src_pixmap );
2846 wine_tsx11_unlock();
2848 LeaveCriticalSection( &xrender_cs );
2850 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2855 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2856 set_color_info( physdev->pict_format, info );
2857 return ERROR_BAD_FORMAT;
2861 /***********************************************************************
2862 * xrenderdrv_AlphaBlend
2864 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2865 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2867 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2868 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2869 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2870 XRenderPictureAttributes pa;
2871 Pixmap tmp_pixmap = 0;
2872 double xscale, yscale;
2875 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2877 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2878 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2881 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2883 SetLastError( ERROR_INVALID_PARAMETER );
2887 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2888 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2890 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2892 use_repeat = use_source_repeat( physdev_src );
2895 xscale = src->width / (double)dst->width;
2896 yscale = src->height / (double)dst->height;
2898 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2900 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2902 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2904 /* mono -> color blending needs an intermediate color pixmap */
2905 XRenderColor fg, bg;
2906 int width = src->visrect.right - src->visrect.left;
2907 int height = src->visrect.bottom - src->visrect.top;
2909 /* blending doesn't use the destination DC colors */
2910 fg.red = fg.green = fg.blue = 0;
2911 bg.red = bg.green = bg.blue = 0xffff;
2912 fg.alpha = bg.alpha = 0xffff;
2915 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2916 physdev_dst->pict_format->depth );
2917 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2918 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2920 wine_tsx11_unlock();
2922 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2923 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2925 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2927 /* we need a source picture with no alpha */
2928 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2929 if (format != physdev_src->format)
2932 pa.subwindow_mode = IncludeInferiors;
2933 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2934 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2935 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2936 wine_tsx11_unlock();
2940 if (tmp_pict) src_pict = tmp_pict;
2942 EnterCriticalSection( &xrender_cs );
2943 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2945 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2946 physdev_src->x11dev->dc_rect.left + src->x,
2947 physdev_src->x11dev->dc_rect.top + src->y,
2948 physdev_dst->x11dev->dc_rect.left + dst->x,
2949 physdev_dst->x11dev->dc_rect.top + dst->y,
2950 xscale, yscale, dst->width, dst->height );
2953 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2954 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2955 wine_tsx11_unlock();
2957 LeaveCriticalSection( &xrender_cs );
2958 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2959 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2964 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
2966 /* At depths >1, the depth of physBitmap and physDev might not be the same e.g. the physbitmap might be a 16-bit DIB while the physdev uses 24-bit */
2967 int depth = physBitmap->depth == 1 ? 1 : physDev->depth;
2968 enum wxr_format src_format = get_xrender_format_from_color_shifts(physBitmap->depth, &physBitmap->color_shifts);
2969 enum wxr_format dst_format = get_xrender_format_from_color_shifts(physDev->depth, physDev->color_shifts);
2972 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, depth);
2974 /* Use XCopyArea when the physBitmap and brush.pixmap have the same format. */
2975 if( (physBitmap->depth == 1) || (!X11DRV_XRender_Installed && physDev->depth == physBitmap->depth) ||
2976 (src_format == dst_format) )
2978 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
2979 get_bitmap_gc(physBitmap->depth), 0, 0, width, height, 0, 0 );
2981 else /* We need depth conversion */
2983 Picture src_pict, dst_pict;
2984 XRenderPictureAttributes pa;
2985 pa.subwindow_mode = IncludeInferiors;
2986 pa.repeat = RepeatNone;
2988 src_pict = pXRenderCreatePicture(gdi_display, physBitmap->pixmap,
2989 pict_formats[src_format], CPSubwindowMode|CPRepeat, &pa);
2990 dst_pict = pXRenderCreatePicture(gdi_display, physDev->brush.pixmap,
2991 pict_formats[dst_format], CPSubwindowMode|CPRepeat, &pa);
2993 xrender_blit(PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, width, height);
2994 pXRenderFreePicture(gdi_display, src_pict);
2995 pXRenderFreePicture(gdi_display, dst_pict);
2997 wine_tsx11_unlock();
3000 static const struct gdi_dc_funcs xrender_funcs =
3002 NULL, /* pAbortDoc */
3003 NULL, /* pAbortPath */
3004 xrenderdrv_AlphaBlend, /* pAlphaBlend */
3005 NULL, /* pAngleArc */
3008 NULL, /* pBeginPath */
3009 xrenderdrv_BlendImage, /* pBlendImage */
3010 NULL, /* pChoosePixelFormat */
3012 NULL, /* pCloseFigure */
3013 xrenderdrv_CreateBitmap, /* pCreateBitmap */
3014 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
3015 xrenderdrv_CreateDC, /* pCreateDC */
3016 NULL, /* pCreateDIBSection */
3017 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
3018 xrenderdrv_DeleteDC, /* pDeleteDC */
3019 NULL, /* pDeleteObject */
3020 NULL, /* pDescribePixelFormat */
3021 NULL, /* pDeviceCapabilities */
3022 NULL, /* pEllipse */
3024 NULL, /* pEndPage */
3025 NULL, /* pEndPath */
3026 NULL, /* pEnumDeviceFonts */
3027 NULL, /* pEnumICMProfiles */
3028 NULL, /* pExcludeClipRect */
3029 NULL, /* pExtDeviceMode */
3030 xrenderdrv_ExtEscape, /* pExtEscape */
3031 NULL, /* pExtFloodFill */
3032 NULL, /* pExtSelectClipRgn */
3033 xrenderdrv_ExtTextOut, /* pExtTextOut */
3034 NULL, /* pFillPath */
3035 NULL, /* pFillRgn */
3036 NULL, /* pFlattenPath */
3037 NULL, /* pFrameRgn */
3038 NULL, /* pGdiComment */
3039 NULL, /* pGetCharWidth */
3040 NULL, /* pGetDeviceCaps */
3041 NULL, /* pGetDeviceGammaRamp */
3042 NULL, /* pGetICMProfile */
3043 xrenderdrv_GetImage, /* pGetImage */
3044 NULL, /* pGetNearestColor */
3045 NULL, /* pGetPixel */
3046 NULL, /* pGetPixelFormat */
3047 NULL, /* pGetSystemPaletteEntries */
3048 NULL, /* pGetTextExtentExPoint */
3049 NULL, /* pGetTextMetrics */
3050 NULL, /* pIntersectClipRect */
3051 NULL, /* pInvertRgn */
3053 NULL, /* pModifyWorldTransform */
3055 NULL, /* pOffsetClipRgn */
3056 NULL, /* pOffsetViewportOrg */
3057 NULL, /* pOffsetWindowOrg */
3058 NULL, /* pPaintRgn */
3061 NULL, /* pPolyBezier */
3062 NULL, /* pPolyBezierTo */
3063 NULL, /* pPolyDraw */
3064 NULL, /* pPolyPolygon */
3065 NULL, /* pPolyPolyline */
3066 NULL, /* pPolygon */
3067 NULL, /* pPolyline */
3068 NULL, /* pPolylineTo */
3069 xrenderdrv_PutImage, /* pPutImage */
3070 NULL, /* pRealizeDefaultPalette */
3071 NULL, /* pRealizePalette */
3072 NULL, /* pRectangle */
3073 NULL, /* pResetDC */
3074 NULL, /* pRestoreDC */
3075 NULL, /* pRoundRect */
3077 NULL, /* pScaleViewportExt */
3078 NULL, /* pScaleWindowExt */
3079 xrenderdrv_SelectBitmap, /* pSelectBitmap */
3080 NULL, /* pSelectBrush */
3081 NULL, /* pSelectClipPath */
3082 xrenderdrv_SelectFont, /* pSelectFont */
3083 NULL, /* pSelectPalette */
3084 NULL, /* pSelectPen */
3085 NULL, /* pSetArcDirection */
3086 NULL, /* pSetBkColor */
3087 NULL, /* pSetBkMode */
3088 NULL, /* pSetDCBrushColor */
3089 NULL, /* pSetDCPenColor */
3090 NULL, /* pSetDIBColorTable */
3091 NULL, /* pSetDIBitsToDevice */
3092 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
3093 NULL, /* pSetDeviceGammaRamp */
3094 NULL, /* pSetLayout */
3095 NULL, /* pSetMapMode */
3096 NULL, /* pSetMapperFlags */
3097 NULL, /* pSetPixel */
3098 NULL, /* pSetPixelFormat */
3099 NULL, /* pSetPolyFillMode */
3100 NULL, /* pSetROP2 */
3101 NULL, /* pSetRelAbs */
3102 NULL, /* pSetStretchBltMode */
3103 NULL, /* pSetTextAlign */
3104 NULL, /* pSetTextCharacterExtra */
3105 NULL, /* pSetTextColor */
3106 NULL, /* pSetTextJustification */
3107 NULL, /* pSetViewportExt */
3108 NULL, /* pSetViewportOrg */
3109 NULL, /* pSetWindowExt */
3110 NULL, /* pSetWindowOrg */
3111 NULL, /* pSetWorldTransform */
3112 NULL, /* pStartDoc */
3113 NULL, /* pStartPage */
3114 xrenderdrv_StretchBlt, /* pStretchBlt */
3115 NULL, /* pStretchDIBits */
3116 NULL, /* pStrokeAndFillPath */
3117 NULL, /* pStrokePath */
3118 NULL, /* pSwapBuffers */
3119 NULL, /* pUnrealizePalette */
3120 NULL, /* pWidenPath */
3121 /* OpenGL not supported */
3124 #else /* SONAME_LIBXRENDER */
3126 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
3128 TRACE("XRender support not compiled in.\n");
3132 void X11DRV_XRender_Finalize(void)
3136 void X11DRV_XRender_CopyBrush(X11DRV_PDEVICE *physDev, X_PHYSBITMAP *physBitmap, int width, int height)
3139 physDev->brush.pixmap = XCreatePixmap(gdi_display, root_window, width, height, physBitmap->pixmap_depth);
3141 XCopyArea( gdi_display, physBitmap->pixmap, physDev->brush.pixmap,
3142 get_bitmap_gc(physBitmap->pixmap_depth), 0, 0, width, height, 0, 0 );
3143 wine_tsx11_unlock();
3146 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
3151 #endif /* SONAME_LIBXRENDER */