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 WINE_DECLARE_DEBUG_CHANNEL(winediag);
49 static BOOL X11DRV_XRender_Installed = FALSE;
52 #include <X11/extensions/Xrender.h>
54 #ifndef RepeatNone /* added in 0.10 */
56 #define RepeatNormal 1
58 #define RepeatReflect 3
76 WXR_INVALID_FORMAT = WXR_NB_FORMATS
79 typedef struct wine_xrender_format_template
83 unsigned int alphaMask;
87 unsigned int greenMask;
89 unsigned int blueMask;
90 } WineXRenderFormatTemplate;
92 static const WineXRenderFormatTemplate wxr_formats_template[WXR_NB_FORMATS] =
94 /* Format depth alpha mask red mask green mask blue mask*/
95 /* WXR_FORMAT_MONO */ { 1, 0, 0x01, 0, 0, 0, 0, 0, 0 },
96 /* WXR_FORMAT_GRAY */ { 8, 0, 0xff, 0, 0, 0, 0, 0, 0 },
97 /* WXR_FORMAT_X1R5G5B5 */ { 16, 0, 0, 10, 0x1f, 5, 0x1f, 0, 0x1f },
98 /* WXR_FORMAT_X1B5G5R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x1f, 10, 0x1f },
99 /* WXR_FORMAT_R5G6B5 */ { 16, 0, 0, 11, 0x1f, 5, 0x3f, 0, 0x1f },
100 /* WXR_FORMAT_B5G6R5 */ { 16, 0, 0, 0, 0x1f, 5, 0x3f, 11, 0x1f },
101 /* WXR_FORMAT_R8G8B8 */ { 24, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
102 /* WXR_FORMAT_B8G8R8 */ { 24, 0, 0, 0, 0xff, 8, 0xff, 16, 0xff },
103 /* WXR_FORMAT_A8R8G8B8 */ { 32, 24, 0xff, 16, 0xff, 8, 0xff, 0, 0xff },
104 /* WXR_FORMAT_B8G8R8A8 */ { 32, 0, 0xff, 8, 0xff, 16, 0xff, 24, 0xff },
105 /* WXR_FORMAT_X8R8G8B8 */ { 32, 0, 0, 16, 0xff, 8, 0xff, 0, 0xff },
106 /* WXR_FORMAT_B8G8R8X8 */ { 32, 0, 0, 8, 0xff, 16, 0xff, 24, 0xff },
109 static const ColorShifts wxr_color_shifts[WXR_NB_FORMATS] =
111 /* format phys red phys green phys blue log red log green log blue */
112 /* WXR_FORMAT_MONO */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
113 /* WXR_FORMAT_GRAY */ { { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 }, { 0,0,0 } },
114 /* WXR_FORMAT_X1R5G5B5 */ { {10,5,31}, { 5,5,31}, { 0,5,31}, {10,5,31}, { 5,5,31}, { 0,5,31} },
115 /* WXR_FORMAT_X1B5G5R5 */ { { 0,5,31}, { 5,5,31}, {10,5,31}, { 0,5,31}, { 5,5,31}, {10,5,31} },
116 /* WXR_FORMAT_R5G6B5 */ { {11,5,31}, { 5,6,63}, { 0,5,31}, {11,5,31}, { 5,6,63}, { 0,5,31} },
117 /* WXR_FORMAT_B5G6R5 */ { { 0,5,31}, { 5,6,63}, {11,5,31}, { 0,5,31}, { 5,6,63}, {11,5,31} },
118 /* WXR_FORMAT_R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
119 /* WXR_FORMAT_B8G8R8 */ { { 0,8,255}, { 8,8,255}, {16,8,255}, { 0,8,255}, { 8,8,255}, {16,8,255} },
120 /* WXR_FORMAT_A8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
121 /* WXR_FORMAT_B8G8R8A8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
122 /* WXR_FORMAT_X8R8G8B8 */ { {16,8,255}, { 8,8,255}, { 0,8,255}, {16,8,255}, { 8,8,255}, { 0,8,255} },
123 /* WXR_FORMAT_B8G8R8X8 */ { { 8,8,255}, {16,8,255}, {24,8,255}, { 8,8,255}, {16,8,255}, {24,8,255} },
126 static enum wxr_format default_format = WXR_INVALID_FORMAT;
127 static XRenderPictFormat *pict_formats[WXR_NB_FORMATS + 1 /* invalid format */];
133 SIZE devsize; /* size in device coords */
137 #define INITIAL_REALIZED_BUF_SIZE 128
139 typedef enum { AA_None = 0, AA_Grey, AA_RGB, AA_BGR, AA_VRGB, AA_VBGR, AA_MAXVALUE } AA_Type;
144 XRenderPictFormat *font_format;
148 } gsCacheEntryFormat;
154 gsCacheEntryFormat * format[AA_MAXVALUE];
159 struct xrender_physdev
161 struct gdi_physdev dev;
162 X11DRV_PDEVICE *x11dev;
163 enum wxr_format format;
168 XRenderPictFormat *pict_format;
171 static inline struct xrender_physdev *get_xrender_dev( PHYSDEV dev )
173 return (struct xrender_physdev *)dev;
176 static const struct gdi_dc_funcs xrender_funcs;
178 static gsCacheEntry *glyphsetCache = NULL;
179 static DWORD glyphsetCacheSize = 0;
180 static INT lastfree = -1;
183 #define INIT_CACHE_SIZE 10
185 static int antialias = 1;
187 static void *xrender_handle;
189 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
190 MAKE_FUNCPTR(XRenderAddGlyphs)
191 MAKE_FUNCPTR(XRenderComposite)
192 MAKE_FUNCPTR(XRenderCompositeText16)
193 MAKE_FUNCPTR(XRenderCreateGlyphSet)
194 MAKE_FUNCPTR(XRenderCreatePicture)
195 MAKE_FUNCPTR(XRenderFillRectangle)
196 MAKE_FUNCPTR(XRenderFindFormat)
197 MAKE_FUNCPTR(XRenderFindVisualFormat)
198 MAKE_FUNCPTR(XRenderFreeGlyphSet)
199 MAKE_FUNCPTR(XRenderFreePicture)
200 MAKE_FUNCPTR(XRenderSetPictureClipRectangles)
201 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
202 MAKE_FUNCPTR(XRenderSetPictureTransform)
204 MAKE_FUNCPTR(XRenderQueryExtension)
206 #ifdef SONAME_LIBFONTCONFIG
207 #include <fontconfig/fontconfig.h>
208 MAKE_FUNCPTR(FcConfigSubstitute)
209 MAKE_FUNCPTR(FcDefaultSubstitute)
210 MAKE_FUNCPTR(FcFontMatch)
212 MAKE_FUNCPTR(FcPatternCreate)
213 MAKE_FUNCPTR(FcPatternDestroy)
214 MAKE_FUNCPTR(FcPatternAddInteger)
215 MAKE_FUNCPTR(FcPatternAddString)
216 MAKE_FUNCPTR(FcPatternGetBool)
217 MAKE_FUNCPTR(FcPatternGetInteger)
218 MAKE_FUNCPTR(FcPatternGetString)
219 static void *fontconfig_handle;
220 static BOOL fontconfig_installed;
225 static CRITICAL_SECTION xrender_cs;
226 static CRITICAL_SECTION_DEBUG critsect_debug =
229 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
230 0, 0, { (DWORD_PTR)(__FILE__ ": xrender_cs") }
232 static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
234 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
235 ( ( (ULONG)_x4 << 24 ) | \
236 ( (ULONG)_x3 << 16 ) | \
237 ( (ULONG)_x2 << 8 ) | \
240 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
242 #define GASP_GRIDFIT 0x01
243 #define GASP_DOGRAY 0x02
245 #ifdef WORDS_BIGENDIAN
246 #define get_be_word(x) (x)
247 #define NATIVE_BYTE_ORDER MSBFirst
249 #define get_be_word(x) RtlUshortByteSwap(x)
250 #define NATIVE_BYTE_ORDER LSBFirst
253 static BOOL has_alpha( enum wxr_format format )
255 return (format == WXR_FORMAT_A8R8G8B8 || format == WXR_FORMAT_B8G8R8A8);
258 static enum wxr_format get_format_without_alpha( enum wxr_format format )
262 case WXR_FORMAT_A8R8G8B8: return WXR_FORMAT_X8R8G8B8;
263 case WXR_FORMAT_B8G8R8A8: return WXR_FORMAT_B8G8R8X8;
264 default: return format;
268 static BOOL get_xrender_template(const WineXRenderFormatTemplate *fmt, XRenderPictFormat *templ, unsigned long *mask)
271 templ->type = PictTypeDirect;
272 templ->depth = fmt->depth;
273 templ->direct.alpha = fmt->alpha;
274 templ->direct.alphaMask = fmt->alphaMask;
275 templ->direct.red = fmt->red;
276 templ->direct.redMask = fmt->redMask;
277 templ->direct.green = fmt->green;
278 templ->direct.greenMask = fmt->greenMask;
279 templ->direct.blue = fmt->blue;
280 templ->direct.blueMask = fmt->blueMask;
283 *mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask;
288 static BOOL is_wxrformat_compatible_with_default_visual(const WineXRenderFormatTemplate *fmt)
290 if(fmt->depth != screen_depth)
292 if( (fmt->redMask << fmt->red) != visual->red_mask)
294 if( (fmt->greenMask << fmt->green) != visual->green_mask)
296 if( (fmt->blueMask << fmt->blue) != visual->blue_mask)
299 /* We never select a default ARGB visual */
306 static int load_xrender_formats(void)
311 for (i = 0; i < WXR_NB_FORMATS; i++)
313 XRenderPictFormat templ;
315 if(is_wxrformat_compatible_with_default_visual(&wxr_formats_template[i]))
318 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, visual);
319 if (!pict_formats[i])
321 /* Xrender doesn't like DirectColor visuals, try to find a TrueColor one instead */
322 if (visual->class == DirectColor)
325 if (XMatchVisualInfo( gdi_display, DefaultScreen(gdi_display),
326 screen_depth, TrueColor, &info ))
328 pict_formats[i] = pXRenderFindVisualFormat(gdi_display, info.visual);
329 if (pict_formats[i]) visual = info.visual;
334 if (pict_formats[i]) default_format = i;
338 unsigned long mask = 0;
339 get_xrender_template(&wxr_formats_template[i], &templ, &mask);
342 pict_formats[i] = pXRenderFindFormat(gdi_display, mask, &templ, 0);
348 TRACE("Loaded pict_format with id=%#lx for wxr_format=%#x\n", pict_formats[i]->id, i);
354 /***********************************************************************
355 * X11DRV_XRender_Init
357 * Let's see if our XServer has the extension available
360 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
364 using_client_side_fonts = client_side_with_render || client_side_with_core;
366 if (!client_side_with_render) return NULL;
367 if (!(xrender_handle = wine_dlopen(SONAME_LIBXRENDER, RTLD_NOW, NULL, 0))) return NULL;
369 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xrender_handle, #f, NULL, 0)) == NULL) return NULL
370 LOAD_FUNCPTR(XRenderAddGlyphs);
371 LOAD_FUNCPTR(XRenderComposite);
372 LOAD_FUNCPTR(XRenderCompositeText16);
373 LOAD_FUNCPTR(XRenderCreateGlyphSet);
374 LOAD_FUNCPTR(XRenderCreatePicture);
375 LOAD_FUNCPTR(XRenderFillRectangle);
376 LOAD_FUNCPTR(XRenderFindFormat);
377 LOAD_FUNCPTR(XRenderFindVisualFormat);
378 LOAD_FUNCPTR(XRenderFreeGlyphSet);
379 LOAD_FUNCPTR(XRenderFreePicture);
380 LOAD_FUNCPTR(XRenderSetPictureClipRectangles);
381 LOAD_FUNCPTR(XRenderQueryExtension);
383 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
384 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = wine_dlsym(xrender_handle, #f, NULL, 0)
385 LOAD_OPTIONAL_FUNCPTR(XRenderSetPictureTransform);
386 #undef LOAD_OPTIONAL_FUNCPTR
390 X11DRV_XRender_Installed = pXRenderQueryExtension(gdi_display, &event_base, &xrender_error_base);
392 if (!X11DRV_XRender_Installed) return NULL;
394 TRACE("Xrender is up and running error_base = %d\n", xrender_error_base);
395 if(!load_xrender_formats()) /* This fails in buggy versions of libXrender.so */
397 ERR_(winediag)("Wine has detected that you probably have a buggy version "
398 "of libXrender. Because of this client side font rendering "
399 "will be disabled. Please upgrade this library.\n");
400 X11DRV_XRender_Installed = FALSE;
404 if (!visual->red_mask || !visual->green_mask || !visual->blue_mask)
406 WARN("one or more of the colour masks are 0, disabling XRENDER. Try running in 16-bit mode or higher.\n");
407 X11DRV_XRender_Installed = FALSE;
411 #ifdef SONAME_LIBFONTCONFIG
412 if ((fontconfig_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0)))
414 #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;}
415 LOAD_FUNCPTR(FcConfigSubstitute);
416 LOAD_FUNCPTR(FcDefaultSubstitute);
417 LOAD_FUNCPTR(FcFontMatch);
418 LOAD_FUNCPTR(FcInit);
419 LOAD_FUNCPTR(FcPatternCreate);
420 LOAD_FUNCPTR(FcPatternDestroy);
421 LOAD_FUNCPTR(FcPatternAddInteger);
422 LOAD_FUNCPTR(FcPatternAddString);
423 LOAD_FUNCPTR(FcPatternGetBool);
424 LOAD_FUNCPTR(FcPatternGetInteger);
425 LOAD_FUNCPTR(FcPatternGetString);
427 fontconfig_installed = pFcInit();
429 else TRACE( "cannot find the fontconfig library " SONAME_LIBFONTCONFIG "\n" );
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;
445 if(screen_depth <= 8 || !client_side_antialias_with_render) antialias = 0;
447 return &xrender_funcs;
450 /* Helper function to convert from a color packed in a 32-bit integer to a XRenderColor */
451 static void get_xrender_color( XRenderPictFormat *pf, int src_color, XRenderColor *dst_color )
453 if(pf->direct.redMask)
454 dst_color->red = ((src_color >> pf->direct.red) & pf->direct.redMask) * 65535/pf->direct.redMask;
458 if(pf->direct.greenMask)
459 dst_color->green = ((src_color >> pf->direct.green) & pf->direct.greenMask) * 65535/pf->direct.greenMask;
461 dst_color->green = 0;
463 if(pf->direct.blueMask)
464 dst_color->blue = ((src_color >> pf->direct.blue) & pf->direct.blueMask) * 65535/pf->direct.blueMask;
468 dst_color->alpha = 0xffff;
471 static enum wxr_format get_xrender_format_from_color_shifts(int depth, ColorShifts *shifts)
473 int redMask, greenMask, blueMask;
476 if (depth == 1) return WXR_FORMAT_MONO;
478 /* physDevs of a depth <=8, don't have color_shifts set and XRender can't handle those except for 1-bit */
479 if (!shifts) return default_format;
481 redMask = shifts->physicalRed.max << shifts->physicalRed.shift;
482 greenMask = shifts->physicalGreen.max << shifts->physicalGreen.shift;
483 blueMask = shifts->physicalBlue.max << shifts->physicalBlue.shift;
485 /* Try to locate a format which matches the specification of the dibsection. */
486 for(i = 0; i < WXR_NB_FORMATS; i++)
488 if( depth == wxr_formats_template[i].depth &&
489 redMask == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
490 greenMask == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
491 blueMask == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue) )
495 /* This should not happen because when we reach 'shifts' must have been set and we only allows shifts which are backed by X */
496 ERR("No XRender format found for %u %08x/%08x/%08x\n", depth, redMask, greenMask, blueMask);
497 return WXR_INVALID_FORMAT;
500 static enum wxr_format get_xrender_format_from_bitmapinfo( const BITMAPINFO *info )
502 if (info->bmiHeader.biPlanes != 1) return WXR_INVALID_FORMAT;
504 switch (info->bmiHeader.biBitCount)
507 return WXR_FORMAT_MONO;
512 if (info->bmiHeader.biCompression != BI_RGB) break;
513 return WXR_FORMAT_R8G8B8;
516 if (info->bmiHeader.biCompression == BI_BITFIELDS)
518 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
521 for (i = 0; i < WXR_NB_FORMATS; i++)
523 if (info->bmiHeader.biBitCount == wxr_formats_template[i].depth &&
524 colors[0] == (wxr_formats_template[i].redMask << wxr_formats_template[i].red) &&
525 colors[1] == (wxr_formats_template[i].greenMask << wxr_formats_template[i].green) &&
526 colors[2] == (wxr_formats_template[i].blueMask << wxr_formats_template[i].blue))
531 if (info->bmiHeader.biCompression != BI_RGB) break;
532 return (info->bmiHeader.biBitCount == 16) ? WXR_FORMAT_X1R5G5B5 : WXR_FORMAT_A8R8G8B8;
534 return WXR_INVALID_FORMAT;
537 static enum wxr_format get_bitmap_format( int bpp )
539 enum wxr_format format = WXR_INVALID_FORMAT;
541 if (bpp == screen_bpp)
545 case 16: format = WXR_FORMAT_R5G6B5; break;
546 case 24: format = WXR_FORMAT_R8G8B8; break;
547 case 32: format = WXR_FORMAT_A8R8G8B8; break;
553 /* Set the x/y scaling and x/y offsets in the transformation matrix of the source picture */
554 static void set_xrender_transformation(Picture src_pict, double xscale, double yscale, int xoffset, int yoffset)
556 #ifdef HAVE_XRENDERSETPICTURETRANSFORM
557 XTransform xform = {{
558 { XDoubleToFixed(xscale), XDoubleToFixed(0), XDoubleToFixed(xoffset) },
559 { XDoubleToFixed(0), XDoubleToFixed(yscale), XDoubleToFixed(yoffset) },
560 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) }
563 pXRenderSetPictureTransform(gdi_display, src_pict, &xform);
567 /* check if we can use repeating instead of scaling for the specified source DC */
568 static BOOL use_source_repeat( struct xrender_physdev *dev )
570 return (dev->x11dev->bitmap &&
571 dev->x11dev->drawable_rect.right - dev->x11dev->drawable_rect.left == 1 &&
572 dev->x11dev->drawable_rect.bottom - dev->x11dev->drawable_rect.top == 1);
575 static Picture get_xrender_picture( struct xrender_physdev *dev, HRGN clip_rgn, const RECT *clip_rect )
577 if (!dev->pict && dev->pict_format)
579 XRenderPictureAttributes pa;
582 pa.subwindow_mode = IncludeInferiors;
583 dev->pict = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
584 dev->pict_format, CPSubwindowMode, &pa );
586 TRACE( "Allocing pict=%lx dc=%p drawable=%08lx\n",
587 dev->pict, dev->dev.hdc, dev->x11dev->drawable );
588 dev->update_clip = TRUE;
591 if (dev->update_clip)
598 rgn = CreateRectRgnIndirect( clip_rect );
599 if (clip_rgn) CombineRgn( rgn, rgn, clip_rgn, RGN_AND );
600 CombineRgn( rgn, rgn, dev->x11dev->region, RGN_AND );
604 rgn = CreateRectRgn( 0, 0, 0, 0 );
605 CombineRgn( rgn, clip_rgn, dev->x11dev->region, RGN_AND );
608 if ((clip_data = X11DRV_GetRegionData( rgn ? rgn : dev->x11dev->region, 0 )))
611 pXRenderSetPictureClipRectangles( gdi_display, dev->pict,
612 dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top,
613 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
615 HeapFree( GetProcessHeap(), 0, clip_data );
617 dev->update_clip = (rgn != 0); /* have to update again if we are using a custom region */
618 if (rgn) DeleteObject( rgn );
623 static Picture get_xrender_picture_source( struct xrender_physdev *dev, BOOL repeat )
625 if (!dev->pict_src && dev->pict_format)
627 XRenderPictureAttributes pa;
630 pa.subwindow_mode = IncludeInferiors;
631 pa.repeat = repeat ? RepeatNormal : RepeatNone;
632 dev->pict_src = pXRenderCreatePicture( gdi_display, dev->x11dev->drawable,
633 dev->pict_format, CPSubwindowMode|CPRepeat, &pa );
636 TRACE("Allocing pict_src=%lx dc=%p drawable=%08lx repeat=%u\n",
637 dev->pict_src, dev->dev.hdc, dev->x11dev->drawable, pa.repeat);
640 return dev->pict_src;
643 static void free_xrender_picture( struct xrender_physdev *dev )
645 if (dev->pict || dev->pict_src)
648 XFlush( gdi_display );
651 TRACE("freeing pict = %lx dc = %p\n", dev->pict, dev->dev.hdc);
652 pXRenderFreePicture(gdi_display, dev->pict);
657 TRACE("freeing pict = %lx dc = %p\n", dev->pict_src, dev->dev.hdc);
658 pXRenderFreePicture(gdi_display, dev->pict_src);
665 /* return a mask picture used to force alpha to 0 */
666 static Picture get_no_alpha_mask(void)
668 static Pixmap pixmap;
674 XRenderPictureAttributes pa;
677 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
678 pa.repeat = RepeatNormal;
679 pa.component_alpha = True;
680 pict = pXRenderCreatePicture( gdi_display, pixmap, pict_formats[WXR_FORMAT_A8R8G8B8],
681 CPRepeat|CPComponentAlpha, &pa );
682 col.red = col.green = col.blue = 0xffff;
684 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
690 static BOOL fontcmp(LFANDSIZE *p1, LFANDSIZE *p2)
692 if(p1->hash != p2->hash) return TRUE;
693 if(memcmp(&p1->devsize, &p2->devsize, sizeof(p1->devsize))) return TRUE;
694 if(memcmp(&p1->xform, &p2->xform, sizeof(p1->xform))) return TRUE;
695 if(memcmp(&p1->lf, &p2->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
696 return strcmpiW(p1->lf.lfFaceName, p2->lf.lfFaceName);
700 static void walk_cache(void)
704 EnterCriticalSection(&xrender_cs);
705 for(i=mru; i >= 0; i = glyphsetCache[i].next)
706 TRACE("item %d\n", i);
707 LeaveCriticalSection(&xrender_cs);
711 static int LookupEntry(LFANDSIZE *plfsz)
715 for(i = mru; i >= 0; i = glyphsetCache[i].next) {
717 if(glyphsetCache[i].count == -1) break; /* reached free list so stop */
719 if(!fontcmp(&glyphsetCache[i].lfsz, plfsz)) {
720 glyphsetCache[i].count++;
722 glyphsetCache[prev_i].next = glyphsetCache[i].next;
723 glyphsetCache[i].next = mru;
726 TRACE("found font in cache %d\n", i);
731 TRACE("font not in cache\n");
735 static void FreeEntry(int entry)
739 for(format = 0; format < AA_MAXVALUE; format++) {
740 gsCacheEntryFormat * formatEntry;
742 if( !glyphsetCache[entry].format[format] )
745 formatEntry = glyphsetCache[entry].format[format];
747 if(formatEntry->glyphset) {
749 pXRenderFreeGlyphSet(gdi_display, formatEntry->glyphset);
751 formatEntry->glyphset = 0;
753 if(formatEntry->nrealized) {
754 HeapFree(GetProcessHeap(), 0, formatEntry->realized);
755 formatEntry->realized = 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;
957 char family[LF_FACESIZE * 4];
959 #if defined(__i386__) && defined(__GNUC__)
960 /* fontconfig generates floating point exceptions, mask them */
961 WORD cw, default_cw = 0x37f;
962 __asm__ __volatile__("fnstcw %0; fldcw %1" : "=m" (cw) : "m" (default_cw));
965 WideCharToMultiByte( CP_UTF8, 0, plfsz->lf.lfFaceName, -1, family, sizeof(family), NULL, NULL );
966 pattern = pFcPatternCreate();
967 pFcPatternAddString( pattern, FC_FAMILY, (FcChar8 *)family );
968 if (plfsz->lf.lfWeight != FW_DONTCARE)
971 switch (plfsz->lf.lfWeight)
973 case FW_THIN: weight = FC_WEIGHT_THIN; break;
974 case FW_EXTRALIGHT: weight = FC_WEIGHT_EXTRALIGHT; break;
975 case FW_LIGHT: weight = FC_WEIGHT_LIGHT; break;
976 case FW_NORMAL: weight = FC_WEIGHT_NORMAL; break;
977 case FW_MEDIUM: weight = FC_WEIGHT_MEDIUM; break;
978 case FW_SEMIBOLD: weight = FC_WEIGHT_SEMIBOLD; break;
979 case FW_BOLD: weight = FC_WEIGHT_BOLD; break;
980 case FW_EXTRABOLD: weight = FC_WEIGHT_EXTRABOLD; break;
981 case FW_HEAVY: weight = FC_WEIGHT_HEAVY; break;
982 default: weight = (plfsz->lf.lfWeight - 80) / 4; break;
984 pFcPatternAddInteger( pattern, FC_WEIGHT, weight );
986 pFcPatternAddInteger( pattern, FC_SLANT, plfsz->lf.lfItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
987 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
988 pFcDefaultSubstitute( pattern );
989 if ((match = pFcFontMatch( NULL, pattern, &result )))
994 if (pFcPatternGetBool( match, FC_ANTIALIAS, 0, &antialias ) != FcResultMatch)
996 if (pFcPatternGetInteger( match, FC_RGBA, 0, &rgba ) == FcResultMatch)
999 if (pFcPatternGetString( match, FC_FILE, 0, &file ) != FcResultMatch) file = NULL;
1001 TRACE( "fontconfig returned rgba %u antialias %u for font %s file %s\n",
1002 rgba, antialias, debugstr_w(plfsz->lf.lfFaceName), debugstr_a((char *)file) );
1006 case FC_RGBA_RGB: entry->aa_default = AA_RGB; break;
1007 case FC_RGBA_BGR: entry->aa_default = AA_BGR; break;
1008 case FC_RGBA_VRGB: entry->aa_default = AA_VRGB; break;
1009 case FC_RGBA_VBGR: entry->aa_default = AA_VBGR; break;
1010 case FC_RGBA_NONE: entry->aa_default = AA_Grey; break;
1013 if (!antialias) font_smoothing = FALSE;
1014 pFcPatternDestroy( match );
1016 pFcPatternDestroy( pattern );
1018 #if defined(__i386__) && defined(__GNUC__)
1019 __asm__ __volatile__("fnclex; fldcw %0" : : "m" (cw));
1022 #endif /* SONAME_LIBFONTCONFIG */
1024 /* now check Xft resources */
1027 BOOL antialias = TRUE;
1030 if ((value = XGetDefault( gdi_display, "Xft", "antialias" )))
1032 if (tolower(value[0]) == 'f' || tolower(value[0]) == 'n' ||
1033 value[0] == '0' || !strcasecmp( value, "off" ))
1036 if ((value = XGetDefault( gdi_display, "Xft", "rgba" )))
1038 TRACE( "Xft resource returned rgba '%s' antialias %u\n", value, antialias );
1039 if (!strcmp( value, "rgb" )) entry->aa_default = AA_RGB;
1040 else if (!strcmp( value, "bgr" )) entry->aa_default = AA_BGR;
1041 else if (!strcmp( value, "vrgb" )) entry->aa_default = AA_VRGB;
1042 else if (!strcmp( value, "vbgr" )) entry->aa_default = AA_VBGR;
1043 else if (!strcmp( value, "none" )) entry->aa_default = AA_Grey;
1045 wine_tsx11_unlock();
1046 if (!antialias) font_smoothing = FALSE;
1049 if (!font_smoothing) entry->aa_default = AA_None;
1051 /* we can't support subpixel without xrender */
1052 if (!X11DRV_XRender_Installed && entry->aa_default > AA_Grey) entry->aa_default = AA_Grey;
1055 entry->aa_default = AA_None;
1060 static void dec_ref_cache(int index)
1063 TRACE("dec'ing entry %d to %d\n", index, glyphsetCache[index].count - 1);
1064 assert(glyphsetCache[index].count > 0);
1065 glyphsetCache[index].count--;
1068 static void lfsz_calc_hash(LFANDSIZE *plfsz)
1070 DWORD hash = 0, *ptr, two_chars;
1074 hash ^= plfsz->devsize.cx;
1075 hash ^= plfsz->devsize.cy;
1076 for(i = 0, ptr = (DWORD*)&plfsz->xform; i < sizeof(XFORM)/sizeof(DWORD); i++, ptr++)
1078 for(i = 0, ptr = (DWORD*)&plfsz->lf; i < 7; i++, ptr++)
1080 for(i = 0, ptr = (DWORD*)plfsz->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1082 pwc = (WCHAR *)&two_chars;
1084 *pwc = toupperW(*pwc);
1086 *pwc = toupperW(*pwc);
1094 /***********************************************************************
1095 * X11DRV_XRender_Finalize
1097 void X11DRV_XRender_Finalize(void)
1101 EnterCriticalSection(&xrender_cs);
1102 for(i = mru; i >= 0; i = glyphsetCache[i].next)
1104 LeaveCriticalSection(&xrender_cs);
1105 DeleteCriticalSection(&xrender_cs);
1108 /**********************************************************************
1109 * xrenderdrv_SelectFont
1111 static HFONT xrenderdrv_SelectFont( PHYSDEV dev, HFONT hfont )
1113 struct xrender_physdev *physdev = get_xrender_dev( dev );
1114 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
1115 HFONT ret = next->funcs->pSelectFont( next, hfont );
1119 if (physdev->x11dev->has_gdi_font)
1123 GetObjectW( hfont, sizeof(lfsz.lf), &lfsz.lf );
1125 TRACE("h=%d w=%d weight=%d it=%d charset=%d name=%s\n",
1126 lfsz.lf.lfHeight, lfsz.lf.lfWidth, lfsz.lf.lfWeight,
1127 lfsz.lf.lfItalic, lfsz.lf.lfCharSet, debugstr_w(lfsz.lf.lfFaceName));
1128 lfsz.lf.lfWidth = abs( lfsz.lf.lfWidth );
1129 lfsz.devsize.cx = X11DRV_XWStoDS( dev->hdc, lfsz.lf.lfWidth );
1130 lfsz.devsize.cy = X11DRV_YWStoDS( dev->hdc, lfsz.lf.lfHeight );
1132 GetTransform( dev->hdc, 0x204, &lfsz.xform );
1133 TRACE("font transform %f %f %f %f\n", lfsz.xform.eM11, lfsz.xform.eM12,
1134 lfsz.xform.eM21, lfsz.xform.eM22);
1136 /* Not used fields, would break hashing */
1137 lfsz.xform.eDx = lfsz.xform.eDy = 0;
1139 lfsz_calc_hash(&lfsz);
1141 EnterCriticalSection(&xrender_cs);
1142 if (physdev->cache_index != -1)
1143 dec_ref_cache( physdev->cache_index );
1144 physdev->cache_index = GetCacheEntry( dev->hdc, &lfsz );
1145 LeaveCriticalSection(&xrender_cs);
1149 EnterCriticalSection( &xrender_cs );
1150 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1151 physdev->cache_index = -1;
1152 LeaveCriticalSection( &xrender_cs );
1157 static BOOL create_xrender_dc( PHYSDEV *pdev, enum wxr_format format )
1159 X11DRV_PDEVICE *x11dev = get_x11drv_dev( *pdev );
1160 struct xrender_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
1162 if (!physdev) return FALSE;
1163 physdev->x11dev = x11dev;
1164 physdev->cache_index = -1;
1165 physdev->format = format;
1166 physdev->pict_format = pict_formats[format];
1167 push_dc_driver( pdev, &physdev->dev, &xrender_funcs );
1171 /* store the color mask data in the bitmap info structure */
1172 static void set_color_info( XRenderPictFormat *format, BITMAPINFO *info )
1174 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1176 info->bmiHeader.biPlanes = 1;
1177 info->bmiHeader.biBitCount = pixmap_formats[format->depth]->bits_per_pixel;
1178 info->bmiHeader.biCompression = BI_RGB;
1179 info->bmiHeader.biClrUsed = 0;
1181 switch (info->bmiHeader.biBitCount)
1184 colors[0] = format->direct.redMask << format->direct.red;
1185 colors[1] = format->direct.greenMask << format->direct.green;
1186 colors[2] = format->direct.blueMask << format->direct.blue;
1187 info->bmiHeader.biCompression = BI_BITFIELDS;
1190 colors[0] = format->direct.redMask << format->direct.red;
1191 colors[1] = format->direct.greenMask << format->direct.green;
1192 colors[2] = format->direct.blueMask << format->direct.blue;
1193 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1194 info->bmiHeader.biCompression = BI_BITFIELDS;
1200 /**********************************************************************
1201 * xrenderdrv_CreateDC
1203 static BOOL xrenderdrv_CreateDC( PHYSDEV *pdev, LPCWSTR driver, LPCWSTR device,
1204 LPCWSTR output, const DEVMODEW* initData )
1206 return create_xrender_dc( pdev, default_format );
1209 /**********************************************************************
1210 * xrenderdrv_CreateCompatibleDC
1212 static BOOL xrenderdrv_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev )
1214 if (orig) /* chain to x11drv first */
1216 orig = GET_NEXT_PHYSDEV( orig, pCreateCompatibleDC );
1217 if (!orig->funcs->pCreateCompatibleDC( orig, pdev )) return FALSE;
1219 /* otherwise we have been called by x11drv */
1221 return create_xrender_dc( pdev, WXR_FORMAT_MONO );
1224 /**********************************************************************
1225 * xrenderdrv_DeleteDC
1227 static BOOL xrenderdrv_DeleteDC( PHYSDEV dev )
1229 struct xrender_physdev *physdev = get_xrender_dev( dev );
1231 free_xrender_picture( physdev );
1233 EnterCriticalSection( &xrender_cs );
1234 if (physdev->cache_index != -1) dec_ref_cache( physdev->cache_index );
1235 LeaveCriticalSection( &xrender_cs );
1237 HeapFree( GetProcessHeap(), 0, physdev );
1241 /**********************************************************************
1242 * xrenderdrv_ExtEscape
1244 static INT xrenderdrv_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data,
1245 INT out_count, LPVOID out_data )
1247 struct xrender_physdev *physdev = get_xrender_dev( dev );
1249 dev = GET_NEXT_PHYSDEV( dev, pExtEscape );
1251 if (escape == X11DRV_ESCAPE && in_data && in_count >= sizeof(enum x11drv_escape_codes))
1253 if (*(const enum x11drv_escape_codes *)in_data == X11DRV_SET_DRAWABLE)
1255 BOOL ret = dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1256 if (ret) free_xrender_picture( physdev ); /* pict format doesn't change, only drawable */
1260 return dev->funcs->pExtEscape( dev, escape, in_count, in_data, out_count, out_data );
1263 /****************************************************************************
1264 * xrenderdrv_CopyBitmap
1266 static BOOL xrenderdrv_CopyBitmap( HBITMAP src, HBITMAP dst )
1268 return X11DRV_CopyBitmap( src, dst );
1271 /****************************************************************************
1272 * xrenderdrv_CreateBitmap
1274 static BOOL xrenderdrv_CreateBitmap( PHYSDEV dev, HBITMAP hbitmap )
1276 enum wxr_format format;
1279 if (!GetObjectW( hbitmap, sizeof(bitmap), &bitmap )) return FALSE;
1281 if (bitmap.bmPlanes != 1) return FALSE;
1282 format = get_bitmap_format( bitmap.bmBitsPixel );
1284 if (pict_formats[format])
1285 return X11DRV_create_phys_bitmap( hbitmap, &bitmap, pict_formats[format]->depth,
1286 TRUE, &wxr_color_shifts[format] );
1288 dev = GET_NEXT_PHYSDEV( dev, pCreateBitmap );
1289 return dev->funcs->pCreateBitmap( dev, hbitmap );
1292 /****************************************************************************
1293 * xrenderdrv_DeleteBitmap
1295 static BOOL xrenderdrv_DeleteBitmap( HBITMAP hbitmap )
1297 return X11DRV_DeleteBitmap( hbitmap );
1300 /***********************************************************************
1301 * xrenderdrv_SelectBitmap
1303 static HBITMAP xrenderdrv_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
1306 struct xrender_physdev *physdev = get_xrender_dev( dev );
1308 dev = GET_NEXT_PHYSDEV( dev, pSelectBitmap );
1309 ret = dev->funcs->pSelectBitmap( dev, hbitmap );
1312 free_xrender_picture( physdev );
1313 physdev->format = get_xrender_format_from_color_shifts( physdev->x11dev->depth,
1314 physdev->x11dev->color_shifts );
1315 physdev->pict_format = pict_formats[physdev->format];
1320 /***********************************************************************
1321 * xrenderdrv_GetImage
1323 static DWORD xrenderdrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1324 struct gdi_image_bits *bits, struct bitblt_coords *src )
1326 if (hbitmap) return X11DRV_GetImage( dev, hbitmap, info, bits, src );
1327 dev = GET_NEXT_PHYSDEV( dev, pGetImage );
1328 return dev->funcs->pGetImage( dev, hbitmap, info, bits, src );
1331 /***********************************************************************
1332 * xrenderdrv_SetDeviceClipping
1334 static void xrenderdrv_SetDeviceClipping( PHYSDEV dev, HRGN vis_rgn, HRGN clip_rgn )
1336 struct xrender_physdev *physdev = get_xrender_dev( dev );
1338 physdev->update_clip = TRUE;
1340 dev = GET_NEXT_PHYSDEV( dev, pSetDeviceClipping );
1341 dev->funcs->pSetDeviceClipping( dev, vis_rgn, clip_rgn );
1345 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
1347 XRenderPictFormat *pict_format;
1349 const DWORD *bitfields;
1350 static const DWORD bitfields_32[3] = {0xff0000, 0x00ff00, 0x0000ff};
1351 static const DWORD bitfields_16[3] = {0x7c00, 0x03e0, 0x001f};
1354 /* When XRender is not around we can only use the screen_depth and when needed we perform depth conversion
1355 * in software. Further we also return the screen depth for paletted formats or TrueColor formats with a low
1356 * number of bits because XRender can't handle paletted formats and 8-bit TrueColor does not exist for XRender. */
1357 if (!X11DRV_XRender_Installed || bits_pixel <= 8)
1360 if(dib->dsBmih.biCompression == BI_BITFIELDS)
1361 bitfields = dib->dsBitfields;
1362 else if(bits_pixel == 24 || bits_pixel == 32)
1363 bitfields = bitfields_32;
1365 bitfields = bitfields_16;
1367 X11DRV_PALETTE_ComputeColorShifts(&shifts, bitfields[0], bitfields[1], bitfields[2]);
1368 pict_format = pict_formats[get_xrender_format_from_color_shifts(dib->dsBm.bmBitsPixel, &shifts)];
1370 /* Common formats should be in our picture format table. */
1373 TRACE("Unhandled dibsection format bpp=%d, redMask=%x, greenMask=%x, blueMask=%x\n",
1374 dib->dsBm.bmBitsPixel, bitfields[0], bitfields[1], bitfields[2]);
1378 physBitmap->depth = pict_format->depth;
1379 physBitmap->trueColor = TRUE;
1380 physBitmap->color_shifts = shifts;
1384 /************************************************************************
1387 * Helper to ExtTextOut. Must be called inside xrender_cs
1389 static void UploadGlyph(struct xrender_physdev *physDev, int glyph, AA_Type format)
1391 unsigned int buflen;
1396 gsCacheEntry *entry = glyphsetCache + physDev->cache_index;
1397 gsCacheEntryFormat *formatEntry;
1398 UINT ggo_format = GGO_GLYPH_INDEX;
1399 enum wxr_format wxr_format;
1400 static const char zero[4];
1401 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
1405 ggo_format |= WINE_GGO_GRAY16_BITMAP;
1408 ggo_format |= WINE_GGO_HRGB_BITMAP;
1411 ggo_format |= WINE_GGO_HBGR_BITMAP;
1414 ggo_format |= WINE_GGO_VRGB_BITMAP;
1417 ggo_format |= WINE_GGO_VBGR_BITMAP;
1421 ERR("aa = %d - not implemented\n", format);
1423 ggo_format |= GGO_BITMAP;
1427 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1428 if(buflen == GDI_ERROR) {
1429 if(format != AA_None) {
1431 entry->aa_default = AA_None;
1432 ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP;
1433 buflen = GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, 0, NULL, &identity);
1435 if(buflen == GDI_ERROR) {
1436 WARN("GetGlyphOutlineW failed using default glyph\n");
1437 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0, ggo_format, &gm, 0, NULL, &identity);
1438 if(buflen == GDI_ERROR) {
1439 WARN("GetGlyphOutlineW failed for default glyph trying for space\n");
1440 buflen = GetGlyphOutlineW(physDev->dev.hdc, 0x20, ggo_format, &gm, 0, NULL, &identity);
1441 if(buflen == GDI_ERROR) {
1442 ERR("GetGlyphOutlineW for all attempts unable to upload a glyph\n");
1447 TRACE("Turning off antialiasing for this monochrome font\n");
1450 /* If there is nothing for the current type, we create the entry. */
1451 if( !entry->format[format] ) {
1452 entry->format[format] = HeapAlloc(GetProcessHeap(),
1454 sizeof(gsCacheEntryFormat));
1456 formatEntry = entry->format[format];
1458 if(formatEntry->nrealized <= glyph) {
1459 formatEntry->nrealized = (glyph / 128 + 1) * 128;
1461 if (formatEntry->realized)
1462 formatEntry->realized = HeapReAlloc(GetProcessHeap(),
1464 formatEntry->realized,
1465 formatEntry->nrealized * sizeof(BOOL));
1467 formatEntry->realized = HeapAlloc(GetProcessHeap(),
1469 formatEntry->nrealized * sizeof(BOOL));
1471 if (formatEntry->gis)
1472 formatEntry->gis = HeapReAlloc(GetProcessHeap(),
1475 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1477 formatEntry->gis = HeapAlloc(GetProcessHeap(),
1479 formatEntry->nrealized * sizeof(formatEntry->gis[0]));
1483 if(formatEntry->glyphset == 0) {
1486 wxr_format = WXR_FORMAT_GRAY;
1493 wxr_format = WXR_FORMAT_A8R8G8B8;
1497 ERR("aa = %d - not implemented\n", format);
1499 wxr_format = WXR_FORMAT_MONO;
1504 formatEntry->font_format = pict_formats[wxr_format];
1505 formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format);
1506 wine_tsx11_unlock();
1510 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen);
1511 GetGlyphOutlineW(physDev->dev.hdc, glyph, ggo_format, &gm, buflen, buf, &identity);
1512 formatEntry->realized[glyph] = TRUE;
1514 TRACE("buflen = %d. Got metrics: %dx%d adv=%d,%d origin=%d,%d\n",
1516 gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY,
1517 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1519 gi.width = gm.gmBlackBoxX;
1520 gi.height = gm.gmBlackBoxY;
1521 gi.x = -gm.gmptGlyphOrigin.x;
1522 gi.y = gm.gmptGlyphOrigin.y;
1523 gi.xOff = gm.gmCellIncX;
1524 gi.yOff = gm.gmCellIncY;
1526 if(TRACE_ON(xrender)) {
1529 unsigned char *line;
1531 if(format == AA_None) {
1532 pitch = ((gi.width + 31) / 32) * 4;
1533 for(i = 0; i < gi.height; i++) {
1534 line = (unsigned char*) buf + i * pitch;
1536 for(j = 0; j < pitch * 8; j++) {
1537 strcat(output, (line[j / 8] & (1 << (7 - (j % 8)))) ? "#" : " ");
1539 TRACE("%s\n", output);
1542 static const char blks[] = " .:;!o*#";
1546 pitch = ((gi.width + 3) / 4) * 4;
1547 for(i = 0; i < gi.height; i++) {
1548 line = (unsigned char*) buf + i * pitch;
1550 for(j = 0; j < pitch; j++) {
1551 str[0] = blks[line[j] >> 5];
1552 strcat(output, str);
1554 TRACE("%s\n", output);
1560 if(formatEntry->glyphset) {
1561 if(format == AA_None && BitmapBitOrder(gdi_display) != MSBFirst) {
1562 unsigned char *byte = (unsigned char*) buf, c;
1568 /* magic to flip bit order */
1569 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1570 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1571 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1576 else if ( format != AA_Grey &&
1577 ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER)
1579 unsigned int i, *data = (unsigned int *)buf;
1580 for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data);
1585 XRenderCompositeText seems to ignore 0x0 glyphs when
1586 AA_None, which means we lose the advance width of glyphs
1587 like the space. We'll pretend that such glyphs are 1x1
1592 gi.width = gi.height = 1;
1595 pXRenderAddGlyphs(gdi_display, formatEntry->glyphset, &gid, &gi, 1,
1596 buflen ? buf : zero, buflen ? buflen : sizeof(zero));
1597 wine_tsx11_unlock();
1598 HeapFree(GetProcessHeap(), 0, buf);
1601 formatEntry->gis[glyph] = gi;
1604 /*************************************************************
1607 * Returns an appropriate Picture for tiling the text colour.
1608 * Call and use result within the xrender_cs
1610 static Picture get_tile_pict( enum wxr_format wxr_format, const XRenderColor *color)
1616 XRenderColor current_color;
1617 } tiles[WXR_NB_FORMATS], *tile;
1619 tile = &tiles[wxr_format];
1623 XRenderPictureAttributes pa;
1624 XRenderPictFormat *pict_format = pict_formats[wxr_format];
1627 tile->xpm = XCreatePixmap(gdi_display, root_window, 1, 1, pict_format->depth);
1629 pa.repeat = RepeatNormal;
1630 tile->pict = pXRenderCreatePicture(gdi_display, tile->xpm, pict_format, CPRepeat, &pa);
1631 wine_tsx11_unlock();
1633 /* init current_color to something different from text_pixel */
1634 tile->current_color = *color;
1635 tile->current_color.red ^= 0xffff;
1637 if (wxr_format == WXR_FORMAT_MONO)
1639 /* for a 1bpp bitmap we always need a 1 in the tile */
1641 col.red = col.green = col.blue = 0;
1644 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, &col, 0, 0, 1, 1);
1645 wine_tsx11_unlock();
1649 if (memcmp( color, &tile->current_color, sizeof(*color) ) && wxr_format != WXR_FORMAT_MONO)
1652 pXRenderFillRectangle(gdi_display, PictOpSrc, tile->pict, color, 0, 0, 1, 1);
1653 wine_tsx11_unlock();
1654 tile->current_color = *color;
1659 /*************************************************************
1662 * Returns an appropriate Picture for masking with the specified alpha.
1663 * Call and use result within the xrender_cs
1665 static Picture get_mask_pict( int alpha )
1667 static Pixmap pixmap;
1668 static Picture pict;
1669 static int current_alpha;
1671 if (alpha == 0xffff) return 0; /* don't need a mask for alpha==1.0 */
1675 XRenderPictureAttributes pa;
1678 pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 32 );
1679 pa.repeat = RepeatNormal;
1680 pict = pXRenderCreatePicture( gdi_display, pixmap,
1681 pict_formats[WXR_FORMAT_A8R8G8B8], CPRepeat, &pa );
1682 wine_tsx11_unlock();
1686 if (alpha != current_alpha)
1689 col.red = col.green = col.blue = 0;
1690 col.alpha = current_alpha = alpha;
1692 pXRenderFillRectangle( gdi_display, PictOpSrc, pict, &col, 0, 0, 1, 1 );
1693 wine_tsx11_unlock();
1698 /***********************************************************************
1699 * xrenderdrv_ExtTextOut
1701 static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
1702 const RECT *lprect, LPCWSTR wstr, UINT count, const INT *lpDx )
1704 struct xrender_physdev *physdev = get_xrender_dev( dev );
1706 gsCacheEntry *entry;
1707 gsCacheEntryFormat *formatEntry;
1708 int textPixel, backgroundPixel;
1709 AA_Type aa_type = AA_None;
1711 Picture pict, tile_pict = 0;
1713 POINT offset, desired, current;
1714 int render_op = PictOpOver;
1717 if (!X11DRV_XRender_Installed || !physdev->x11dev->has_gdi_font)
1719 dev = GET_NEXT_PHYSDEV( dev, pExtTextOut );
1720 return dev->funcs->pExtTextOut( dev, x, y, flags, lprect, wstr, count, lpDx );
1723 xgcval.function = GXcopy;
1724 xgcval.background = physdev->x11dev->backgroundPixel;
1725 xgcval.fill_style = FillSolid;
1727 XChangeGC( gdi_display, physdev->x11dev->gc, GCFunction | GCBackground | GCFillStyle, &xgcval );
1728 wine_tsx11_unlock();
1730 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
1732 if(physdev->x11dev->depth == 1) {
1733 if((physdev->x11dev->textPixel & 0xffffff) == 0) {
1735 backgroundPixel = 1;
1738 backgroundPixel = 0;
1741 textPixel = physdev->x11dev->textPixel;
1742 backgroundPixel = physdev->x11dev->backgroundPixel;
1745 if(flags & ETO_OPAQUE)
1748 XSetForeground( gdi_display, physdev->x11dev->gc, backgroundPixel );
1749 XFillRectangle( gdi_display, physdev->x11dev->drawable, physdev->x11dev->gc,
1750 physdev->x11dev->dc_rect.left + lprect->left, physdev->x11dev->dc_rect.top + lprect->top,
1751 lprect->right - lprect->left, lprect->bottom - lprect->top );
1752 wine_tsx11_unlock();
1757 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1761 EnterCriticalSection(&xrender_cs);
1763 entry = glyphsetCache + physdev->cache_index;
1764 aa_type = entry->aa_default;
1765 formatEntry = entry->format[aa_type];
1767 for(idx = 0; idx < count; idx++) {
1768 if( !formatEntry ) {
1769 UploadGlyph(physdev, wstr[idx], aa_type);
1770 /* re-evaluate antialias since aa_default may have changed */
1771 aa_type = entry->aa_default;
1772 formatEntry = entry->format[aa_type];
1773 } else if( wstr[idx] >= formatEntry->nrealized || formatEntry->realized[wstr[idx]] == FALSE) {
1774 UploadGlyph(physdev, wstr[idx], aa_type);
1779 WARN("could not upload requested glyphs\n");
1780 LeaveCriticalSection(&xrender_cs);
1781 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1785 TRACE("Writing %s at %d,%d\n", debugstr_wn(wstr,count),
1786 physdev->x11dev->dc_rect.left + x, physdev->x11dev->dc_rect.top + y);
1788 elts = HeapAlloc(GetProcessHeap(), 0, sizeof(XGlyphElt16) * count);
1789 pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL );
1791 /* There's a bug in XRenderCompositeText that ignores the xDst and yDst parameters.
1792 So we pass zeros to the function and move to our starting position using the first
1793 element of the elts array. */
1795 desired.x = physdev->x11dev->dc_rect.left + x;
1796 desired.y = physdev->x11dev->dc_rect.top + y;
1797 offset.x = offset.y = 0;
1798 current.x = current.y = 0;
1800 get_xrender_color(physdev->pict_format, physdev->x11dev->textPixel, &col);
1801 tile_pict = get_tile_pict(physdev->format, &col);
1803 /* FIXME the mapping of Text/BkColor onto 1 or 0 needs investigation.
1805 if((physdev->format == WXR_FORMAT_MONO) && (textPixel == 0))
1806 render_op = PictOpOutReverse; /* This gives us 'black' text */
1808 for(idx = 0; idx < count; idx++)
1810 elts[idx].glyphset = formatEntry->glyphset;
1811 elts[idx].chars = wstr + idx;
1812 elts[idx].nchars = 1;
1813 elts[idx].xOff = desired.x - current.x;
1814 elts[idx].yOff = desired.y - current.y;
1816 current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff);
1817 current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff);
1821 desired.x += formatEntry->gis[wstr[idx]].xOff;
1822 desired.y += formatEntry->gis[wstr[idx]].yOff;
1828 offset.x += lpDx[idx * 2];
1829 offset.y += lpDx[idx * 2 + 1];
1832 offset.x += lpDx[idx];
1833 desired.x = physdev->x11dev->dc_rect.left + x + offset.x;
1834 desired.y = physdev->x11dev->dc_rect.top + y + offset.y;
1839 /* Make sure we don't have any transforms set from a previous call */
1840 set_xrender_transformation(pict, 1, 1, 0, 0);
1841 pXRenderCompositeText16(gdi_display, render_op,
1844 formatEntry->font_format,
1845 0, 0, 0, 0, elts, count);
1846 wine_tsx11_unlock();
1847 HeapFree(GetProcessHeap(), 0, elts);
1849 LeaveCriticalSection(&xrender_cs);
1850 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
1854 /* multiply the alpha channel of a picture */
1855 static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha,
1856 int x, int y, int width, int height )
1858 XRenderPictureAttributes pa;
1859 Pixmap src_pixmap, mask_pixmap;
1860 Picture src_pict, mask_pict;
1864 src_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1865 mask_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, format->depth );
1866 pa.repeat = RepeatNormal;
1867 src_pict = pXRenderCreatePicture( gdi_display, src_pixmap, format, CPRepeat, &pa );
1868 pa.component_alpha = True;
1869 mask_pict = pXRenderCreatePicture( gdi_display, mask_pixmap, format, CPRepeat|CPComponentAlpha, &pa );
1870 color.red = color.green = color.blue = color.alpha = 0xffff;
1871 pXRenderFillRectangle( gdi_display, PictOpSrc, src_pict, &color, 0, 0, 1, 1 );
1872 color.alpha = alpha;
1873 pXRenderFillRectangle( gdi_display, PictOpSrc, mask_pict, &color, 0, 0, 1, 1 );
1874 pXRenderComposite( gdi_display, PictOpInReverse, src_pict, mask_pict, pict,
1875 0, 0, 0, 0, x, y, width, height );
1876 pXRenderFreePicture( gdi_display, src_pict );
1877 pXRenderFreePicture( gdi_display, mask_pict );
1878 XFreePixmap( gdi_display, src_pixmap );
1879 XFreePixmap( gdi_display, mask_pixmap );
1880 wine_tsx11_unlock();
1883 /* Helper function for (stretched) blitting using xrender */
1884 static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict,
1885 int x_src, int y_src, int x_dst, int y_dst,
1886 double xscale, double yscale, int width, int height )
1888 int x_offset, y_offset;
1890 /* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
1891 * This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
1892 * In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
1894 if(xscale != 1.0 || yscale != 1.0)
1896 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1897 * in the wrong quadrant of the x-y plane.
1899 x_offset = (xscale < 0) ? -width : 0;
1900 y_offset = (yscale < 0) ? -height : 0;
1901 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1907 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1909 pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict,
1910 x_offset, y_offset, 0, 0, x_dst, y_dst, width, height );
1911 wine_tsx11_unlock();
1914 /* Helper function for (stretched) mono->color blitting using xrender */
1915 static void xrender_mono_blit( Picture src_pict, Picture dst_pict,
1916 enum wxr_format dst_format, XRenderColor *fg, XRenderColor *bg,
1917 int x_src, int y_src, int x_dst, int y_dst,
1918 double xscale, double yscale, int width, int height )
1921 int x_offset, y_offset;
1924 /* When doing a mono->color blit, the source data is used as mask, and the source picture
1925 * contains a 1x1 picture for tiling. The source data effectively acts as an alpha channel to
1928 EnterCriticalSection( &xrender_cs );
1930 color.alpha = 0xffff; /* tile pict needs 100% alpha */
1931 tile_pict = get_tile_pict( dst_format, &color );
1934 pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, fg, x_dst, y_dst, width, height );
1936 if (xscale != 1.0 || yscale != 1.0)
1938 /* In case of mirroring we need a source x- and y-offset because without the pixels will be
1939 * in the wrong quadrant of the x-y plane.
1941 x_offset = (xscale < 0) ? -width : 0;
1942 y_offset = (yscale < 0) ? -height : 0;
1943 set_xrender_transformation(src_pict, xscale, yscale, x_src, y_src);
1949 set_xrender_transformation(src_pict, 1, 1, 0, 0);
1951 pXRenderComposite(gdi_display, PictOpOver, tile_pict, src_pict, dst_pict,
1952 0, 0, x_offset, y_offset, x_dst, y_dst, width, height );
1953 wine_tsx11_unlock();
1954 LeaveCriticalSection( &xrender_cs );
1956 /* force the alpha channel for background pixels, it has been set to 100% by the tile */
1957 if (bg->alpha != 0xffff && (dst_format == WXR_FORMAT_A8R8G8B8 || dst_format == WXR_FORMAT_B8G8R8A8))
1958 multiply_alpha( dst_pict, pict_formats[dst_format], bg->alpha, x_dst, y_dst, width, height );
1961 /* create a pixmap and render picture for an image */
1962 static DWORD create_image_pixmap( BITMAPINFO *info, const struct gdi_image_bits *bits,
1963 struct bitblt_coords *src, enum wxr_format format,
1964 Pixmap *pixmap, Picture *pict, BOOL *use_repeat )
1967 int width = src->visrect.right - src->visrect.left;
1968 int height = src->visrect.bottom - src->visrect.top;
1969 int depth = pict_formats[format]->depth;
1970 struct gdi_image_bits dst_bits;
1971 XRenderPictureAttributes pa;
1975 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1976 info->bmiHeader.biWidth, height, 32, 0 );
1977 wine_tsx11_unlock();
1978 if (!image) return ERROR_OUTOFMEMORY;
1980 ret = copy_image_bits( info, (format == WXR_FORMAT_R8G8B8), image, bits, &dst_bits, src, NULL, ~0u );
1981 if (ret) return ret;
1983 image->data = dst_bits.ptr;
1984 /* hack: make sure the bits are readable if we are reading from a DIB section */
1985 /* to be removed once we get rid of DIB access protections */
1986 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, image->height * image->bytes_per_line );
1988 *use_repeat = (width == 1 && height == 1);
1989 pa.repeat = *use_repeat ? RepeatNormal : RepeatNone;
1992 *pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1993 XPutImage( gdi_display, *pixmap, get_bitmap_gc( depth ), image,
1994 src->visrect.left, 0, 0, 0, width, height );
1995 *pict = pXRenderCreatePicture( gdi_display, *pixmap, pict_formats[format], CPRepeat, &pa );
1996 wine_tsx11_unlock();
1998 /* make coordinates relative to the pixmap */
1999 src->x -= src->visrect.left;
2000 src->y -= src->visrect.top;
2001 OffsetRect( &src->visrect, -src->visrect.left, -src->visrect.top );
2005 XDestroyImage( image );
2006 wine_tsx11_unlock();
2007 if (dst_bits.free) dst_bits.free( &dst_bits );
2011 static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xrender_physdev *physdev_dst,
2012 Drawable drawable, const struct bitblt_coords *src,
2013 const struct bitblt_coords *dst )
2015 int width = abs( dst->width );
2016 int height = abs( dst->height );
2017 int x_src = physdev_src->x11dev->dc_rect.left + src->x;
2018 int y_src = physdev_src->x11dev->dc_rect.top + src->y;
2020 Picture src_pict = 0, dst_pict, mask_pict = 0;
2022 double xscale, yscale;
2024 use_repeat = use_source_repeat( physdev_src );
2027 xscale = src->width / (double)dst->width;
2028 yscale = src->height / (double)dst->height;
2030 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2032 if (drawable) /* using an intermediate pixmap */
2034 XRenderPictureAttributes pa;
2038 pa.repeat = RepeatNone;
2040 dst_pict = pXRenderCreatePicture( gdi_display, drawable, physdev_dst->pict_format, CPRepeat, &pa );
2041 wine_tsx11_unlock();
2045 x_dst = physdev_dst->x11dev->dc_rect.left + dst->x;
2046 y_dst = physdev_dst->x11dev->dc_rect.top + dst->y;
2047 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2050 if (src->width < 0) x_src += src->width + 1;
2051 if (src->height < 0) y_src += src->height + 1;
2052 if (dst->width < 0) x_dst += dst->width + 1;
2053 if (dst->height < 0) y_dst += dst->height + 1;
2055 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2058 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2060 XRenderColor fg, bg;
2062 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->textPixel, &fg );
2063 get_xrender_color( physdev_dst->pict_format, physdev_dst->x11dev->backgroundPixel, &bg );
2064 fg.alpha = bg.alpha = 0;
2066 xrender_mono_blit( src_pict, dst_pict, physdev_dst->format, &fg, &bg,
2067 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2069 else /* color -> color (can be at different depths) or mono -> mono */
2071 if (physdev_dst->x11dev->depth == 32 && physdev_src->x11dev->depth < 32)
2072 mask_pict = get_no_alpha_mask();
2074 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict,
2075 x_src, y_src, x_dst, y_dst, xscale, yscale, width, height );
2081 pXRenderFreePicture( gdi_display, dst_pict );
2082 wine_tsx11_unlock();
2087 static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask_pict, HRGN clip,
2088 XRenderPictFormat *dst_format, struct xrender_physdev *physdev,
2089 Drawable drawable, struct bitblt_coords *src,
2090 struct bitblt_coords *dst, BOOL use_repeat )
2092 int x_src, y_src, x_dst, y_dst;
2094 XRenderPictureAttributes pa;
2095 double xscale, yscale;
2097 if (drawable) /* using an intermediate pixmap */
2099 RGNDATA *clip_data = NULL;
2101 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
2104 pa.repeat = RepeatNone;
2106 dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, CPRepeat, &pa );
2108 pXRenderSetPictureClipRectangles( gdi_display, dst_pict, 0, 0,
2109 (XRectangle *)clip_data->Buffer, clip_data->rdh.nCount );
2110 wine_tsx11_unlock();
2111 HeapFree( GetProcessHeap(), 0, clip_data );
2115 x_dst = physdev->x11dev->dc_rect.left + dst->x;
2116 y_dst = physdev->x11dev->dc_rect.top + dst->y;
2117 dst_pict = get_xrender_picture( physdev, clip, &dst->visrect );
2122 xscale = src->width / (double)dst->width;
2123 yscale = src->height / (double)dst->height;
2125 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2129 if (src->width < 0) x_src += src->width + 1;
2130 if (src->height < 0) y_src += src->height + 1;
2131 if (dst->width < 0) x_dst += dst->width + 1;
2132 if (dst->height < 0) y_dst += dst->height + 1;
2134 xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, x_dst, y_dst,
2135 xscale, yscale, abs( dst->width ), abs( dst->height ));
2140 pXRenderFreePicture( gdi_display, dst_pict );
2141 wine_tsx11_unlock();
2146 /***********************************************************************
2147 * xrenderdrv_StretchBlt
2149 static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
2150 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
2152 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2153 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2154 BOOL stretch = (src->width != dst->width) || (src->height != dst->height);
2156 if (src_dev->funcs != dst_dev->funcs)
2158 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
2159 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
2162 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2164 /* XRender is of no use for color -> mono */
2165 if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO)
2166 goto x11drv_fallback;
2168 /* if not stretching, we only need to handle format conversion */
2169 if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback;
2171 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2172 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2178 struct bitblt_coords tmp;
2180 /* make coordinates relative to tmp pixmap */
2182 tmp.x -= tmp.visrect.left;
2183 tmp.y -= tmp.visrect.top;
2184 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2187 tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL );
2188 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
2189 XSetGraphicsExposures( gdi_display, tmpGC, False );
2190 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2191 tmp.visrect.bottom - tmp.visrect.top, physdev_dst->x11dev->depth );
2192 wine_tsx11_unlock();
2194 xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp );
2195 execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop );
2198 XFreePixmap( gdi_display, tmp_pixmap );
2199 XFreeGC( gdi_display, tmpGC );
2200 wine_tsx11_unlock();
2202 else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst );
2204 if (physdev_dst != physdev_src) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2205 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2209 return X11DRV_StretchBlt( &physdev_dst->x11dev->dev, dst, &physdev_src->x11dev->dev, src, rop );
2213 /***********************************************************************
2214 * xrenderdrv_PutImage
2216 static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
2217 const struct gdi_image_bits *bits, struct bitblt_coords *src,
2218 struct bitblt_coords *dst, DWORD rop )
2220 struct xrender_physdev *physdev;
2221 X_PHYSBITMAP *bitmap;
2225 enum wxr_format src_format, dst_format;
2226 XRenderPictFormat *pict_format;
2228 Picture src_pict, mask_pict = 0;
2231 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2235 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2237 dst_format = get_xrender_format_from_color_shifts( bitmap->depth, &bitmap->color_shifts );
2241 physdev = get_xrender_dev( dev );
2243 dst_format = physdev->format;
2246 src_format = get_xrender_format_from_bitmapinfo( info );
2247 if (!(pict_format = pict_formats[src_format])) goto update_format;
2249 /* make sure we can create an image with the same bpp */
2250 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2253 /* mono <-> color conversions not supported */
2254 if ((src_format != dst_format) && (src_format == WXR_FORMAT_MONO || dst_format == WXR_FORMAT_MONO))
2255 goto x11drv_fallback;
2257 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2259 if (!has_alpha( src_format ) && has_alpha( dst_format )) mask_pict = get_no_alpha_mask();
2261 ret = create_image_pixmap( info, bits, src, src_format, &src_pixmap, &src_pict, &use_repeat );
2264 struct bitblt_coords tmp;
2268 HRGN rgn = CreateRectRgnIndirect( &dst->visrect );
2269 if (clip) CombineRgn( rgn, rgn, clip, RGN_AND );
2271 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2273 xrender_put_image( src_pixmap, src_pict, mask_pict, rgn,
2274 pict_formats[dst_format], NULL, bitmap->pixmap, src, dst, use_repeat );
2276 X11DRV_DIB_Unlock( bitmap, TRUE );
2277 DeleteObject( rgn );
2281 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2285 RGNDATA *clip_data = NULL;
2287 /* make coordinates relative to tmp pixmap */
2289 tmp.x -= tmp.visrect.left;
2290 tmp.y -= tmp.visrect.top;
2291 OffsetRect( &tmp.visrect, -tmp.visrect.left, -tmp.visrect.top );
2293 if (clip) clip_data = add_extra_clipping_region( physdev->x11dev, clip );
2296 gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL );
2297 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
2298 XSetGraphicsExposures( gdi_display, gc, False );
2299 tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left,
2300 tmp.visrect.bottom - tmp.visrect.top, physdev->x11dev->depth );
2301 wine_tsx11_unlock();
2303 xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format,
2304 NULL, tmp_pixmap, src, &tmp, use_repeat );
2305 execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop );
2308 XFreePixmap( gdi_display, tmp_pixmap );
2309 XFreeGC( gdi_display, gc );
2310 wine_tsx11_unlock();
2312 restore_clipping_region( physdev->x11dev, clip_data );
2314 else xrender_put_image( src_pixmap, src_pict, mask_pict, clip,
2315 physdev->pict_format, physdev, 0, src, dst, use_repeat );
2317 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2321 pXRenderFreePicture( gdi_display, src_pict );
2322 XFreePixmap( gdi_display, src_pixmap );
2323 wine_tsx11_unlock();
2328 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2329 set_color_info( pict_formats[dst_format], info );
2330 return ERROR_BAD_FORMAT;
2333 if (hbitmap) return X11DRV_PutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2334 dev = GET_NEXT_PHYSDEV( dev, pPutImage );
2335 return dev->funcs->pPutImage( dev, hbitmap, clip, info, bits, src, dst, rop );
2339 /***********************************************************************
2340 * xrenderdrv_BlendImage
2342 static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
2343 struct bitblt_coords *src, struct bitblt_coords *dst,
2344 BLENDFUNCTION func )
2346 struct xrender_physdev *physdev = get_xrender_dev( dev );
2348 enum wxr_format format;
2349 XRenderPictFormat *pict_format;
2350 Picture dst_pict, src_pict, mask_pict;
2354 if (!X11DRV_XRender_Installed)
2356 dev = GET_NEXT_PHYSDEV( dev, pBlendImage );
2357 return dev->funcs->pBlendImage( dev, info, bits, src, dst, func );
2360 format = get_xrender_format_from_bitmapinfo( info );
2361 if (!(func.AlphaFormat & AC_SRC_ALPHA))
2362 format = get_format_without_alpha( format );
2363 else if (format != WXR_FORMAT_A8R8G8B8)
2364 return ERROR_INVALID_PARAMETER;
2366 if (!(pict_format = pict_formats[format])) goto update_format;
2368 /* make sure we can create an image with the same bpp */
2369 if (info->bmiHeader.biBitCount != pixmap_formats[pict_format->depth]->bits_per_pixel)
2372 if (format == WXR_FORMAT_MONO && physdev->format != WXR_FORMAT_MONO)
2375 if (!bits) return ERROR_SUCCESS; /* just querying the format */
2377 ret = create_image_pixmap( info, bits, src, format, &src_pixmap, &src_pict, &use_repeat );
2380 double xscale, yscale;
2382 X11DRV_LockDIBSection( physdev->x11dev, DIB_Status_GdiMod );
2386 xscale = src->width / (double)dst->width;
2387 yscale = src->height / (double)dst->height;
2389 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2391 dst_pict = get_xrender_picture( physdev, 0, &dst->visrect );
2393 EnterCriticalSection( &xrender_cs );
2394 mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 );
2396 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y,
2397 physdev->x11dev->dc_rect.left + dst->x,
2398 physdev->x11dev->dc_rect.top + dst->y,
2399 xscale, yscale, dst->width, dst->height );
2402 pXRenderFreePicture( gdi_display, src_pict );
2403 XFreePixmap( gdi_display, src_pixmap );
2404 wine_tsx11_unlock();
2406 LeaveCriticalSection( &xrender_cs );
2408 X11DRV_UnlockDIBSection( physdev->x11dev, TRUE );
2413 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
2414 set_color_info( physdev->pict_format, info );
2415 return ERROR_BAD_FORMAT;
2419 /***********************************************************************
2420 * xrenderdrv_AlphaBlend
2422 static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
2423 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
2425 struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev );
2426 struct xrender_physdev *physdev_src = get_xrender_dev( src_dev );
2427 Picture dst_pict, src_pict = 0, mask_pict = 0, tmp_pict = 0;
2428 XRenderPictureAttributes pa;
2429 Pixmap tmp_pixmap = 0;
2430 double xscale, yscale;
2433 if (!X11DRV_XRender_Installed || src_dev->funcs != dst_dev->funcs)
2435 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pAlphaBlend );
2436 return dst_dev->funcs->pAlphaBlend( dst_dev, dst, src_dev, src, blendfn );
2439 if ((blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->format != WXR_FORMAT_A8R8G8B8)
2441 SetLastError( ERROR_INVALID_PARAMETER );
2445 X11DRV_LockDIBSection( physdev_dst->x11dev, DIB_Status_GdiMod );
2446 if (physdev_dst != physdev_src) X11DRV_LockDIBSection( physdev_src->x11dev, DIB_Status_GdiMod );
2448 dst_pict = get_xrender_picture( physdev_dst, 0, &dst->visrect );
2450 use_repeat = use_source_repeat( physdev_src );
2453 xscale = src->width / (double)dst->width;
2454 yscale = src->height / (double)dst->height;
2456 else xscale = yscale = 1; /* no scaling needed with a repeating source */
2458 src_pict = get_xrender_picture_source( physdev_src, use_repeat );
2460 if (physdev_src->format == WXR_FORMAT_MONO && physdev_dst->format != WXR_FORMAT_MONO)
2462 /* mono -> color blending needs an intermediate color pixmap */
2463 XRenderColor fg, bg;
2464 int width = src->visrect.right - src->visrect.left;
2465 int height = src->visrect.bottom - src->visrect.top;
2467 /* blending doesn't use the destination DC colors */
2468 fg.red = fg.green = fg.blue = 0;
2469 bg.red = bg.green = bg.blue = 0xffff;
2470 fg.alpha = bg.alpha = 0xffff;
2473 tmp_pixmap = XCreatePixmap( gdi_display, root_window, width, height,
2474 physdev_dst->pict_format->depth );
2475 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2476 tmp_pict = pXRenderCreatePicture( gdi_display, tmp_pixmap, physdev_dst->pict_format,
2478 wine_tsx11_unlock();
2480 xrender_mono_blit( src_pict, tmp_pict, physdev_dst->format, &fg, &bg,
2481 src->visrect.left, src->visrect.top, 0, 0, 1, 1, width, height );
2483 else if (!(blendfn.AlphaFormat & AC_SRC_ALPHA) && physdev_src->pict_format)
2485 /* we need a source picture with no alpha */
2486 enum wxr_format format = get_format_without_alpha( physdev_src->format );
2487 if (format != physdev_src->format)
2490 pa.subwindow_mode = IncludeInferiors;
2491 pa.repeat = use_repeat ? RepeatNormal : RepeatNone;
2492 tmp_pict = pXRenderCreatePicture( gdi_display, physdev_src->x11dev->drawable,
2493 pict_formats[format], CPSubwindowMode|CPRepeat, &pa );
2494 wine_tsx11_unlock();
2498 if (tmp_pict) src_pict = tmp_pict;
2500 EnterCriticalSection( &xrender_cs );
2501 mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 );
2503 xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict,
2504 physdev_src->x11dev->dc_rect.left + src->x,
2505 physdev_src->x11dev->dc_rect.top + src->y,
2506 physdev_dst->x11dev->dc_rect.left + dst->x,
2507 physdev_dst->x11dev->dc_rect.top + dst->y,
2508 xscale, yscale, dst->width, dst->height );
2511 if (tmp_pict) pXRenderFreePicture( gdi_display, tmp_pict );
2512 if (tmp_pixmap) XFreePixmap( gdi_display, tmp_pixmap );
2513 wine_tsx11_unlock();
2515 LeaveCriticalSection( &xrender_cs );
2516 if (physdev_src != physdev_dst) X11DRV_UnlockDIBSection( physdev_src->x11dev, FALSE );
2517 X11DRV_UnlockDIBSection( physdev_dst->x11dev, TRUE );
2521 /***********************************************************************
2522 * xrenderdrv_SelectBrush
2524 static HBRUSH xrenderdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, HBITMAP bitmap,
2525 const BITMAPINFO *info, void *bits, UINT usage )
2527 struct xrender_physdev *physdev = get_xrender_dev( dev );
2528 X_PHYSBITMAP *physbitmap;
2529 enum wxr_format format;
2530 BOOL delete_bitmap = FALSE;
2533 Picture src_pict, dst_pict;
2534 XRenderPictureAttributes pa;
2536 if (!X11DRV_XRender_Installed) goto x11drv_fallback;
2537 if (!bitmap && !info) goto x11drv_fallback;
2538 if (physdev->format == WXR_FORMAT_MONO) goto x11drv_fallback;
2540 if (!bitmap || !(physbitmap = X11DRV_get_phys_bitmap( bitmap )))
2542 if (!(bitmap = create_brush_bitmap( physdev->x11dev, info, bits, usage ))) return 0;
2543 physbitmap = X11DRV_get_phys_bitmap( bitmap );
2544 delete_bitmap = TRUE;
2547 format = get_xrender_format_from_color_shifts( physbitmap->depth, &physbitmap->color_shifts );
2548 if (format == WXR_FORMAT_MONO || !pict_formats[format]) goto x11drv_fallback;
2550 GetObjectW( bitmap, sizeof(bm), &bm );
2552 X11DRV_DIB_Lock( physbitmap, DIB_Status_GdiMod );
2555 pixmap = XCreatePixmap( gdi_display, root_window, bm.bmWidth, bm.bmHeight,
2556 physdev->pict_format->depth );
2558 pa.repeat = RepeatNone;
2559 src_pict = pXRenderCreatePicture(gdi_display, physbitmap->pixmap, pict_formats[format], CPRepeat, &pa);
2560 dst_pict = pXRenderCreatePicture(gdi_display, pixmap, physdev->pict_format, CPRepeat, &pa);
2562 xrender_blit( PictOpSrc, src_pict, 0, dst_pict, 0, 0, 0, 0, 1.0, 1.0, bm.bmWidth, bm.bmHeight );
2563 pXRenderFreePicture( gdi_display, src_pict );
2564 pXRenderFreePicture( gdi_display, dst_pict );
2566 if (physdev->x11dev->brush.pixmap) XFreePixmap( gdi_display, physdev->x11dev->brush.pixmap );
2567 physdev->x11dev->brush.pixmap = pixmap;
2568 physdev->x11dev->brush.fillStyle = FillTiled;
2569 physdev->x11dev->brush.pixel = 0; /* ignored */
2570 wine_tsx11_unlock();
2572 X11DRV_DIB_Unlock( physbitmap, TRUE );
2573 if (delete_bitmap) DeleteObject( bitmap );
2577 if (delete_bitmap) DeleteObject( bitmap );
2578 dev = GET_NEXT_PHYSDEV( dev, pSelectBrush );
2579 return dev->funcs->pSelectBrush( dev, hbrush, bitmap, info, bits, usage );
2583 static const struct gdi_dc_funcs xrender_funcs =
2585 NULL, /* pAbortDoc */
2586 NULL, /* pAbortPath */
2587 xrenderdrv_AlphaBlend, /* pAlphaBlend */
2588 NULL, /* pAngleArc */
2591 NULL, /* pBeginPath */
2592 xrenderdrv_BlendImage, /* pBlendImage */
2593 NULL, /* pChoosePixelFormat */
2595 NULL, /* pCloseFigure */
2596 xrenderdrv_CopyBitmap, /* pCopyBitmap */
2597 xrenderdrv_CreateBitmap, /* pCreateBitmap */
2598 xrenderdrv_CreateCompatibleDC, /* pCreateCompatibleDC */
2599 xrenderdrv_CreateDC, /* pCreateDC */
2600 NULL, /* pCreateDIBSection */
2601 xrenderdrv_DeleteBitmap, /* pDeleteBitmap */
2602 xrenderdrv_DeleteDC, /* pDeleteDC */
2603 NULL, /* pDeleteObject */
2604 NULL, /* pDescribePixelFormat */
2605 NULL, /* pDeviceCapabilities */
2606 NULL, /* pEllipse */
2608 NULL, /* pEndPage */
2609 NULL, /* pEndPath */
2610 NULL, /* pEnumFonts */
2611 NULL, /* pEnumICMProfiles */
2612 NULL, /* pExcludeClipRect */
2613 NULL, /* pExtDeviceMode */
2614 xrenderdrv_ExtEscape, /* pExtEscape */
2615 NULL, /* pExtFloodFill */
2616 NULL, /* pExtSelectClipRgn */
2617 xrenderdrv_ExtTextOut, /* pExtTextOut */
2618 NULL, /* pFillPath */
2619 NULL, /* pFillRgn */
2620 NULL, /* pFlattenPath */
2621 NULL, /* pFontIsLinked */
2622 NULL, /* pFrameRgn */
2623 NULL, /* pGdiComment */
2624 NULL, /* pGdiRealizationInfo */
2625 NULL, /* pGetCharABCWidths */
2626 NULL, /* pGetCharABCWidthsI */
2627 NULL, /* pGetCharWidth */
2628 NULL, /* pGetDeviceCaps */
2629 NULL, /* pGetDeviceGammaRamp */
2630 NULL, /* pGetFontData */
2631 NULL, /* pGetFontUnicodeRanges */
2632 NULL, /* pGetGlyphIndices */
2633 NULL, /* pGetGlyphOutline */
2634 NULL, /* pGetICMProfile */
2635 xrenderdrv_GetImage, /* pGetImage */
2636 NULL, /* pGetKerningPairs */
2637 NULL, /* pGetNearestColor */
2638 NULL, /* pGetOutlineTextMetrics */
2639 NULL, /* pGetPixel */
2640 NULL, /* pGetPixelFormat */
2641 NULL, /* pGetSystemPaletteEntries */
2642 NULL, /* pGetTextCharsetInfo */
2643 NULL, /* pGetTextExtentExPoint */
2644 NULL, /* pGetTextExtentExPointI */
2645 NULL, /* pGetTextFace */
2646 NULL, /* pGetTextMetrics */
2647 NULL, /* pGradientFill */
2648 NULL, /* pIntersectClipRect */
2649 NULL, /* pInvertRgn */
2651 NULL, /* pModifyWorldTransform */
2653 NULL, /* pOffsetClipRgn */
2654 NULL, /* pOffsetViewportOrg */
2655 NULL, /* pOffsetWindowOrg */
2656 NULL, /* pPaintRgn */
2659 NULL, /* pPolyBezier */
2660 NULL, /* pPolyBezierTo */
2661 NULL, /* pPolyDraw */
2662 NULL, /* pPolyPolygon */
2663 NULL, /* pPolyPolyline */
2664 NULL, /* pPolygon */
2665 NULL, /* pPolyline */
2666 NULL, /* pPolylineTo */
2667 xrenderdrv_PutImage, /* pPutImage */
2668 NULL, /* pRealizeDefaultPalette */
2669 NULL, /* pRealizePalette */
2670 NULL, /* pRectangle */
2671 NULL, /* pResetDC */
2672 NULL, /* pRestoreDC */
2673 NULL, /* pRoundRect */
2675 NULL, /* pScaleViewportExt */
2676 NULL, /* pScaleWindowExt */
2677 xrenderdrv_SelectBitmap, /* pSelectBitmap */
2678 xrenderdrv_SelectBrush, /* pSelectBrush */
2679 NULL, /* pSelectClipPath */
2680 xrenderdrv_SelectFont, /* pSelectFont */
2681 NULL, /* pSelectPalette */
2682 NULL, /* pSelectPen */
2683 NULL, /* pSetArcDirection */
2684 NULL, /* pSetBkColor */
2685 NULL, /* pSetBkMode */
2686 NULL, /* pSetDCBrushColor */
2687 NULL, /* pSetDCPenColor */
2688 NULL, /* pSetDIBColorTable */
2689 NULL, /* pSetDIBitsToDevice */
2690 xrenderdrv_SetDeviceClipping, /* pSetDeviceClipping */
2691 NULL, /* pSetDeviceGammaRamp */
2692 NULL, /* pSetLayout */
2693 NULL, /* pSetMapMode */
2694 NULL, /* pSetMapperFlags */
2695 NULL, /* pSetPixel */
2696 NULL, /* pSetPixelFormat */
2697 NULL, /* pSetPolyFillMode */
2698 NULL, /* pSetROP2 */
2699 NULL, /* pSetRelAbs */
2700 NULL, /* pSetStretchBltMode */
2701 NULL, /* pSetTextAlign */
2702 NULL, /* pSetTextCharacterExtra */
2703 NULL, /* pSetTextColor */
2704 NULL, /* pSetTextJustification */
2705 NULL, /* pSetViewportExt */
2706 NULL, /* pSetViewportOrg */
2707 NULL, /* pSetWindowExt */
2708 NULL, /* pSetWindowOrg */
2709 NULL, /* pSetWorldTransform */
2710 NULL, /* pStartDoc */
2711 NULL, /* pStartPage */
2712 xrenderdrv_StretchBlt, /* pStretchBlt */
2713 NULL, /* pStretchDIBits */
2714 NULL, /* pStrokeAndFillPath */
2715 NULL, /* pStrokePath */
2716 NULL, /* pSwapBuffers */
2717 NULL, /* pUnrealizePalette */
2718 NULL, /* pWidenPath */
2719 /* OpenGL not supported */
2722 #else /* SONAME_LIBXRENDER */
2724 const struct gdi_dc_funcs *X11DRV_XRender_Init(void)
2726 TRACE("XRender support not compiled in.\n");
2730 void X11DRV_XRender_Finalize(void)
2734 BOOL X11DRV_XRender_SetPhysBitmapDepth(X_PHYSBITMAP *physBitmap, int bits_pixel, const DIBSECTION *dib)
2739 #endif /* SONAME_LIBXRENDER */